Implementing LineSegment2D class
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
|
||||
namespace J3ML::Geometry
|
||||
{
|
||||
/// A line segment in 2D space is a finite line with a start and end point.
|
||||
class LineSegment2D
|
||||
{
|
||||
class LineSegment2D {
|
||||
public:
|
||||
/// The starting point of this line segment.
|
||||
Vector2 A;
|
||||
@@ -20,43 +21,127 @@ namespace J3ML::Geometry
|
||||
LineSegment2D() {}
|
||||
|
||||
/// Constructs a line segment through the given end points.
|
||||
LineSegment2D(const Vector2& a, const Vector2& b);
|
||||
LineSegment2D(const Vector2 &a, const Vector2 &b);
|
||||
|
||||
/// Returns a point on the line.
|
||||
/** @param d The normalized distance along the line segment to compute. If a value in the range [0, 1] is passed, then the
|
||||
returned point lies along this line segment. If some other value is specified, the returned point lies on the line
|
||||
defined by this line segment, but *not* inside the interval from a to b.
|
||||
@note The meaning of d here differs from Line2D::GetPoint and Ray2D::GetPoint. For the class LineSegment2D,
|
||||
GetPoint(0) returns a, and getPoint(1) returns b. This means that GetPoint(1) will not generally be exactly one unit
|
||||
away from the starting point of this line segment, as is the case with Line2D and Ray2D.
|
||||
@return (1-d)*a + d*b;
|
||||
@see a, b, Line2D::GetPoint(), Ray2D::GetPoint() */
|
||||
Vector2 GetPoint(float d) const;
|
||||
Vector2 CenterPoint() const;
|
||||
Vector2 Centroid() const;
|
||||
void Reverse();
|
||||
Vector2 Dir() const;
|
||||
inline Vector2 AnyPointFast() const { return A; }
|
||||
Vector2 ExtremePoint(const Vector2& direction) const;
|
||||
Vector2 ExtremePoint(const Vector2& direction, float& projectionDistance) const;
|
||||
|
||||
/// Returns the center point of this line segment.
|
||||
/** This function is the same as calling GetPoint(0.5f), but provided here as convenience.
|
||||
@see GetPoint(). */
|
||||
Vector2 CenterPoint() const;
|
||||
|
||||
Vector2 Centroid() const;
|
||||
|
||||
/// Reverses the direction of this line segment.
|
||||
/** This function swaps the start and end points of this line segment so that it runs from b to a.
|
||||
This does not have an effect on the set of points represented by this line segment, but it reverses
|
||||
the direction of the vector returned by Dir().
|
||||
@note This function operates in-place.
|
||||
@see a, b, Dir(). */
|
||||
void Reverse();
|
||||
|
||||
/// Returns the normalized direction vector that points in the direction a->b.
|
||||
/** @note The returned vector is normalized, meaning that its length is 1, not |b-a|.
|
||||
@see a, b. */
|
||||
Vector2 Dir() const;
|
||||
|
||||
/// Quickly returns an arbitrary point inside this LineSegment2D. Used in GJK intersection test.
|
||||
Vector2 AnyPointFast() const;
|
||||
|
||||
/// Computes an extreme point of this LineSegment2D in the given direction.
|
||||
/** An extreme point is a farthest point along this LineSegment2D in the given direction. Given a direction,
|
||||
this point is not necessarily unique.
|
||||
@param direction The direction vector of the direction to find the extreme point. This vector may
|
||||
be un-normalized, but may not be null.
|
||||
@return An extreme point of this LineSegment2D in the given direction. The returned point is always
|
||||
either a or b.
|
||||
@see a, b. **/
|
||||
Vector2 ExtremePoint(const Vector2 &direction) const;
|
||||
|
||||
Vector2 ExtremePoint(const Vector2 &direction, float &projectionDistance) const;
|
||||
|
||||
/// Translates this LineSegment2D in world space.
|
||||
/** @param offset The amount of displacement to apply to this LineSegment2D, in world space coordinates.
|
||||
@see Transform(). */
|
||||
void Translate(const Vector2& offset);
|
||||
|
||||
/// Applies a transformation to this line.
|
||||
/** This function operates in-place.
|
||||
@see Translate(), Transform(), classes Matrix3x3, Matrix4x4, Quaternion*/
|
||||
void Transform(const Matrix3x3& transform);
|
||||
void Transform(const Matrix4x4& transform);
|
||||
void Transform(const Quaternion& transform);
|
||||
|
||||
/// Computes the length of this line segment.
|
||||
/** @return |b - a|
|
||||
@see a, b. */
|
||||
float Length() const;
|
||||
/// Computes the squared length of this line segment.
|
||||
/** Calling this function is faster than calling Length(), since this function avoids computing a square root.
|
||||
If you only need to compare lengths to each other and are not interested in the actual length values,
|
||||
you can compare using LengthSq(), instead of Length(), since Sqrt() is an order-preserving,
|
||||
(monotonous and non-decreasing) function. */
|
||||
float LengthSq() const;
|
||||
float LengthSquared() const;
|
||||
|
||||
/// Tests if this line segment is finite
|
||||
/** A line segment is finite if its endpoints a and b do not contain floating-point NaNs for +/- infs
|
||||
in them.
|
||||
@return True if both a and b have finite floating-point values. */
|
||||
bool IsFinite() const;
|
||||
bool Equals(const LineSegment2D& rhs, float epsilon = 1e-3f) const;
|
||||
bool Contains(const Vector2& point, float epsilon = 1e-3f) const;
|
||||
bool Contains(const LineSegment2D& lineSegment, float epsilon = 1e-3f) const;
|
||||
|
||||
/// Tests if this line segment represents the same set of points than the the given line segment.
|
||||
/** @param epsilon Specifies how much distance threshold to allow in the comparison.
|
||||
@return True if a == rhs.a && b == rhs.b, or, a == rhs.b && b == rhs.a, within the given epsilon. */
|
||||
bool Equals(const LineSegment2D& rhs, float epsilon = 1e-3f) const;
|
||||
|
||||
/// Tests if the given point or line segment is contained on this line segment.
|
||||
/** @param epsilon Because a line segment is a one-dimensional object in 3D space, an epsilon value
|
||||
is used as a threshold for this test. This effectively transforms this line segment to a capsule with
|
||||
the radius indicated by this value.
|
||||
@return True if this line segment contains the given point or line segment.
|
||||
@see Intersects, ClosestPoint(), Distance(). */
|
||||
bool Contains(const Vector2& point, float epsilon = 1e-3f) const;
|
||||
bool Contains(const LineSegment2D& rhs, float epsilon = 1e-3f) const;
|
||||
|
||||
/// Computes the closest point on this line segment to the given object.
|
||||
/** @param d If specified, this parameter receives the normalized distance along
|
||||
this line segment which specifies the closest point on this line segment to
|
||||
the specified point.
|
||||
@return The closest point on this line segment to the given object.
|
||||
@see Contains(), Distance(), Intersects(). */
|
||||
Vector2 ClosestPoint(const Vector2& point) const;
|
||||
Vector2 ClosestPoint(const Vector2& point, float& d) const;
|
||||
|
||||
|
||||
|
||||
/** @param d2 [out] If specified, this parameter receives the (normalized, in case of line segment)
|
||||
distance along the other line object which specifies the closest point on that line to
|
||||
this line segment. */
|
||||
Vector2 ClosestPoint(const LineSegment2D& other) const;
|
||||
Vector2 ClosestPoint(const LineSegment2D& other, float& d) const;
|
||||
Vector2 ClosestPoint(const LineSegment2D& other, float& d, float& d2) const;
|
||||
|
||||
/// Computes the distance between this line segment and the given object.
|
||||
/** @param d [out] If specified, this parameter receives the normalized distance along
|
||||
this line segment which specifies the closest point on this line segment to
|
||||
the specified point.
|
||||
@return The distance between this line segment and the given object. */
|
||||
float Distance(const Vector2& point) const;
|
||||
float Distance(const Vector2& point, float& d) const;
|
||||
|
||||
|
||||
/** @param d2 [out] If specified, this parameter receives the (normalized, in case of line segment)
|
||||
distance along the other line object which specifies the closest point on that line to
|
||||
this line segment. */
|
||||
float Distance(const LineSegment2D& other) const;
|
||||
float Distance(const LineSegment2D& other, float& d) const;
|
||||
float Distance(const LineSegment2D& other, float& d, float& d2) const;
|
||||
@@ -64,9 +149,25 @@ namespace J3ML::Geometry
|
||||
float DistanceSq(const Vector2& point) const;
|
||||
float DistanceSq(const LineSegment2D& other) const;
|
||||
|
||||
/** @param epsilon If testing intersection between two line segments, a distance threshold value is used to account
|
||||
for floating point inaccuracies. */
|
||||
bool Intersects(const LineSegment2D& lineSegment, float epsilon = 1e-3f) const;
|
||||
|
||||
|
||||
/// Projects this LineSegment2D onto the given 1D axis direction vector.
|
||||
/** This function collapses this LineSegment2D onto a 1D axis for the purposes of e.g. separate axis test computations.
|
||||
This function returns a 1D range [outMin, outNax] denoting the interval of the projection.
|
||||
@param direction The 1D axis to project to. This vector may be unnormalized, in which case the output
|
||||
of this function gets scaled by the length of this vector.
|
||||
@param outMin [out] Returns the minimum extent of this vector along the projection axis.
|
||||
@param outMax [out] Returns the maximum extent of this vector along the projection axis. */
|
||||
void ProjectToAxis(const Vector2& direction, float& outMin, float& outMax) const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
};
|
||||
|
||||
LineSegment2D operator * (const Matrix3x3& transform, const LineSegment2D& line);
|
||||
LineSegment2D operator * (const Matrix4x4& transform, const LineSegment2D& line);
|
||||
LineSegment2D operator * (const Quaternion& transform, const LineSegment2D& line);
|
||||
}
|
@@ -1,2 +1,123 @@
|
||||
#include <J3ML/Geometry/LineSegment2D.hpp>
|
||||
|
||||
void Line2DClosestPointLineLine(const Vector2& v0, const Vector2& v10, const Vector2& v2, const Vector2& v32, float& d, float& d2) // TODO: Move to Line2D when that exists
|
||||
{
|
||||
// assert(!v10.IsZero());
|
||||
// assert(!v32.IsZero());
|
||||
Vector2 v02 = v0 - v2;
|
||||
float d0232 = v02.Dot(v32);
|
||||
float d3210 = v32.Dot(v10);
|
||||
float d3232 = v32.Dot(v32);
|
||||
// assert(d3232 != 0.f); // Don't call with a zero direction vector.
|
||||
float d0210 = v02.Dot(v10);
|
||||
float d1010 = v10.Dot(v10);
|
||||
float denom = d1010*d3232 - d3210*d3210;
|
||||
|
||||
d = (denom !=0) ? (d0232*d3210 - d0210*d3232) / denom : 0;
|
||||
|
||||
d2 = (d0232 + d * d3210) / d3232;
|
||||
}
|
||||
|
||||
Geometry::LineSegment2D::LineSegment2D(const Vector2 &a, const Vector2 &b)
|
||||
: A(a), B(b) {}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::GetPoint(float d) const {
|
||||
return (1.f - d) * A + d * B;
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::CenterPoint() const {
|
||||
return (A + B) * 0.5f;
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::Centroid() const {
|
||||
return CenterPoint();
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Reverse() {
|
||||
Swap(A, B);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::Dir() const {
|
||||
return (B - A).Normalized();
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::AnyPointFast() const { return A; }
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ExtremePoint(const Vector2 &direction) const {
|
||||
return Vector2::Dot(direction, B - A) >= 0.f ? B : A;
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ExtremePoint(const Vector2 &direction, float &projectionDistance) const {
|
||||
Vector2 extremePoint = ExtremePoint(direction);
|
||||
projectionDistance = extremePoint.Dot(direction);
|
||||
return extremePoint;
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Translate(const Vector2 &offset) {
|
||||
A += offset;
|
||||
B += offset;
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Transform(const Matrix3x3 &transform) {
|
||||
A = transform.Mul(A);
|
||||
B = transform.Mul(B);
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Transform(const Matrix4x4 &transform) {
|
||||
A = transform.Mul(A);
|
||||
B = transform.Mul(B);
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Transform(const Quaternion &transform) {
|
||||
//A = transform.Mul(A);
|
||||
//B = transform.Mul(B);
|
||||
}
|
||||
|
||||
float Geometry::LineSegment2D::Length() const { return A.Distance(B); }
|
||||
|
||||
float Geometry::LineSegment2D::LengthSq() const { return A.DistanceSq(B); }
|
||||
|
||||
float Geometry::LineSegment2D::LengthSquared() const { return LengthSq(); }
|
||||
|
||||
bool Geometry::LineSegment2D::IsFinite() const { return A.IsFinite() && B.IsFinite(); }
|
||||
|
||||
bool Geometry::LineSegment2D::Equals(const Geometry::LineSegment2D &rhs, float epsilon) const {
|
||||
return (A.Equals(rhs.A, epsilon) && B.Equals(rhs.B, epsilon) ||
|
||||
A.Equals(rhs.B, epsilon) && B.Equals(rhs.A, epsilon));
|
||||
}
|
||||
|
||||
bool Geometry::LineSegment2D::Contains(const Vector2 &point, float epsilon) const {
|
||||
return ClosestPoint(point).DistanceSq(point) <= epsilon;
|
||||
}
|
||||
|
||||
bool Geometry::LineSegment2D::Contains(const Geometry::LineSegment2D &rhs, float epsilon) const {
|
||||
return Contains(rhs.A, epsilon) && Contains(rhs.B, epsilon);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Vector2 &point) const {
|
||||
float d;
|
||||
return ClosestPoint(point, d);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Vector2 &point, float &d) const {
|
||||
Vector2 dir = B - A;
|
||||
d = J3ML::Math::Clamp01(Vector2::Dot(point - A, dir) / dir.LengthSquared());
|
||||
return A + d * dir;
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Geometry::LineSegment2D &other) const {
|
||||
float d, d2;
|
||||
return ClosestPoint(other, d, d2);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Geometry::LineSegment2D &other, float &d) const {
|
||||
float d2; return ClosestPoint(other, d, d2);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Geometry::LineSegment2D &other, float &d, float &d2) const {
|
||||
Vector2 dir = B - A;
|
||||
Line2DClosestPointLineLine(A, B - A, other.A, other.B - other.A, d, d2);
|
||||
|
||||
|
||||
return Vector2::Zero;
|
||||
}
|
||||
|
Reference in New Issue
Block a user