175 lines
6.3 KiB
C++
175 lines
6.3 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Containers/ContainersFwd.h"
|
|
#include "Math/UnrealMathSSE.h"
|
|
#include "Math/Vector.h"
|
|
#include "Math/Vector2D.h"
|
|
|
|
namespace UE::AI
|
|
{
|
|
/** @return 2D cross product. Using X and Y components of 3D vectors. */
|
|
inline FVector::FReal Cross2D(const FVector& A, const FVector& B)
|
|
{
|
|
return A.X * B.Y - A.Y * B.X;
|
|
}
|
|
|
|
/** @return 2D cross product. */
|
|
inline FVector2D::FReal Cross2D(const FVector2D& A, const FVector2D& B)
|
|
{
|
|
return A.X * B.Y - A.Y * B.X;
|
|
}
|
|
|
|
/** @return 2D area of triangle. Using X and Y components of 3D vectors. */
|
|
inline FVector::FReal TriArea2D(const FVector& A, const FVector& B, const FVector& C)
|
|
{
|
|
const FVector AB = B - A;
|
|
const FVector AC = C - A;
|
|
return (AC.X * AB.Y - AB.X * AC.Y) * 0.5;
|
|
}
|
|
|
|
/** @return 2D area of triangle. */
|
|
inline FVector2D::FReal TriArea2D(const FVector2D& A, const FVector2D& B, const FVector2D& C)
|
|
{
|
|
const FVector2D AB = B - A;
|
|
const FVector2D AC = C - A;
|
|
return (AC.X * AB.Y - AB.X * AC.Y) * 0.5;
|
|
}
|
|
|
|
/** @return value in range [0..1] of the 'Point' project on segment 'Start-End'. Using X and Y components of 3D vectors. */
|
|
inline FVector2D::FReal ProjectPointOnSegment2D(const FVector Point, const FVector Start, const FVector End)
|
|
{
|
|
using FReal = FVector::FReal;
|
|
|
|
const FVector2D Seg(End - Start);
|
|
const FVector2D Dir(Point - Start);
|
|
const FReal D = Seg.SquaredLength();
|
|
const FReal T = FVector2D::DotProduct(Seg, Dir);
|
|
|
|
if (T < 0.0)
|
|
{
|
|
return 0.0;
|
|
}
|
|
else if (T > D)
|
|
{
|
|
return 1.0;
|
|
}
|
|
|
|
return D > UE_KINDA_SMALL_NUMBER ? (T / D) : 0.0;
|
|
}
|
|
|
|
/** @return value of the 'Point' project on infinite line defined by segment 'Start-End'. Using X and Y components of 3D vectors. */
|
|
inline FVector::FReal ProjectPointOnLine2D(const FVector Point, const FVector Start, const FVector End)
|
|
{
|
|
using FReal = FVector::FReal;
|
|
|
|
const FVector2D Seg(End - Start);
|
|
const FVector2D Dir(Point - Start);
|
|
const FReal D = Seg.SquaredLength();
|
|
const FReal T = FVector2D::DotProduct(Seg, Dir);
|
|
return D > UE_KINDA_SMALL_NUMBER ? (T / D) : 0.0;
|
|
}
|
|
|
|
/** @return signed distance of the 'Point' to infinite line defined by segment 'Start-End'. Using X and Y components of 3D vectors. */
|
|
inline FVector::FReal SignedDistancePointLine2D(const FVector Point, const FVector Start, const FVector End)
|
|
{
|
|
using FReal = FVector::FReal;
|
|
|
|
const FVector2D Seg(End - Start);
|
|
const FVector2D Dir(Point - Start);
|
|
const FReal Nom = Cross2D(Seg, Dir);
|
|
const FReal Den = Seg.SquaredLength();
|
|
const FReal Dist = Den > UE_KINDA_SMALL_NUMBER ? (Nom / FMath::Sqrt(Den)) : 0.0;
|
|
return Dist;
|
|
}
|
|
|
|
/**
|
|
* Intersects infinite lines defined by segments A and B in 2D. Using X and Y components of 3D vectors.
|
|
* @param StartA start point of segment A
|
|
* @param EndA end point of segment A
|
|
* @param StartB start point of segment B
|
|
* @param EndB end point of segment B
|
|
* @param OutTA intersection value along segment A
|
|
* @param OutTB intersection value along segment B
|
|
* @return if segments A and B intersect in 2D
|
|
*/
|
|
inline bool IntersectLineLine2D(const FVector& StartA, const FVector& EndA, const FVector& StartB, const FVector& EndB, FVector2D::FReal& OutTA, FVector2D::FReal& OutTB)
|
|
{
|
|
using FReal = FVector::FReal;
|
|
|
|
const FVector U = EndA - StartA;
|
|
const FVector V = EndB - StartB;
|
|
const FVector W = StartA - StartB;
|
|
|
|
const FReal D = Cross2D(U, V);
|
|
if (FMath::Abs(D) < UE_KINDA_SMALL_NUMBER)
|
|
{
|
|
OutTA = 0.0;
|
|
OutTB = 0.0;
|
|
return false;
|
|
}
|
|
|
|
OutTA = Cross2D(V, W) / D;
|
|
OutTB = Cross2D(U, W) / D;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Calculates intersection of segment Start-End with convex polygon Poly in 2D. Using X and Y components of 3D vectors.
|
|
* @param Start start point of the segment
|
|
* @param End end point of the segment
|
|
* @param Poly convex polygon
|
|
* @param OutTMin value along the segment of the first intersection point [0..1]
|
|
* @param OutTMax value along the segment of the second intersection point [0..1]
|
|
* @param OutSegMin index of the polygon segment of the first intersection point
|
|
* @param OutSegMax index of the polygon segment of the second intersection point
|
|
* @return true if the segment inside or intersects with the polygon.
|
|
*/
|
|
extern AIMODULE_API bool IntersectSegmentPoly2D(const FVector& Start, const FVector& End, TConstArrayView<FVector> Poly,
|
|
FVector2D::FReal& OutTMin, FVector2D::FReal& OutTMax, int32& OutSegMin, int32& OutSegMax);
|
|
|
|
/**
|
|
* Interpolates bilinear patch A,B,C,D. U interpolates from A->B, and C->D, and V interpolates from AB->CD.
|
|
* @param UV interpolation coordinates [0..1] range
|
|
* @param VertexA first corner
|
|
* @param VertexB second corner
|
|
* @param VertexC third corner
|
|
* @param VertexD fourth corner
|
|
* @return interpolated value.
|
|
*/
|
|
inline FVector Bilinear(const FVector2D UV, const FVector VertexA, const FVector VertexB, const FVector VertexC, const FVector VertexD)
|
|
{
|
|
const FVector AB = FMath::Lerp(VertexA, VertexB, UV.X);
|
|
const FVector CD = FMath::Lerp(VertexD, VertexC, UV.X);
|
|
return FMath::Lerp(AB, CD, UV.Y);
|
|
}
|
|
|
|
/**
|
|
* Finds the UV coordinates of the 'Point' on bilinear patch A,B,C,D. U interpolates from A->B, and C->D, and V interpolates from AB->CD.
|
|
* @param Point location inside or close to the bilinear patch
|
|
* @param VertexA first corner
|
|
* @param VertexB second corner
|
|
* @param VertexC third corner
|
|
* @param VertexD fourth corner
|
|
* @return UV interpolation coordinates of the 'Point'.
|
|
*/
|
|
extern AIMODULE_API FVector2D InvBilinear2D(const FVector Point, const FVector VertexA, const FVector VertexB, const FVector VertexC, const FVector VertexD);
|
|
|
|
/**
|
|
* Finds the UV coordinates of the 'Point' on bilinear patch A,B,C,D. U interpolates from A->B, and C->D, and V interpolates from AB->CD.
|
|
* The UV coordinate is clamped to [0..1] range after inversion.
|
|
* @param Point location inside or close to the bilinear patch
|
|
* @param VertexA first corner
|
|
* @param VertexB second corner
|
|
* @param VertexC third corner
|
|
* @param VertexD fourth corner
|
|
* @return UV interpolation coordinates of the 'Point' in [0..1] range.
|
|
*/
|
|
inline FVector2D InvBilinear2DClamped(const FVector Point, const FVector VertexA, const FVector VertexB, const FVector VertexC, const FVector VertexD)
|
|
{
|
|
return InvBilinear2D(Point, VertexA, VertexB, VertexC, VertexD).ClampAxes(0.0, 1.0);
|
|
}
|
|
|
|
}; // UE::AI
|