Skip to content

Commit 81db844

Browse files
committed
More coverage
1 parent c2c0734 commit 81db844

File tree

8 files changed

+1364
-21
lines changed

8 files changed

+1364
-21
lines changed

modules/yup_graphics/primitives/yup_Line.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,12 @@ class YUP_API Line
277277
*/
278278
constexpr bool contains (const Point<ValueType>& point, float tolerance) const noexcept
279279
{
280-
return std::abs ((point.getY() - p1.getY()) * (p2.getX() - p1.getX()) - (point.getX() - p1.getX()) * (p2.getY() - p1.getY())) < tolerance;
280+
const auto lineLength = p1.distanceTo (p2);
281+
if (lineLength == 0.0f)
282+
return p1.distanceTo (point) <= tolerance;
283+
284+
const auto area = yup_abs ((point.getY() - p1.getY()) * (p2.getX() - p1.getX()) - (point.getX() - p1.getX()) * (p2.getY() - p1.getY()));
285+
return (area / lineLength) <= tolerance;
281286
}
282287

283288
//==============================================================================

modules/yup_graphics/primitives/yup_Point.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ class YUP_API Point
260260
*/
261261
[[nodiscard]] constexpr ValueType horizontalDistanceTo (const Point& other) const noexcept
262262
{
263-
return other.x - x;
263+
return yup_abs (other.x - x);
264264
}
265265

266266
/** Calculates the vertical distance between this point and another point.
@@ -274,7 +274,7 @@ class YUP_API Point
274274
*/
275275
[[nodiscard]] constexpr ValueType verticalDistanceTo (const Point& other) const noexcept
276276
{
277-
return other.y - y;
277+
return yup_abs (other.y - y);
278278
}
279279

280280
/** Calculates the Manhattan distance between this point and another point.
@@ -288,7 +288,7 @@ class YUP_API Point
288288
*/
289289
[[nodiscard]] constexpr ValueType manhattanDistanceTo (const Point& other) const noexcept
290290
{
291-
return std::abs (x - other.x) + std::abs (y - other.y);
291+
return yup_abs (x - other.x) + yup_abs (y - other.y);
292292
}
293293

294294
//==============================================================================
@@ -721,7 +721,7 @@ class YUP_API Point
721721
*/
722722
[[nodiscard]] constexpr bool isWithinCircle (const Point& center, float radius) const noexcept
723723
{
724-
return distanceTo (center) <= radius;
724+
return distanceTo (center) <= jmax (0.0f, radius);
725725
}
726726

