Skip to content

Commit 274378c

Browse files
arjo129chapulinascpeters
authored
Volume below a plane for spheres and boxes (#219)
Signed-off-by: Arjo Chakravarty <[email protected]> Signed-off-by: Louise Poubel <[email protected]> Co-authored-by: Louise Poubel <[email protected]> Co-authored-by: Steve Peters <[email protected]>
1 parent 4af8a25 commit 274378c

13 files changed

+1126
-2
lines changed

include/ignition/math/Box.hh

+40-1
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,24 @@
2020
#include <ignition/math/config.hh>
2121
#include <ignition/math/MassMatrix3.hh>
2222
#include <ignition/math/Material.hh>
23+
#include <ignition/math/Plane.hh>
2324
#include <ignition/math/Vector3.hh>
2425

26+
#include "ignition/math/detail/WellOrderedVector.hh"
27+
28+
#include <set>
29+
2530
namespace ignition
2631
{
2732
namespace math
2833
{
2934
// Inline bracket to help doxygen filtering.
3035
inline namespace IGNITION_MATH_VERSION_NAMESPACE {
31-
//
36+
/// \brief This is the type used for deduplicating and returning the set of
37+
/// intersections.
38+
template<typename T>
39+
using IntersectionPoints = std::set<Vector3<T>, WellOrderedVectors<T>>;
40+
3241
/// \class Box Box.hh ignition/math/Box.hh
3342
/// \brief A representation of a box. All units are in meters.
3443
///
@@ -128,6 +137,28 @@ namespace ignition
128137
/// \return Volume of the box in m^3.
129138
public: Precision Volume() const;
130139

140+
/// \brief Get the volume of the box below a plane.
141+
/// \param[in] _plane The plane which cuts the box, expressed in the box's
142+
/// frame.
143+
/// \return Volume below the plane in m^3.
144+
public: Precision VolumeBelow(const Plane<Precision> &_plane) const;
145+
146+
/// \brief Center of volume below the plane. This is useful when
147+
/// calculating where buoyancy should be applied, for example.
148+
/// \param[in] _plane The plane which cuts the box, expressed in the box's
149+
/// frame.
150+
/// \return Center of volume, in box's frame.
151+
public: std::optional<Vector3<Precision>>
152+
CenterOfVolumeBelow(const Plane<Precision> &_plane) const;
153+
154+
/// \brief All the vertices which are on or below the plane.
155+
/// \param[in] _plane The plane which cuts the box, expressed in the box's
156+
/// frame.
157+
/// \return Box vertices which are below the plane, expressed in the box's
158+
/// frame.
159+
public: IntersectionPoints<Precision>
160+
VerticesBelow(const Plane<Precision> &_plane) const;
161+
131162
/// \brief Compute the box's density given a mass value. The
132163
/// box is assumed to be solid with uniform density. This
133164
/// function requires the box's size to be set to
@@ -161,6 +192,14 @@ namespace ignition
161192
/// could be due to an invalid size (<=0) or density (<=0).
162193
public: bool MassMatrix(MassMatrix3<Precision> &_massMat) const;
163194

195+
/// \brief Get intersection between a plane and the box's edges.
196+
/// Edges contained on the plane are ignored.
197+
/// \param[in] _plane The plane against which we are testing intersection.
198+
/// \returns A list of points along the edges of the box where the
199+
/// intersection occurs.
200+
public: IntersectionPoints<Precision> Intersections(
201+
const Plane<Precision> &_plane) const;
202+
164203
/// \brief Size of the box.
165204
private: Vector3<Precision> size = Vector3<Precision>::Zero;
166205

include/ignition/math/Line3.hh

+30
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,36 @@ namespace ignition
229229
return true;
230230
}
231231

232+
/// \brief Calculate shortest distance between line and point
233+
/// \param[in] _pt Point which we are measuring distance to.
234+
/// \returns Distance from point to line.
235+
public: T Distance(const Vector3<T> &_pt)
236+
{
237+
auto line = this->pts[1] - this->pts[0];
238+
auto ptTo0 = _pt - this->pts[0];
239+
auto ptTo1 = _pt - this->pts[1];
240+
241+
// Point is projected beyond pt0 or the line has length 0
242+
if (ptTo0.Dot(line) <= 0.0)
243+
{
244+
return ptTo0.Length();
245+
}
246+
247+
// Point is projected beyond pt1
248+
if (ptTo1.Dot(line) >= 0.0)
249+
{
250+
return ptTo1.Length();
251+
}
252+
253+
// Distance to point projected onto line
254+
// line.Length() will have to be > 0 at this point otherwise it would
255+
// return at line 244.
256+
auto d = ptTo0.Cross(line);
257+
auto lineLength = line.Length();
258+
assert(lineLength > 0);
259+
return d.Length() / lineLength;
260+
}
261+
232262
/// \brief Check if this line intersects the given line segment.
233263
/// \param[in] _line The line to check for intersection.
234264
/// \param[in] _epsilon The error bounds within which the intersection

include/ignition/math/Plane.hh

+49
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#include <ignition/math/Vector2.hh>
2222
#include <ignition/math/Vector3.hh>
2323
#include <ignition/math/config.hh>
24+
#include <ignition/math/Line2.hh>
25+
#include <ignition/math/Quaternion.hh>
26+
#include <optional>
2427

2528
namespace ignition
2629
{
@@ -119,6 +122,52 @@ namespace ignition
119122
return this->normal.Dot(_point) - this->d;
120123
}
121124

125+
/// \brief Get the intersection of an infinite line with the plane,
126+
/// given the line's gradient and a point in parametrized space.
127+
/// \param[in] _point A point that lies on the line.
128+
/// \param[in] _gradient The gradient of the line.
129+
/// \param[in] _tolerance The tolerance for determining a line is
130+
/// parallel to the plane. Optional, default=10^-16
131+
/// \return The point of intersection. std::nullopt if the line is
132+
/// parallel to the plane (including lines on the plane).
133+
public: std::optional<Vector3<T>> Intersection(
134+
const Vector3<T> &_point,
135+
const Vector3<T> &_gradient,
136+
const double &_tolerance = 1e-6) const
137+
{
138+
if (std::abs(this->Normal().Dot(_gradient)) < _tolerance)
139+
{
140+
return std::nullopt;
141+
}
142+
auto constant = this->Offset() - this->Normal().Dot(_point);
143+
auto param = constant / this->Normal().Dot(_gradient);
144+
auto intersection = _point + _gradient*param;
145+
146+
if (this->Size() == Vector2<T>(0, 0))
147+
return intersection;
148+
149+
// Check if the point is within the size bounds
150+
// To do this we create a Quaternion using Angle, Axis constructor and
151+
// rotate the Y and X axis the same amount as the normal.
152+
auto dotProduct = Vector3<T>::UnitZ.Dot(this->Normal());
153+
auto angle = acos(dotProduct / this->Normal().Length());
154+
auto axis = Vector3<T>::UnitZ.Cross(this->Normal().Normalized());
155+
Quaternion<T> rotation(axis, angle);
156+
157+
Vector3<T> rotatedXAxis = rotation * Vector3<T>::UnitX;
158+
Vector3<T> rotatedYAxis = rotation * Vector3<T>::UnitY;
159+
160+
auto xBasis = rotatedXAxis.Dot(intersection);
161+
auto yBasis = rotatedYAxis.Dot(intersection);
162+
163+
if (std::abs(xBasis) < this->Size().X() / 2 &&
164+
std::abs(yBasis) < this->Size().Y() / 2)
165+
{
166+
return intersection;
167+
}
168+
return std::nullopt;
169+
}
170+
122171
/// \brief The side of the plane a point is on.
123172
/// \param[in] _point The 3D point to check.
124173
/// \return Plane::NEGATIVE_SIDE if the distance from the point to the

include/ignition/math/Sphere.hh

+18
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "ignition/math/MassMatrix3.hh"
2121
#include "ignition/math/Material.hh"
2222
#include "ignition/math/Quaternion.hh"
23+
#include "ignition/math/Plane.hh"
2324

2425
namespace ignition
2526
{
@@ -91,6 +92,23 @@ namespace ignition
9192
/// \return Volume of the sphere in m^3.
9293
public: Precision Volume() const;
9394

95+
/// \brief Get the volume of sphere below a given plane in m^3.
96+
/// It is assumed that the center of the sphere is on the origin
97+
/// \param[in] _plane The plane which slices this sphere, expressed
98+
/// in the sphere's reference frame.
99+
/// \return Volume below the sphere in m^3.
100+
public: Precision VolumeBelow(const Plane<Precision> &_plane) const;
101+
102+
/// \brief Center of volume below the plane. This is useful for example
103+
/// when calculating where buoyancy should be applied.
104+
/// \param[in] _plane The plane which slices this sphere, expressed
105+
/// in the sphere's reference frame.
106+
/// \return The center of volume if there is anything under the plane,
107+
/// otherwise return a std::nullopt. Expressed in the sphere's reference
108+
/// frame.
109+
public: std::optional<Vector3<Precision>>
110+
CenterOfVolumeBelow(const Plane<Precision> &_plane) const;
111+
94112
/// \brief Compute the sphere's density given a mass value. The
95113
/// sphere is assumed to be solid with uniform density. This
96114
/// function requires the sphere's radius to be set to a

include/ignition/math/Vector3.hh

+1-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ namespace ignition
264264
return n.Normalize();
265265
}
266266

267-
/// \brief Get distance to a line
267+
/// \brief Get distance to an infinite line defined by 2 points.
268268
/// \param[in] _pt1 first point on the line
269269
/// \param[in] _pt2 second point on the line
270270
/// \return the minimum distance from this point to the line

0 commit comments

Comments
 (0)