1 /* Copyright Jukka Jyl�nki
2
3    Licensed under the Apache License, Version 2.0 (the "License");
4    you may not use this file except in compliance with the License.
5    You may obtain a copy of the License at
6
7        http://www.apache.org/licenses/LICENSE-2.0
8
9    Unless required by applicable law or agreed to in writing, software
10    distributed under the License is distributed on an "AS IS" BASIS,
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12    See the License for the specific language governing permissions and
13    limitations under the License. */
14
15 /** @file Capsule.h
16         @author Jukka Jyl�nki
17         @brief The Capsule geometry object. */
18 #pragma once
19
20 #include "../MathGeoLibFwd.h"
21 #include "LineSegment.h"
22
23 MATH_BEGIN_NAMESPACE
24
25 /// A 3D cylinder with spherical ends.
26 class Capsule
27 {
28 public:
29         /// Specifies the two inner points of this capsule.
30         LineSegment l;
31
32         /// Specifies the radius of this capsule. [similarOverload: l]
33         float r;
34
35         /// The default constructor does not initialize any members of this class.
36         /** This means that the values of the members l and r are both undefined after creating a new capsule using
37                 this default constructor. Remember to assign to them before use.
38                 @see l, r. */
39         Capsule() {}
40
41         /// Constructs a new capsule by explicitly specifying the member variables.
42         /** @param endPoints Specifies the line segment of the capsule.
43                 @param radius Specifies the size of this capsule.
44                 @see l, r. */
45         Capsule(const LineSegment &endPoints, float radius);
46
47         /// Constructs a new capsule by explicitly specifying the member variables.
48         /** This constructor is equivalent to calling Capsule(LineSegment(bottomPoint, topPoint), radius), but provided
49                 here for conveniency.
50                 @see l, r. */
51         Capsule(const vec &bottomPoint, const vec &topPoint, float radius);
52
53         /// Constructs a new capsule from a sphere.
54         /** This conversion results in a capsule which has its both endpoints at the exact same coordinates, and hence the
55                 length of the inner line segment is set to 0. */
56         void SetFrom(const Sphere &s);
57
58         /// Sets this Capsule to a degenerate negative-volume state.
59         void SetDegenerate();
60
61         /// Tests if this Capsule is degenerate.
62         /** @return True if this Capsule does not span a strictly positive volume. */
63         bool IsDegenerate() const;
64
65         /// Computes the distance of the two inner points of this capsule.
66         /** <img src="CapsuleFunctions.png" />
67                 @see Height(). */
68         float LineLength() const;
69
70         /// Computes the total height of this capsule, i.e. LineLength() + Diameter().
71         /** <img src="CapsuleFunctions.png" />
72                 @see LineLength(). */
73         float Height() const;
74
75         /// Computes the diameter of this capsule.
76         /** <img src="CapsuleFunctions.png" />
77                 @return 2*r.
78                 @see r. */
79         float Diameter() const;
80
81         /// Returns the bottom-most point of this Capsule.
82         /** <img src="CapsuleFunctions.png" />
83                 @note The bottom-most point is only a naming convention, and does not correspond to the bottom-most point along any world axis. The returned
84                         point is simply the point at the far end of this Capsule where the point l.a resides.
85                 @note The bottom-most point of the capsule is different than the point l.a. The returned point is the point at the very far
86                         edge of this capsule, and does not lie on the internal line. See the attached diagram.
87                 @see Top(), l. */
88         vec Bottom() const;
89
90         /// Returns the center point of this Capsule.
91         /** <img src="CapsuleFunctions.png" />
92                 @return The point (l.a + l.b) / 2. This point is the center of mass for this capsule.
93                 @see l, Bottom(), Top(). */
94         vec Center() const;
95         vec Centroid() const return l.CenterPoint(); } ///< [similarOverload: Center]
96
97         /// Quickly returns an arbitrary point inside this Capsule. Used in GJK intersection test.
98         inline vec AnyPointFast() const return l.a; }
99
100         /// Computes the extreme point of this Capsule in the given direction.
101         /** An extreme point is a farthest point of this Capsule in the given direction. Given a direction,
102                 this point is not necessarily unique.
103                 @param direction The direction vector of the direction to find the extreme point. This vector may
104                         be unnormalized, but may not be null.
105                 @return The extreme point of this Capsule in the given direction. */
106         vec ExtremePoint(const vec &direction) const;
107         vec ExtremePoint(const vec &direction, float &projectionDistance) const;
108
109         /// Projects this Capsule onto the given 1D axis direction vector.
110         /** This function collapses this Capsule onto an 1D axis for the purposes of e.g. separate axis test computations.
111                 The function returns a 1D range [outMin, outMax] denoting the interval of the projection.
112                 @param direction The 1D axis to project to. This vector may be unnormalized, in which case the output
113                         of this function gets scaled by the length of this vector.
114                 @param outMin [out] Returns the minimum extent of this object along the projection axis.
115                 @param outMax [out] Returns the maximum extent of this object along the projection axis. */
116         void ProjectToAxis(const vec &direction, float &outMin, float &outMax) const;
117
118         /// Returns the topmost point of this Capsule.
119         /** <img src="CapsuleFunctions.png" />
120                 @note The topmost point is only a naming convention, and does not correspond to the topmost point along any world axis. The returned
121                         point is simply the point at the far end of this Capsule where the point l.b resides.
122                 @note The topmost point of the capsule is different than the point l.b. The returned point is the point at the very far
123                         edge of this capsule, and does not lie on the internal line. See the attached diagram.
124                 @see Bottom(), l. */
125         vec Top() const;
126
127         /// Returns the direction from the bottommost point towards the topmost point of this Capsule.
128         /** <img src="CapsuleFunctions.png" />
129                 @return The normalized direction vector from l.a to l.b.
130                 @see l. */
131         vec UpDirection() const;
132
133         /// Computes the volume of this Capsule.
134         /** @return pi * r^2 * |b-a| + 4 * pi * r^2 / 3.
135                 @see SurfaceArea(). */
136         float Volume() const;
137
138         /// Computes the surface area of this Capsule.
139         /** @return 2 * pi * r * |b-a| + 4 * pi * r^2.
140                 @see Volume(). */
141         float SurfaceArea() const;
142
143         /// Returns the cross-section circle at the given height of this Capsule.
144         /** <img src="CapsuleFunctions.png" />
145                 @param l A normalized parameter between [0,1]. l == 0 returns a degenerate circle of radius 0 at the bottom of this Capsule, and l == 1
146                                 will return a degenerate circle of radius 0 at the top of this Capsule. */
147         Circle CrossSection(float lconst;
148
149         /// Returns a line segment that spans the far axis of this capsule from bottom to tip.
150         /** <img src="CapsuleFunctions.png" />
151                 @see Height(), LineLength(), l. */
152         LineSegment HeightLineSegment() const;
153
154         /// Tests if this Capsule is finite.
155         /** A Capsule is <b><i>finite</i></b> if none of its member variables contain floating-point NaNs or +/-infs
156                 in them.
157                 @return True if each member variable has a finite floating-point value.
158                 @see l, r.
159                 @todo Implement IsDegenerate(). */
160         bool IsFinite() const;
161
162         /// Generates a point inside this capsule.
163         /** @param l A normalized value between [0,1]. This specifies the point position along the height line of this capsule.
164                 @param a A normalized value between [0,1]. This specifies the normalized directed angle of the point position around the capsule line segment.
165                 @param d A normalized value between [0,1]. This specifies the normalized distance of the point position from the capsule line segment.
166                 @note This function does not generate points inside this capsule uniformly, as (l,a,d) ranges uniformly over [0,1]^3.
167                 @see UniformPointPerhapsInside(), RandomPointInside(). */
168         vec PointInside(float lfloat a, float dconst;
169
170         /// Generates a point that perhaps lies inside this capsule.
171         /** @param l A normalized value between [0,1]. This specifies the point position along the height line of this capsule.
172                 @param x A normalized value between [0,1]. This specifies the x coordinate on the plane of the circle cross-section specified by l.
173                 @param y A normalized value between [0,1]. This specifies the y coordinate on the plane of the circle cross-section specified by l.
174                 @note This function will generate points uniformly, but they do not necessarily lie inside the capsule.
175                 @see PointInside(). */
176         vec UniformPointPerhapsInside(float lfloat x, float y) const;
177
178         /// Returns the Sphere defining the 'bottom' section of this Capsule (corresponding to the endpoint l.a)
179         Sphere SphereA() const;
180
181         /// Returns the Sphere defining the 'top' section of this Capsule (corresponding to the endpoint l.b)
182         Sphere SphereB() const;
183
184         /// Returns the smallest AABB that encloses this capsule.
185         /** @see MinimalEnclosingOBB(). */
186         AABB MinimalEnclosingAABB() const;
187
188         /// Returns the smallest OBB that encloses this capsule.
189         /** @see MinimalEnclosingAABB(). */
190         OBB MinimalEnclosingOBB() const;
191
192         /// Generates a random point inside this capsule.
193         /** The points are distributed uniformly.
194                 @see RandomPointOnSurface(). */
195         vec RandomPointInside(LCG &rng) const;
196
197         /// Generates a random point on the surface of this Capsule.
198         /** @todo The points are NOT distributed uniformly. Convert this to using the rejection method and RandomPointInside()
199                         to produce a uniform distribution.
200                 @see RandomPointInside(). */
201         vec RandomPointOnSurface(LCG &rng) const;
202
203         /// Moves this capsule by the given offset vector.
204         /** @note This function operates in-place.
205                 @param offset The world space offset to apply to the position of this capsule.
206                 @see Transform(), Scale(). */
207         void Translate(const vec &offset);
208
209         /// Applies a uniform scale to this Capsule.
210         /** This function scales this capsule structure in-place, using the given center point as the origin
211                 for the scaling operation.
212                 @param centerPoint Specifies the center of the scaling operation, in world space.
213                 @param scaleFactor The uniform scale factor to apply to each world space axis.
214                 @see Translate(), Transform(). */
215         void Scale(const vec &centerPoint, float scaleFactor);
216
217         /// Applies a transformation to this capsule.
218         /** @param transform The transformation to apply to this capsule. This transformation must be
219                 affine, and must contain an orthogonal set of column vectors (may not contain shear or projection).
220                 The transformation can only contain uniform scale, and may not contain mirroring.
221                 @see Translate(), Scale(), classes float3x3, float3x4, float4x4, Quat. */
222         void Transform(const float3x3 &transform);
223         void Transform(const float3x4 &transform);
224         void Transform(const float4x4 &transform);
225         void Transform(const Quat &transform);
226
227         /// Computes the closest point inside this capsule to the given point.
228         /** If the target point lies inside this capsule, then that point is returned.
229                 @see Distance(), Contains(), Intersects().
230                 @todo Add ClosestPoint(Line/Ray/LineSegment/Plane/Triangle/Polygon/Circle/Disc/AABB/OBB/Sphere/Capsule/Frustum/Polyhedron). */
231         vec ClosestPoint(const vec &targetPoint) const;
232
233         /// Computes the distance between this capsule and the given object.
234         /** This function finds the nearest pair of points on this and the given object, and computes their distance.
235                 If the two objects intersect, or one object is contained inside the other, the returned distance is zero.
236                 @todo Add Distance(Triangle/Polygon/Circle/Disc/Capsule).
237                 @see Contains(), Intersects(), ClosestPoint(). */
238         float Distance(const vec &point) const;
239         float Distance(const Plane &plane) const;
240         float Distance(const Sphere &sphere) const;
241         float Distance(const Ray &ray) const;
242         float Distance(const Line &line) const;
243         float Distance(const LineSegment &lineSegment) const;
244         float Distance(const Capsule &capsule) const;
245
246         /// Tests if the given object is fully contained inside this capsule.
247         /** This function returns true if the given object lies inside this capsule, and false otherwise.
248                 @note The comparison is performed using less-or-equal, so the surface of this capsule count as being inside, but
249                         due to float inaccuracies, this cannot generally be relied upon.
250                 @todo Add Contains(Circle/Disc/Sphere/Capsule).
251                 @see Distance(), Intersects(), ClosestPoint(). */
252         bool Contains(const vec &point) const;
253         bool Contains(const LineSegment &lineSegment) const;
254         bool Contains(const Triangle &triangle) const;
255         bool Contains(const Polygon &polygon) const;
256         bool Contains(const AABB &aabb) const;
257         bool Contains(const OBB &obb) const;
258         bool Contains(const Frustum &frustum) const;
259         bool Contains(const Polyhedron &polyhedron) const;
260
261         /// Tests whether this capsule and the given object intersect.  
262         /** Both objects are treated as "solid", meaning that if one of the objects is fully contained inside
263                 another, this function still returns true. (e.g. in case a line segment is contained inside this capsule,
264                 or this capsule is contained inside a Sphere, etc.)
265                 The first parameter of this function specifies the other object to test against.
266                 @see Contains(), Distance(), ClosestPoint().
267                 @todo Add Intersects(Circle/Disc). */
268         bool Intersects(const Ray &ray) const;
269         bool Intersects(const Line &line) const;
270         bool Intersects(const LineSegment &lineSegment) const;
271         bool Intersects(const Plane &plane) const;
272         bool Intersects(const Sphere &sphere) const;
273         bool Intersects(const Capsule &capsule) const;
274         bool Intersects(const AABB &aabb) const;
275         bool Intersects(const OBB &obb) const;
276         bool Intersects(const Triangle &triangle) const;
277         bool Intersects(const Polygon &polygon) const;
278         bool Intersects(const Frustum &frustum) const;
279         bool Intersects(const Polyhedron &polyhedron) const;
280
281 #ifdef MATH_ENABLE_STL_SUPPORT
282         /// Returns a human-readable representation of this Capsule. Most useful for debugging purposes.
283         /** The returned string specifies the line segment and the radius of this Capsule. */
284         std::string ToString() const;
285         std::string SerializeToString() const;
286
287         /// Returns a string of C++ code that can be used to construct this object. Useful for generating test cases from badly behaving objects.
288         std::string SerializeToCodeString() const;
289 #endif
290
291         static Capsule FromString(const char *str, const char **outEndStr = 0);
292 #ifdef MATH_ENABLE_STL_SUPPORT
293         static Capsule FromString(const std::string &str) { return FromString(str.c_str()); }
294 #endif
295
296 #ifdef MATH_QT_INTEROP
297         operator QString() const return toString(); }
298         QString toString() const return QString::fromStdString(ToString()); }
299 #endif
300
301         bool Equals(const Capsule &rhs, float epsilon = 1e-3f) const return l.Equals(rhs.lepsilon) && EqualAbs(r, rhs.repsilon); }
302
303         /// Compares whether this Capsule and the given Capsule are identical bit-by-bit in the underlying representation.
304         /** @note Prefer using this over e.g. memcmp, since there can be SSE-related padding in the structures. */
305         bool BitEquals(const Capsule &other) const;
306 };
307
308 Capsule operator *(const float3x3 &transform, const Capsule &capsule);
309 Capsule operator *(const float3x4 &transform, const Capsule &capsule);
310 Capsule operator *(const float4x4 &transform, const Capsule &capsule);
311 Capsule operator *(const Quat &transform, const Capsule &capsule);
312
313 #ifdef MATH_QT_INTEROP
314 Q_DECLARE_METATYPE(Capsule)
315 Q_DECLARE_METATYPE(Capsule*)
316 #endif
317
318 #ifdef MATH_ENABLE_STL_SUPPORT
319 std::ostream &operator <<(std::ostream &o, const Capsule &capsule);
320 #endif
321
322 MATH_END_NAMESPACE

Go back to previous page