Skip to content

Commit 166aba4

Browse files
authored
Merge pull request #1207 from aprokop/segment_intersection
Add segment-segment intersection (2D only)
2 parents 2bf01bf + 62d0a8d commit 166aba4

6 files changed

+88
-10
lines changed

src/geometry/ArborX_Segment.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ namespace ArborX::Experimental
2222
template <int DIM, typename Coordinate = float>
2323
struct Segment
2424
{
25-
ArborX::Point<DIM, Coordinate> _start;
26-
ArborX::Point<DIM, Coordinate> _end;
25+
ArborX::Point<DIM, Coordinate> a;
26+
ArborX::Point<DIM, Coordinate> b;
2727
};
2828

2929
template <int DIM, typename Coordinate>

src/geometry/algorithms/ArborX_Centroid.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ struct centroid<SegmentTag, Segment>
119119
// WARNING implicit requirement on KDOP first DIM directions
120120
Point<DIM, Coordinate> point;
121121
for (int d = 0; d < DIM; ++d)
122-
point[d] = (segment._start[d] + segment._end[d]) / 2;
122+
point[d] = (segment.a[d] + segment.b[d]) / 2;
123123
return point;
124124
}
125125
};

src/geometry/algorithms/ArborX_Distance.hpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -255,20 +255,20 @@ struct distance<PointTag, SegmentTag, Point, Segment>
255255
constexpr int DIM = GeometryTraits::dimension_v<Point>;
256256
using Coordinate = GeometryTraits::coordinate_type_t<Point>;
257257

258-
if (Details::equals(segment._start, segment._end))
259-
return Details::distance(point, segment._start);
258+
if (Details::equals(segment.a, segment.b))
259+
return Details::distance(point, segment.a);
260260

261-
auto const dir = segment._end - segment._start;
261+
auto const dir = segment.b - segment.a;
262262

263263
// The line of the segment [a,b] is parametrized as a + t * (b - a).
264264
// Find the projection of the point to that line, and clamp it.
265265
auto t =
266-
Kokkos::clamp(dir.dot(point - segment._start) / dir.dot(dir),
266+
Kokkos::clamp(dir.dot(point - segment.a) / dir.dot(dir),
267267
static_cast<Coordinate>(0), static_cast<Coordinate>(1));
268268

269269
Point projection;
270270
for (int d = 0; d < DIM; ++d)
271-
projection[d] = segment._start[d] + t * dir[d];
271+
projection[d] = segment.a[d] + t * dir[d];
272272

273273
return Details::distance(point, projection);
274274
}

src/geometry/algorithms/ArborX_Expand.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,8 @@ struct expand<BoxTag, SegmentTag, Box, Segment>
230230
{
231231
KOKKOS_FUNCTION static void apply(Box &box, Segment const &segment)
232232
{
233-
Details::expand(box, segment._start);
234-
Details::expand(box, segment._end);
233+
Details::expand(box, segment.a);
234+
Details::expand(box, segment.b);
235235
}
236236
};
237237

src/geometry/algorithms/ArborX_Intersects.hpp

+64
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,70 @@ struct intersects<PointTag, TetrahedronTag, Point, Tetrahedron>
412412
}
413413
};
414414

415+
template <typename Segment>
416+
struct intersects<SegmentTag, SegmentTag, Segment, Segment>
417+
{
418+
// The algorithm is described in
419+
// https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
420+
421+
// Given a segment and a collinear point, check if the point lies on the
422+
// segment
423+
template <typename Point>
424+
KOKKOS_FUNCTION static bool on_segment(Segment const &segment, Point const &p)
425+
{
426+
using Kokkos::max;
427+
using Kokkos::min;
428+
auto const &a = segment.a;
429+
auto const &b = segment.b;
430+
return (p[0] >= min(a[0], b[0]) && p[0] <= max(a[0], b[0])) &&
431+
(p[1] >= min(a[1], b[1]) && p[1] <= max(a[1], b[1]));
432+
}
433+
434+
// Find orientation of an ordered tuple (a, b, c)
435+
// - 0: points are collinear
436+
// - 1: clockwise
437+
// - -1: counter-clockwise
438+
template <typename Point>
439+
KOKKOS_FUNCTION static int orientation(Point const &a, Point const &b,
440+
Point const &c)
441+
{
442+
auto x = (b[1] - a[1]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[1] - b[1]);
443+
return (0 < x) - (x < 0); // sgn
444+
}
445+
446+
KOKKOS_FUNCTION static constexpr bool apply(Segment const &segment1,
447+
Segment const &segment2)
448+
{
449+
static_assert(GeometryTraits::dimension_v<Segment> == 2);
450+
451+
int o1 = orientation(segment1.a, segment1.b, segment2.a);
452+
int o2 = orientation(segment1.a, segment1.b, segment2.b);
453+
int o3 = orientation(segment2.a, segment2.b, segment1.a);
454+
int o4 = orientation(segment2.a, segment2.b, segment1.b);
455+
456+
// General case (no collinearity)
457+
if (o1 != o2 && o3 != o4)
458+
return true;
459+
460+
// Special cases
461+
462+
// segment2.a is collinear to segment1 and is within
463+
if (o1 == 0 && on_segment(segment1, segment2.a))
464+
return true;
465+
// segment2.b is collinear to segment1 and is within
466+
if (o2 == 0 && on_segment(segment1, segment2.b))
467+
return true;
468+
// segment1.a is collinear to segment2 and is within
469+
if (o3 == 0 && on_segment(segment2, segment1.a))
470+
return true;
471+
// segment1.b is collinear to segment2 and is within
472+
if (o4 == 0 && on_segment(segment2, segment1.b))
473+
return true;
474+
475+
return false;
476+
}
477+
};
478+
415479
} // namespace Dispatch
416480

417481
} // namespace ArborX::Details

test/tstDetailsAlgorithms.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,20 @@ BOOST_AUTO_TEST_CASE(intersects)
313313
BOOST_TEST(!intersects(Point{0, 0, 1.1}, tet));
314314
BOOST_TEST(!intersects(Point{0.5, 0.5, 0.5}, tet));
315315
BOOST_TEST(!intersects(Point{-0.5, 0.5, 0.5}, tet));
316+
317+
// segment
318+
using Segment2 = ArborX::Experimental::Segment<2>;
319+
constexpr Segment2 seg{{1, 1}, {2, 2}};
320+
BOOST_TEST(intersects(Segment2{{2, 2}, {3, 3}}, seg));
321+
BOOST_TEST(intersects(Segment2{{1.5, 1.5}, {1.7, 1.7}}, seg));
322+
BOOST_TEST(intersects(Segment2{{0, 0}, {1, 1}}, seg));
323+
BOOST_TEST(intersects(Segment2{{1, 2}, {2, 1}}, seg));
324+
BOOST_TEST(intersects(Segment2{{2, 0}, {0, 2}}, seg));
325+
BOOST_TEST(intersects(Segment2{{1, 3}, {3, 1}}, seg));
326+
BOOST_TEST(!intersects(Segment2{{0, 0}, {0.9, 0.9}}, seg));
327+
BOOST_TEST(!intersects(Segment2{{1.1, 1}, {2, 1}}, seg));
328+
BOOST_TEST(!intersects(Segment2{{1, 0}, {2, 1}}, seg));
329+
BOOST_TEST(!intersects(Segment2{{1, 3}, {3, 1.1}}, seg));
316330
}
317331

318332
BOOST_AUTO_TEST_CASE(equals)

0 commit comments

Comments
 (0)