3ds Max C++ API Reference
Loading...
Searching...
No Matches
linearAlgebra.h File Reference
#include <algorithm>
#include "IPoint2.h"
#include "IPoint3.h"
#include "Point2.h"
#include "Point3.h"

Classes

class  PointTraits< PointType >
 
class  PointTraits< IPoint2 >
 
class  PointTraits< IPoint3 >
 
class  PointTraits< Point2 >
 
class  PointTraits< Point3 >
 

Functions

template<class PointType >
PointType Interpolate (const PointType &P0, const PointType &P1, const float alpha)
 
template<>
IPoint2 Interpolate (const IPoint2 &P0, const IPoint2 &P1, const float alpha)
 
template<>
IPoint3 Interpolate (const IPoint3 &P0, const IPoint3 &P1, const float alpha)
 
template<class PointType >
PointTraits< PointType >::StorageType CrossProduct2D (const PointType &a, const PointType &b)
 
template<class PointType >
float SignedDistanceToLine2D (const PointType &P, const PointType &P0, const PointType &P1)
 
template<class PointType >
float SquaredDistanceToSegment (const PointType &P, const PointType &P0, const PointType &P1)
 
template<class PointType >
float DistanceToSegment (const PointType &P, const PointType &P0, const PointType &P1)
 
template<class PointType >
PointType ClosestPointOnSegmentGivenProjection (const PointType &P0, const PointType &P1, typename PointTraits< PointType >::StorageType projectionAmount, typename PointTraits< PointType >::StorageType edgeLengthSquared)
 
template<class PointType , class PointType2 >
PointType ClosestPointOnSegment2D (const PointType2 &P, const PointType &P0, const PointType &P1)
 
template<class PointType >
PointType ClosestPointOnSegment (const PointType &P, const PointType &P0, const PointType &P1)
 
template<class PointType >
bool SegmentIntersectsCircleOrSphere (const PointType &P0, const PointType &P1, const PointType &centre, typename PointTraits< PointType >::StorageType radius)
 
template<class PointType >
bool PointInsideTriangle2D (const PointType &P, const PointType &V0, const PointType &V1, const PointType &V2)
 

Function Documentation

◆ Interpolate() [1/3]

PointType Interpolate ( const PointType &  P0,
const PointType &  P1,
const float  alpha 
)
inline
Remarks
Interpolates between two points.
72{
73 return P0 * (1.0f - alpha) + P1 * alpha;
74}

◆ Interpolate() [2/3]

IPoint2 Interpolate ( const IPoint2 P0,
const IPoint2 P1,
const float  alpha 
)
inline
Remarks
Interpolates between two points. Specialization to handle rounding of integer type
82{
83 return IPoint2(int(std::floor(P0.x * (1.0 - alpha) + P1.x * alpha + 0.5)),
84 int(std::floor(P0.y * (1.0 - alpha) + P1.y * alpha + 0.5)));
85}
Definition: ipoint2.h:30
int y
Definition: ipoint2.h:33
int x
Definition: ipoint2.h:32

◆ Interpolate() [3/3]

IPoint3 Interpolate ( const IPoint3 P0,
const IPoint3 P1,
const float  alpha 
)
inline
Remarks
Interpolates between two points. Specialization to handle rounding of integer type
93{
94 return IPoint3(int(std::floor(P0.x * (1.0 - alpha) + P1.x * alpha + 0.5)),
95 int(std::floor(P0.y * (1.0 - alpha) + P1.y * alpha + 0.5)),
96 int(std::floor(P0.z * (1.0 - alpha) + P1.z * alpha + 0.5)));
97}
Definition: ipoint3.h:29
int y
Definition: ipoint3.h:32
int z
Definition: ipoint3.h:33
int x
Definition: ipoint3.h:31

◆ CrossProduct2D()

PointTraits< PointType >::StorageType CrossProduct2D ( const PointType &  a,
const PointType &  b 
)
inline
Remarks
Returns the 2D cross product of two vectors
102{
103 return a.x * b.y - a.y * b.x;
104}
float float b
Definition: texutil.h:51
float a
Definition: texutil.h:51

◆ SignedDistanceToLine2D()

float SignedDistanceToLine2D ( const PointType &  P,
const PointType &  P0,
const PointType &  P1 
)
inline
Remarks
Returns the signed distance of a point relative to a line. Positive sign is in the perpendicular direction counterclockwise from the line direction
113{
114 const Point2 v(P1 - P0);
115 const Point2 w( P - P0);
116 const double lengthV = v.Length(); // use double precision even for integer points
117 if (lengthV == 0.0)
118 {
119 return w.Length();
120 }
121 else
122 {
123 const double vCrossW = CrossProduct2D(v, w);
124
125 // No danger of overflow because vCrossW is at most length(v) * length(w), so we
126 // can safely divide by length(v), even if this is near zero.
127 return vCrossW / lengthV;
128 }
129}
Definition: point2.h:38
PointTraits< PointType >::StorageType CrossProduct2D(const PointType &a, const PointType &b)
Definition: linearAlgebra.h:101