727727
/** Checks if this point is within a rectangular area defined by two corner points.

modules/yup_graphics/primitives/yup_Rectangle.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ class YUP_API Rectangle
723723
*/
724724
constexpr Rectangle& setBottomRight (const Point<ValueType>& newPosition) noexcept
725725
{
726-
xy = newPosition.translated (-static_cast<ValueType> (getHeight()), -static_cast<ValueType> (getHeight()));
726+
xy = newPosition.translated (-static_cast<ValueType> (getWidth()), -static_cast<ValueType> (getHeight()));
727727

728728
return *this;
729729
}
@@ -1769,7 +1769,7 @@ class YUP_API Rectangle
17691769
*/
17701770
[[nodiscard]] constexpr Rectangle largestFittingSquare() const noexcept
17711771
{
1772-
if (getWidth() == getHeight())
1772+
if (isEmpty())
17731773
return *this;
17741774

17751775
if (getWidth() > getHeight())
@@ -1791,6 +1791,16 @@ class YUP_API Rectangle
17911791
*/
17921792
[[nodiscard]] constexpr Rectangle unionWith (const Rectangle& other) const noexcept
17931793
{
1794+
const bool thisIsEmpty = isEmpty();
1795+
const bool otherIsEmpty = other.isEmpty();
1796+
1797+
if (thisIsEmpty && otherIsEmpty)
1798+
return {};
1799+
else if (thisIsEmpty)
1800+
return other;
1801+
else if (otherIsEmpty)
1802+
return *this;
1803+
17941804
const auto x1 = jmin (getX(), other.getX());
17951805
const auto x2 = jmax (getX() + getWidth(), other.getX() + other.getWidth());
17961806

modules/yup_graphics/primitives/yup_RectangleList.h

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ class YUP_API RectangleList
183183

184184
[[nodiscard]] bool contains (const Point<ValueType>& point) const
185185
{
186-
for (const auto& rect : rectangles)
186+
for (const auto& r : rectangles)
187187
{
188-
if (rect.contains (point))
188+
if (r.contains (point))
189189
return true;
190190
}
191191

@@ -206,9 +206,9 @@ class YUP_API RectangleList
206206

207207
[[nodiscard]] bool intersects (const RectangleType& rect) const
208208
{
209-
for (const auto& rect : rectangles)
209+
for (const auto& r : rectangles)
210210
{
211-
if (rect.intersects (rect))
211+
if (rect.intersects (r))
212212
return true;
213213
}
214214

@@ -256,21 +256,20 @@ class YUP_API RectangleList
256256
*/
257257
[[nodiscard]] RectangleType getBoundingBox() const
258258
{
259+
if (rectangles.isEmpty())
260+
return {};
261+
259262
ValueType minX = std::numeric_limits<ValueType>::max();
260263
ValueType maxX = std::numeric_limits<ValueType>::min();
261264
ValueType minY = std::numeric_limits<ValueType>::max();
262265
ValueType maxY = std::numeric_limits<ValueType>::min();
263266

264-
for (const auto& rect : rectangles)
267+
for (const auto& r : rectangles)
265268
{
266-
if (minX > rect.getX())
267-
minX = rect.getX();
268-
if (minY > rect.getY())
269-
minY = rect.getY();
270-
if (maxX > rect.getX() + rect.getWidth())
271-
maxX = rect.getX() + rect.getWidth();
272-
if (maxY > rect.getY() + rect.getHeight())
273-
maxY = rect.getY() + rect.getHeight();
269+
minX = jmin (minX, r.getX());
270+
minY = jmin (minY, r.getY());
271+
maxX = jmax (maxX, r.getX() + r.getWidth());
272+
maxY = jmax (maxY, r.getY() + r.getHeight());
274273
}
275274

276275
return { minX, minY, maxX - minX, maxY - minY };

tests/yup_graphics/yup_Line.cpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,20 @@ TEST (LineTests, Contains)
9090
EXPECT_TRUE (l.contains (Point<float> (5.0f, 5.0f)));
9191
EXPECT_FALSE (l.contains (Point<float> (5.0f, 6.0f)));
9292
EXPECT_TRUE (l.contains (Point<float> (5.001f, 5.001f), 0.01f));
93+
94+
// Test the specific case mentioned by the user
95+
EXPECT_TRUE (l.contains (Point<float> (5.0f, 5.1f), 0.2f));
96+
97+
// Test edge cases with corrected distance calculation
98+
Line<float> l2 (0.0f, 0.0f, 10.0f, 0.0f); // Horizontal line
99+
EXPECT_TRUE (l2.contains (Point<float> (5.0f, 0.1f), 0.2f));
100+
EXPECT_FALSE (l2.contains (Point<float> (5.0f, 0.3f), 0.2f));
101+
102+
// Test zero-length line edge case
103+
Line<float> zeroLine (5.0f, 5.0f, 5.0f, 5.0f);
104+
EXPECT_TRUE (zeroLine.contains (Point<float> (5.0f, 5.0f), 0.1f));
105+
EXPECT_TRUE (zeroLine.contains (Point<float> (5.05f, 5.05f), 0.1f));
106+
EXPECT_FALSE (zeroLine.contains (Point<float> (5.2f, 5.2f), 0.1f));
93107
}
94108

95109
TEST (LineTests, PointAlong)
@@ -194,3 +208,152 @@ TEST (LineTests, StreamOutput)
194208
str << l;
195209
EXPECT_EQ (str, "1, 2, 3, 4");
196210
}
211+
212+
// Additional missing tests
213+
TEST (LineTests, ExtendMethods)
214+
{
215+
Line<float> l (5.0f, 0.0f, 15.0f, 0.0f);
216+
217+
// Test extend method (non-const version)
218+
l.extend (5.0f);
219+
EXPECT_EQ (l.getStart(), Point<float> (0.0f, 0.0f));
220+
EXPECT_EQ (l.getEnd(), Point<float> (20.0f, 0.0f));
221+
222+
// Test extendBefore method (non-const version)
223+
l.extendBefore (5.0f);
224+
EXPECT_EQ (l.getStart(), Point<float> (-5.0f, 0.0f));
225+
EXPECT_EQ (l.getEnd(), Point<float> (20.0f, 0.0f));
226+
227+
// Test extendAfter method (non-const version)
228+
l.extendAfter (5.0f);
229+
EXPECT_EQ (l.getStart(), Point<float> (-5.0f, 0.0f));
230+
EXPECT_EQ (l.getEnd(), Point<float> (25.0f, 0.0f));
231+
}
232+
233+
TEST (LineTests, TransformMethods)
234+
{
235+
Line<float> l (1.0f, 2.0f, 3.0f, 4.0f);
236+
237+
// Test transform method
238+
AffineTransform t = AffineTransform::translation (5.0f, 6.0f);
239+
l.transform (t);
240+
EXPECT_EQ (l.getStart(), Point<float> (6.0f, 8.0f));
241+
EXPECT_EQ (l.getEnd(), Point<float> (8.0f, 10.0f));
242+
243+
// Test transformed method
244+
Line<float> l2 (1.0f, 2.0f, 3.0f, 4.0f);
245+
AffineTransform t2 = AffineTransform::scaling (2.0f);
246+
Line<float> transformed = l2.transformed (t2);
247+
EXPECT_EQ (transformed.getStart(), Point<float> (2.0f, 4.0f));
248+
EXPECT_EQ (transformed.getEnd(), Point<float> (6.0f, 8.0f));
249+
250+
// Original line should be unchanged
251+
EXPECT_EQ (l2.getStart(), Point<float> (1.0f, 2.0f));
252+
EXPECT_EQ (l2.getEnd(), Point<float> (3.0f, 4.0f));
253+
}
254+
255+
TEST (LineTests, EdgeCases)
256+
{
257+
// Test with zero-length line
258+
Line<float> zeroLine (5.0f, 5.0f, 5.0f, 5.0f);
259+
EXPECT_FLOAT_EQ (zeroLine.length(), 0.0f);
260+
EXPECT_TRUE (zeroLine.contains (Point<float> (5.0f, 5.0f)));
261+
262+
// Test slope with vertical line
263+
Line<float> verticalLine (1.0f, 1.0f, 1.0f, 5.0f);
264+
EXPECT_FLOAT_EQ (verticalLine.slope(), 0.0f); // Vertical line has slope 0 in this implementation
265+
266+
// Test pointAlong with negative and > 1.0 values
267+
Line<float> l (0.0f, 0.0f, 10.0f, 0.0f);
268+
EXPECT_EQ (l.pointAlong (-0.5f), Point<float> (-5.0f, 0.0f));
269+
EXPECT_EQ (l.pointAlong (2.0f), Point<float> (20.0f, 0.0f));
270+
271+
// Test extend with negative values
272+
Line<float> l2 (10.0f, 10.0f, 20.0f, 10.0f);
273+
l2.extend (-5.0f);
274+
EXPECT_EQ (l2.getStart(), Point<float> (15.0f, 10.0f));
275+
EXPECT_EQ (l2.getEnd(), Point<float> (15.0f, 10.0f));
276+
277+
// Test contains with tolerance on edge cases
278+
Line<float> l3 (0.0f, 0.0f, 10.0f, 10.0f);
279+
EXPECT_TRUE (l3.contains (Point<float> (0.0f, 0.0f)));
280+
EXPECT_TRUE (l3.contains (Point<float> (10.0f, 10.0f)));
281+
EXPECT_FALSE (l3.contains (Point<float> (5.0f, 6.0f)));
282+
EXPECT_TRUE (l3.contains (Point<float> (5.0f, 5.1f), 0.2f)); // Corrected: should be true with sufficient tolerance
283+
}
284+
285+
TEST (LineTests, TypeConversionEdgeCases)
286+
{
287+
// Test with extreme values
288+
Line<float> l (1.9f, 2.1f, 3.9f, 4.1f);
289+
auto rounded = l.roundToInt();
290+
EXPECT_EQ (rounded.getStart(), Point<int> (2, 2));
291+
EXPECT_EQ (rounded.getEnd(), Point<int> (4, 4));
292+
293+
// Test with negative values
294+
Line<float> lNeg (-1.7f, -2.3f, -3.1f, -4.9f);
295+
auto roundedNeg = lNeg.roundToInt();
296+
EXPECT_EQ (roundedNeg.getStart(), Point<int> (-2, -2));
297+
EXPECT_EQ (roundedNeg.getEnd(), Point<int> (-3, -5));
298+
}
299+
300+
TEST (LineTests, RotationEdgeCases)
301+
{
302+
// Test rotation with different angles
303+
Line<float> l (0.0f, 0.0f, 2.0f, 0.0f);
304+
305+
// 180 degree rotation
306+
auto rotated180 = l.rotateAtPoint (Point<float> (1.0f, 0.0f), MathConstants<float>::pi);
307+
EXPECT_NEAR (rotated180.getStartX(), 2.0f, tol);
308+
EXPECT_NEAR (rotated180.getStartY(), 0.0f, tol);
309+
EXPECT_NEAR (rotated180.getEndX(), 0.0f, tol);
310+
EXPECT_NEAR (rotated180.getEndY(), 0.0f, tol);
311+
312+
// 270 degree rotation
313+
auto rotated270 = l.rotateAtPoint (Point<float> (0.0f, 0.0f), -MathConstants<float>::halfPi);
314+
EXPECT_NEAR (rotated270.getStartX(), 0.0f, tol);
315+
EXPECT_NEAR (rotated270.getStartY(), 0.0f, tol);
316+
EXPECT_NEAR (rotated270.getEndX(), 0.0f, tol);
317+
EXPECT_NEAR (rotated270.getEndY(), -2.0f, tol);
318+
}
319+
320+
TEST (LineTests, ExtendWithDifferentDirections)
321+
{
322+
// Test extend with diagonal line
323+
Line<float> diagLine (0.0f, 0.0f, 3.0f, 4.0f); // Length = 5
324+
auto extended = diagLine.extended (5.0f);
325+
EXPECT_FLOAT_EQ (extended.length(), 15.0f);
326+
327+
// Test extend before/after with diagonal line
328+
auto extendedBefore = diagLine.extendedBefore (5.0f);
329+
auto extendedAfter = diagLine.extendedAfter (5.0f);
330+
EXPECT_FLOAT_EQ (extendedBefore.length(), 10.0f);
331+
EXPECT_FLOAT_EQ (extendedAfter.length(), 10.0f);
332+
}
333+
334+
TEST (LineTests, ComplexTransformations)
335+
{
336+
Line<float> l (1.0f, 1.0f, 2.0f, 2.0f);
337+
338+
// Test combination of transformations
339+
AffineTransform complex = AffineTransform::translation (5.0f, 5.0f)
340+
.scaled (2.0f)
341+
.rotated (MathConstants<float>::pi / 4.0f);
342+
343+
Line<float> transformed = l.transformed (complex);
344+
EXPECT_FALSE (transformed.getStart() == l.getStart());
345+
EXPECT_FALSE (transformed.getEnd() == l.getEnd());
346+
}
347+
348+
TEST (LineTests, ApproximatelyEqual)
349+
{
350+
Line<float> l1 (1.0f, 2.0f, 3.0f, 4.0f);
351+
Line<float> l2 (1.0000001f, 2.0000001f, 3.0000001f, 4.0000001f);
352+
Line<float> l3 (1.1f, 2.1f, 3.1f, 4.1f);
353+
354+
// Test floating point precision
355+
EXPECT_TRUE (l1.getStart().approximatelyEqualTo (l2.getStart()));
356+
EXPECT_TRUE (l1.getEnd().approximatelyEqualTo (l2.getEnd()));
357+
EXPECT_FALSE (l1.getStart().approximatelyEqualTo (l3.getStart()));
358+
EXPECT_FALSE (l1.getEnd().approximatelyEqualTo (l3.getEnd()));
359+
}

0 commit comments

Comments
 (0)