-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ellipsoid geometry #1221
Add ellipsoid geometry #1221
Changes from all commits
0399d5f
d020222
288238e
a1c6690
a6109b2
13de0b4
3667fb5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/**************************************************************************** | ||
* Copyright (c) 2025, ArborX authors * | ||
* All rights reserved. * | ||
* * | ||
* This file is part of the ArborX library. ArborX is * | ||
* distributed under a BSD 3-clause license. For the licensing terms see * | ||
* the LICENSE file in the top-level directory. * | ||
* * | ||
* SPDX-License-Identifier: BSD-3-Clause * | ||
****************************************************************************/ | ||
#ifndef ARBORX_ELLIPSOID_HPP | ||
#define ARBORX_ELLIPSOID_HPP | ||
|
||
#include <ArborX_GeometryTraits.hpp> | ||
#include <ArborX_Point.hpp> | ||
|
||
#include <Kokkos_Assert.hpp> | ||
#include <Kokkos_Macros.hpp> | ||
|
||
#include <initializer_list> | ||
#include <type_traits> | ||
|
||
namespace ArborX::Experimental | ||
{ | ||
|
||
template <int DIM, class Coordinate = float> | ||
struct Ellipsoid | ||
{ | ||
KOKKOS_DEFAULTED_FUNCTION | ||
Ellipsoid() = default; | ||
|
||
KOKKOS_FUNCTION | ||
constexpr Ellipsoid(Point<DIM, Coordinate> const ¢roid, | ||
Coordinate const rmt[DIM][DIM]) | ||
: _centroid(centroid) | ||
{ | ||
for (int i = 0; i < DIM; ++i) | ||
for (int j = 0; j < DIM; ++j) | ||
_rmt[i][j] = rmt[i][j]; | ||
} | ||
|
||
KOKKOS_FUNCTION | ||
constexpr Ellipsoid( | ||
Point<DIM, Coordinate> const ¢roid, | ||
std::initializer_list<std::initializer_list<Coordinate>> const rmt) | ||
: _centroid(centroid) | ||
{ | ||
KOKKOS_ASSERT(rmt.size() == DIM); | ||
int i = 0; | ||
for (auto const &row : rmt) | ||
{ | ||
KOKKOS_ASSERT(row.size() == DIM); | ||
int j = 0; | ||
for (auto const &value : row) | ||
_rmt[i][j++] = value; | ||
++i; | ||
} | ||
} | ||
|
||
KOKKOS_FUNCTION | ||
constexpr auto ¢roid() { return _centroid; } | ||
|
||
KOKKOS_FUNCTION | ||
constexpr auto const ¢roid() const { return _centroid; } | ||
|
||
KOKKOS_FUNCTION | ||
constexpr auto const &rmt() const { return _rmt; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's RMT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Riemann metric tensor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment... |
||
|
||
Point<DIM, Coordinate> _centroid = {}; | ||
Coordinate _rmt[DIM][DIM] = {}; | ||
}; | ||
|
||
template <typename T, std::size_t N> | ||
#if KOKKOS_VERSION >= 40400 | ||
KOKKOS_DEDUCTION_GUIDE | ||
#else | ||
KOKKOS_FUNCTION | ||
#endif | ||
Ellipsoid(T const (&)[N], T const (&)[N][N]) -> Ellipsoid<N, T>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we have this deduction guide and a constructor from an initializer lists instead of having a constructor from array of arrays? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was trying to make things work well enough. If you have a better approach that would simplify things, it would be nice. I want to be able to construct ellipsoid as Ellipsoid ellipse{{3, 1}, {1, 3}}; // testing
float rmt[2][2];
// initialize rmt
Ellipsoid ellipse1{Point{0,0}, rmt}; |
||
|
||
} // namespace ArborX::Experimental | ||
|
||
template <int DIM, class Coordinate> | ||
struct ArborX::GeometryTraits::dimension< | ||
ArborX::Experimental::Ellipsoid<DIM, Coordinate>> | ||
{ | ||
static constexpr int value = DIM; | ||
}; | ||
template <int DIM, class Coordinate> | ||
struct ArborX::GeometryTraits::tag< | ||
ArborX::Experimental::Ellipsoid<DIM, Coordinate>> | ||
{ | ||
using type = EllipsoidTag; | ||
}; | ||
template <int DIM, class Coordinate> | ||
struct ArborX::GeometryTraits::coordinate_type< | ||
ArborX::Experimental::Ellipsoid<DIM, Coordinate>> | ||
{ | ||
using type = Coordinate; | ||
}; | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,8 +14,11 @@ | |
#include "ArborX_Distance.hpp" | ||
#include "ArborX_Expand.hpp" | ||
#include <ArborX_GeometryTraits.hpp> | ||
#include <ArborX_Segment.hpp> | ||
#include <misc/ArborX_Vector.hpp> | ||
|
||
#include <Kokkos_Array.hpp> | ||
#include <Kokkos_Clamp.hpp> | ||
#include <Kokkos_MathematicalFunctions.hpp> | ||
|
||
namespace ArborX::Details | ||
|
@@ -512,6 +515,123 @@ struct intersects<BoxTag, SegmentTag, Box, Segment> | |
} | ||
}; | ||
|
||
namespace | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why anonymous space here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I try to use anonymous spaces when I know it's not needed anywhere outside of this file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a header file though |
||
{ | ||
// Computes x^t R y | ||
template <int DIM, typename Coordinate> | ||
KOKKOS_INLINE_FUNCTION auto rmt_multiply(Details::Vector<DIM, Coordinate> x, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any good reason not to spell out that it returns There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No good reason. I find either acceptable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case it is slightly less readable |
||
Coordinate const (&rmt)[DIM][DIM], | ||
Details::Vector<DIM, Coordinate> y) | ||
{ | ||
Coordinate r = 0; | ||
for (int i = 0; i < DIM; ++i) | ||
for (int j = 0; j < DIM; ++j) | ||
r += x[i] * rmt[i][j] * y[j]; | ||
return r; | ||
} | ||
} // namespace | ||
|
||
template <typename Ellipsoid, typename Point> | ||
struct intersects<EllipsoidTag, PointTag, Ellipsoid, Point> | ||
{ | ||
KOKKOS_FUNCTION static constexpr bool apply(Ellipsoid const &ellipsoid, | ||
Point const &point) | ||
{ | ||
auto d = point - ellipsoid.centroid(); | ||
return rmt_multiply(d, ellipsoid.rmt(), d) <= 1; | ||
} | ||
}; | ||
|
||
template <typename Point, typename Ellipsoid> | ||
struct intersects<PointTag, EllipsoidTag, Point, Ellipsoid> | ||
{ | ||
KOKKOS_FUNCTION static constexpr bool apply(Point const &point, | ||
Ellipsoid const &ellipsoid) | ||
{ | ||
return Details::intersects(ellipsoid, point); | ||
} | ||
}; | ||
Comment on lines
+545
to
+553
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't we generate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't. If you know of an easy way to do it, I'm all ears. Boost geometry does it, but I can't quite recall why we couldn't do it that way. |
||
|
||
template <typename Ellipsoid, typename Segment> | ||
struct intersects<EllipsoidTag, SegmentTag, Ellipsoid, Segment> | ||
{ | ||
KOKKOS_FUNCTION static constexpr bool apply(Ellipsoid const &ellipsoid, | ||
Segment const &segment) | ||
{ | ||
// Preliminaries: | ||
// - parametric segment formula: a + t(b-a) | ||
// - ellipsoid formula: (x-c)^T R (x-c) <= 1 | ||
// | ||
// Steps: | ||
// - shift coordinates so that ellipsoid center is at origin | ||
// new segment formula: a-c + t(b-a) | ||
// new ellipsoid formula: x^T R x <= 1 | ||
// - substitute segment parametric equation into ellipsoid formula | ||
// - find the value of t minimizing it | ||
// t = -(R(b-a), a-c) / (R(b-a), b-a) | ||
// - clamp t to [0, 1] | ||
// - Plug the resulting point into ellipsoid equation | ||
auto const &rmt = ellipsoid.rmt(); | ||
|
||
auto ab = segment.b - segment.a; | ||
auto ca = segment.a - ellipsoid.centroid(); | ||
|
||
// At^2 + 2B^t + C | ||
auto A = rmt_multiply(ab, rmt, ab); | ||
auto B = rmt_multiply(ca, rmt, ab); | ||
auto C = rmt_multiply(ca, rmt, ca); | ||
auto t = -B / A; | ||
|
||
using Float = coordinate_type_t<Segment>; | ||
t = Kokkos::clamp(t, (Float)0, (Float)1); | ||
|
||
return A * t * t + 2 * B * t + C <= 1; | ||
} | ||
}; | ||
|
||
template <typename Segment, typename Ellipsoid> | ||
struct intersects<SegmentTag, EllipsoidTag, Segment, Ellipsoid> | ||
{ | ||
KOKKOS_FUNCTION static constexpr bool apply(Segment const &segment, | ||
Ellipsoid const &ellipsoid) | ||
{ | ||
return Details::intersects(ellipsoid, segment); | ||
} | ||
}; | ||
|
||
template <typename Ellipsoid, typename Box> | ||
struct intersects<EllipsoidTag, BoxTag, Ellipsoid, Box> | ||
{ | ||
KOKKOS_FUNCTION static constexpr bool apply(Ellipsoid const &ellipsoid, | ||
Box const &box) | ||
{ | ||
static_assert(GeometryTraits::dimension_v<Box> == 2, | ||
"Ellipsoid-box intersection is only implemented for 2D"); | ||
|
||
auto min_corner = box.minCorner(); | ||
auto max_corner = box.maxCorner(); | ||
using ::ArborX::Experimental::Segment; | ||
// clang-format off | ||
return | ||
Details::intersects(ellipsoid.centroid(), box) || | ||
Details::intersects(ellipsoid, Segment{min_corner, {min_corner[0], max_corner[1]}}) || | ||
Details::intersects(ellipsoid, Segment{min_corner, {max_corner[0], min_corner[1]}}) || | ||
Details::intersects(ellipsoid, Segment{max_corner, {min_corner[0], max_corner[1]}}) || | ||
Details::intersects(ellipsoid, Segment{max_corner, {max_corner[0], min_corner[1]}}); | ||
// clang-format on | ||
} | ||
}; | ||
|
||
template <typename Box, typename Ellipsoid> | ||
struct intersects<BoxTag, EllipsoidTag, Box, Ellipsoid> | ||
{ | ||
KOKKOS_FUNCTION static constexpr bool apply(Box const &box, | ||
Ellipsoid const &ellipsoid) | ||
{ | ||
return Details::intersects(ellipsoid, box); | ||
} | ||
}; | ||
|
||
} // namespace Dispatch | ||
|
||
} // namespace ArborX::Details | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we want this constructor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For unit tests to allow
{{a, b}, {b, c}}
initialization.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could(should?) have used array of arrays