◆ SquaredDistanceToSegment()

float SquaredDistanceToSegment ( const PointType &  P,
const PointType &  P0,
const PointType &  P1 
)
inline
Remarks
Returns the squared distance between a point and a line segment
137{
138 const PointType v = P1 - P0;
139 const PointType w = P - P0;
140 const double wDotV = w.DotProd(v); // use double precision even for integer points
141 if (wDotV <= 0.0)
142 {
143 return w.LengthSquared(); // Nearest point is P0
144 }
145
146 const double vDotV = v.DotProd(v);
147 if (wDotV >= vDotV)
148 {
149 return LengthSquared(P - P1); // Nearest point is P1
150 }
151 else
152 {
153 const double wDotW = w.DotProd(w);
154 // No danger of overflow since vDotv > wDotV and wDotV > 0
155 return static_cast< float >(std::max(wDotW - wDotV * wDotV / vDotV, 0.0));
156 }
157}
constexpr double LengthSquared(const DPoint2 &p)
The 'Length' squared of this point.
Definition: dpoint2.h:278

◆ DistanceToSegment()

float DistanceToSegment ( const PointType &  P,
const PointType &  P0,
const PointType &  P1 
)
inline
Remarks
Returns the distance between a point and a line segment
165{
166 return std::sqrt(SquaredDistanceToSegment(P, P0, P1));
167}
float SquaredDistanceToSegment(const PointType &P, const PointType &P0, const PointType &P1)
Definition: linearAlgebra.h:133

◆ ClosestPointOnSegmentGivenProjection()

PointType ClosestPointOnSegmentGivenProjection ( const PointType &  P0,
const PointType &  P1,
typename PointTraits< PointType >::StorageType  projectionAmount,
typename PointTraits< PointType >::StorageType  edgeLengthSquared 
)
inline
Remarks
Helper for finding the closest point to a line segment. Handles all degenerate and near-degenerate cases.
177{
178 if (projectionAmount <= 0)
179 {
180 return P0; // segment is zero length or point is to the left of segment
181 }
182 else if (projectionAmount >= edgeLengthSquared)
183 {
184 return P1; // point is to the right of the segment
185 }
186 else {
187 // The segment is non-zero length, and the closest point is strictly between the two end points.
188 const double alpha = static_cast< double >(projectionAmount) / static_cast< double >(edgeLengthSquared);
189 return Interpolate(P0, P1, alpha);
190 }
191}
PointType Interpolate(const PointType &P0, const PointType &P1, const float alpha)
Definition: linearAlgebra.h:68

◆ ClosestPointOnSegment2D()

PointType ClosestPointOnSegment2D ( const PointType2 &  P,
const PointType &  P0,
const PointType &  P1 
)
inline
Remarks
Uses the 2D portions of the points to determine the closest point on a segment. The type of the P argument can be different from that of the segment arguments. For integer point types, the closest point components will be rounded to the nearest integer, so the return value might not be exactly on the segment.
202{
203 typedef typename PointTraits< PointType >::StorageType StorageType;
204 typedef typename PointTraits< PointType >::PointType2D PointType2D;
205
206 // Get the two vectors defining the geometry, extracting the 2D portions from the possibly 3D input types
207 const PointType2D edgeDir2D (P1.x - P0.x, P1.y - P0.y);
208 const PointType2D dirToTarget2D( P.x - P0.x, P.y - P0.y);
209
210 // Project the vector onto the edge and get the squared length of the edge.
211 const StorageType projectionAmount = edgeDir2D.DotProd(dirToTarget2D);
212 const StorageType edgeLengthSquared = edgeDir2D.DotProd(edgeDir2D);
213
214 return ClosestPointOnSegmentGivenProjection(P0, P1, projectionAmount, edgeLengthSquared);
215}
Definition: linearAlgebra.h:30
PointType ClosestPointOnSegmentGivenProjection(const PointType &P0, const PointType &P1, typename PointTraits< PointType >::StorageType projectionAmount, typename PointTraits< PointType >::StorageType edgeLengthSquared)
Definition: linearAlgebra.h:172

◆ ClosestPointOnSegment()

PointType ClosestPointOnSegment ( const PointType &  P,
const PointType &  P0,
const PointType &  P1 
)
inline
Remarks
Returns the closest point on a segment. Handles 2D or 3D points. For integer point types, the closest point components will be rounded to the nearest integer, so the return value might not be exactly on the segment.
225{
226 typedef typename PointTraits< PointType >::StorageType StorageType;
227
228 // Get the two vectors defining the geometry
229 const PointType edgeDir = P1 - P0;
230 const PointType dirToTarget = P - P0;
231
232 // Project the vector onto the edge and get the squared length of the edge.
233 const StorageType projectionAmount = edgeDir.DotProd(dirToTarget);
234 const StorageType edgeLengthSquared = edgeDir.DotProd(edgeDir);
235
236 // Now interpolate along the edge based on the projection amount relative to the edge length
237 return ClosestPointOnSegmentGivenProjection(P0, P1, projectionAmount, edgeLengthSquared);
238}

◆ SegmentIntersectsCircleOrSphere()

bool SegmentIntersectsCircleOrSphere ( const PointType &  P0,
const PointType &  P1,
const PointType &  centre,
typename PointTraits< PointType >::StorageType  radius 
)
inline
Remarks
Returns true if the segment intersects the circle/sphere. Point type can be integer or float, 2D or 3D.
248{
249 // Find the closest distance from the centre to the segment
250 const float squaredDistanceCentreToSegment = SquaredDistanceToSegment(centre, P0, P1);
251
252 // If this distance is less than or equal to the radius, we have an intersection
253 return squaredDistanceCentreToSegment <= static_cast< float >(radius * radius);
254}

◆ PointInsideTriangle2D()

bool PointInsideTriangle2D ( const PointType &  P,
const PointType &  V0,
const PointType &  V1,
const PointType &  V2 
)
inline
Remarks
Returns true if the point is on or inside the triangle. Point type can be integer or float, 2D or 3D, but only the 2D portions of the points are used to determine inside status. Handles all degenerate and near-degenerate cases. If the PointType is IPoint2 or IPoint3, integer overflow can occur if the values are not well within 16 bit range.
267{
268 typedef typename PointTraits< PointType >::StorageType StorageType;
269 typedef typename PointTraits< PointType >::PointType2D PointType2D;
270
271 // Because the input types might be 3D, extract the 2D portions
272 const PointType2D edge0 (V1.x - V0.x, V1.y - V0.y);
273 const PointType2D edge1 (V2.x - V0.x, V2.y - V0.y);
274 const PointType2D PMinusV0( P.x - V0.x, P.y - V0.y);
275
276 // Get the signed area of the triangle
277 const StorageType signedArea = CrossProduct2D(edge0, edge1);
278
279 // Get the relative distance of the point from each edge
280 const StorageType signedDistanceEdge0 = edge0.x * PMinusV0.y - edge0.y * PMinusV0.x;
281 const StorageType signedDistanceEdge1 = PMinusV0.x * edge1.y - PMinusV0.y * edge1.x;
282 const StorageType signedDistanceEdge2 = signedArea - signedDistanceEdge0 - signedDistanceEdge1;
283
284 if (signedArea > 0)
285 {
286 // Triangle is ccw and non-degenerate. Check on or inside all 3 edges.
287 return signedDistanceEdge0 >= 0 && signedDistanceEdge1 >= 0 && signedDistanceEdge2 >= 0;
288 }
289 else if (signedArea < 0)
290 {
291 // Triangle is cw and non-degenerate. Check on or inside all 3 edges.
292 return signedDistanceEdge0 <= 0 && signedDistanceEdge1 <= 0 && signedDistanceEdge2 <= 0;
293 }
294 else {
295 // Triangle is degenerate
296
297 if (signedDistanceEdge0 != 0 || signedDistanceEdge1 != 0)
298 {
299 // The triangle is colinear and the point is not on the infinite line through the edge segments
300 return false;
301 }
302
303 // Get the length of the 2 edges and the projection of the point onto the 2 edges
304 const StorageType edge0LengthSquared = edge0.LengthSquared();
305 const StorageType edge1LengthSquared = edge1.LengthSquared();
306
307
308 if (edge0LengthSquared != 0)
309 {
310 if (edge1LengthSquared != 0)
311 {
312 // Both edges are non-zero length, so the point could be on either one of them
313 const StorageType PDotEdge0 = PMinusV0.DotProd(edge0);
314 const StorageType PDotEdge1 = PMinusV0.DotProd(edge1);
315 return 0 <= PDotEdge0 && PDotEdge0 <= edge0LengthSquared ||
316 0 <= PDotEdge1 && PDotEdge1 <= edge1LengthSquared;
317 }
318 else
319 {
320 // Edge 1 is zero length, so just check edge 1
321 const StorageType PDotEdge0 = PMinusV0.DotProd(edge0);
322 return 0 <= PDotEdge0 && PDotEdge0 <= edge0LengthSquared;
323 }
324 }
325 else
326 {
327 if (edge1LengthSquared != 0)
328 {
329 // Edge 0 is zero length, so just check edge 2
330 const StorageType PDotEdge1 = PMinusV0.DotProd(edge1);
331 return 0 <= PDotEdge1 && PDotEdge1 <= edge1LengthSquared;
332 }
333 else
334 {
335 // All 3 vertices equal, just check if the point is equal P0
336 return PMinusV0.x == 0 && PMinusV0.y == 0;
337 }
338 }
339 }
340}