2019-12-27 09:26:59 -05:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
2019-09-12 13:55:17 -04:00
|
|
|
|
|
|
|
|
#include "Snapping/BasePositionSnapSolver3.h"
|
|
|
|
|
#include "VectorUtil.h"
|
|
|
|
|
#include "LineTypes.h"
|
|
|
|
|
#include "Distance/DistLine3Ray3.h"
|
|
|
|
|
|
2021-03-09 19:33:56 -04:00
|
|
|
using namespace UE::Geometry;
|
2019-09-12 13:55:17 -04:00
|
|
|
|
|
|
|
|
FBasePositionSnapSolver3::FBasePositionSnapSolver3()
|
|
|
|
|
{
|
|
|
|
|
// initialize to sane values
|
|
|
|
|
SnapMetricFunc =
|
2021-03-30 21:25:22 -04:00
|
|
|
[](const FVector3d& A, const FVector3d& B) { return Distance(A, B); };
|
2019-09-12 13:55:17 -04:00
|
|
|
SnapMetricTolerance = 1.0;
|
|
|
|
|
|
2021-10-28 19:47:45 -04:00
|
|
|
FBasePositionSnapSolver3::Reset();
|
2019-09-12 13:55:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FBasePositionSnapSolver3::Reset()
|
|
|
|
|
{
|
|
|
|
|
TargetPoints.Reset();
|
|
|
|
|
TargetLines.Reset();
|
|
|
|
|
TargetCircles.Reset();
|
|
|
|
|
ResetActiveSnap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FBasePositionSnapSolver3::ResetActiveSnap()
|
|
|
|
|
{
|
|
|
|
|
ClearActiveSnapData();
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-11 16:57:36 -05:00
|
|
|
void FBasePositionSnapSolver3::AddPointTarget(const FVector3d& Position, int TargetID, int Priority)
|
2019-09-12 13:55:17 -04:00
|
|
|
{
|
2019-11-11 16:57:36 -05:00
|
|
|
FSnapTargetPoint Point;
|
|
|
|
|
Point.Position = Position;
|
|
|
|
|
Point.TargetID = TargetID;
|
|
|
|
|
Point.Priority = Priority;
|
|
|
|
|
Point.bHaveCustomMetric = false;
|
|
|
|
|
TargetPoints.Add(Point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FBasePositionSnapSolver3::AddPointTarget(const FVector3d& Position, int TargetID, const FCustomMetric& CustomMetric, int Priority)
|
|
|
|
|
{
|
|
|
|
|
FSnapTargetPoint Point;
|
|
|
|
|
Point.Position = Position;
|
|
|
|
|
Point.TargetID = TargetID;
|
|
|
|
|
Point.Priority = Priority;
|
|
|
|
|
Point.bHaveCustomMetric = true;
|
|
|
|
|
Point.CustomMetric = CustomMetric;
|
2019-09-12 13:55:17 -04:00
|
|
|
TargetPoints.Add(Point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FBasePositionSnapSolver3::RemovePointTargetsByID(int TargetID)
|
|
|
|
|
{
|
|
|
|
|
bool bRemoved = false;
|
|
|
|
|
int Num = TargetPoints.Num();
|
|
|
|
|
for (int k = 0; k < Num; ++k)
|
|
|
|
|
{
|
|
|
|
|
if (TargetPoints[k].TargetID == TargetID)
|
|
|
|
|
{
|
|
|
|
|
TargetPoints.RemoveAtSwap(k);
|
|
|
|
|
k--; Num--;
|
|
|
|
|
bRemoved = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bRemoved;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FBasePositionSnapSolver3::AddLineTarget(const FLine3d& Line, int TargetID, int Priority)
|
|
|
|
|
{
|
|
|
|
|
FSnapTargetLine Target = { Line, TargetID, Priority };
|
|
|
|
|
TargetLines.Add(Target);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool FBasePositionSnapSolver3::RemoveLineTargetsByID(int TargetID)
|
|
|
|
|
{
|
|
|
|
|
bool bRemoved = false;
|
|
|
|
|
int Num = TargetLines.Num();
|
|
|
|
|
for (int k = 0; k < Num; ++k)
|
|
|
|
|
{
|
|
|
|
|
if (TargetLines[k].TargetID == TargetID)
|
|
|
|
|
{
|
|
|
|
|
TargetLines.RemoveAtSwap(k);
|
|
|
|
|
k--; Num--;
|
|
|
|
|
bRemoved = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bRemoved;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FBasePositionSnapSolver3::AddCircleTarget(const FCircle3d& Circle, int TargetID, int Priority)
|
|
|
|
|
{
|
|
|
|
|
FSnapTargetCircle Target = { Circle, TargetID, Priority };
|
|
|
|
|
TargetCircles.Add(Target);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool FBasePositionSnapSolver3::RemoveCircleTargetsByID(int TargetID)
|
|
|
|
|
{
|
|
|
|
|
bool bRemoved = false;
|
|
|
|
|
int Num = TargetCircles.Num();
|
|
|
|
|
for (int k = 0; k < Num; ++k)
|
|
|
|
|
{
|
|
|
|
|
if (TargetCircles[k].TargetID == TargetID)
|
|
|
|
|
{
|
|
|
|
|
TargetCircles.RemoveAtSwap(k);
|
|
|
|
|
k--; Num--;
|
|
|
|
|
bRemoved = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bRemoved;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FBasePositionSnapSolver3::AddIgnoreTarget(int TargetID)
|
|
|
|
|
{
|
|
|
|
|
IgnoreTargets.Add(TargetID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FBasePositionSnapSolver3::RemoveIgnoreTarget(int TargetID)
|
|
|
|
|
{
|
|
|
|
|
IgnoreTargets.Remove(TargetID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FBasePositionSnapSolver3::IsIgnored(int TargetID) const
|
|
|
|
|
{
|
|
|
|
|
return IgnoreTargets.Contains(TargetID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-09-01 14:07:48 -04:00
|
|
|
int32 FBasePositionSnapSolver3::FindIndexOfBestSnapInSet(const TArray<FSnapTargetPoint>& TestTargets, double& MinMetric, int& MinPriority,
|
2019-09-12 13:55:17 -04:00
|
|
|
const TFunction<FVector3d(const FVector3d&)>& GetSnapPointFromFunc)
|
|
|
|
|
{
|
2020-09-01 14:07:48 -04:00
|
|
|
int32 BestIndex = -1;
|
2019-09-12 13:55:17 -04:00
|
|
|
int NumTargets = TestTargets.Num();
|
|
|
|
|
for (int k = 0; k < NumTargets; ++k)
|
|
|
|
|
{
|
|
|
|
|
if (TestTargets[k].Priority > MinPriority)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (IgnoreTargets.Contains(TestTargets[k].TargetID))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-11 16:57:36 -05:00
|
|
|
double TestMetric = SnapMetricTolerance;
|
|
|
|
|
if (TestTargets[k].bHaveCustomMetric)
|
|
|
|
|
{
|
|
|
|
|
switch (TestTargets[k].CustomMetric.Type)
|
|
|
|
|
{
|
|
|
|
|
case ECustomMetricType::MinValue:
|
|
|
|
|
TestMetric = FMathd::Min(SnapMetricTolerance, TestTargets[k].CustomMetric.Value);
|
|
|
|
|
break;
|
|
|
|
|
case ECustomMetricType::Multiplier:
|
|
|
|
|
TestMetric = TestTargets[k].CustomMetric.Value * SnapMetricTolerance;
|
|
|
|
|
break;
|
|
|
|
|
case ECustomMetricType::ReplaceValue:
|
|
|
|
|
TestMetric = TestTargets[k].CustomMetric.Value;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-12 13:55:17 -04:00
|
|
|
FVector3d SnapPoint = GetSnapPointFromFunc(TestTargets[k].Position);
|
|
|
|
|
double Metric = SnapMetricFunc(SnapPoint, TestTargets[k].Position);
|
2019-11-11 16:57:36 -05:00
|
|
|
|
|
|
|
|
if (Metric < TestMetric)
|
2019-09-12 13:55:17 -04:00
|
|
|
{
|
|
|
|
|
if (Metric < MinMetric || TestTargets[k].Priority < MinPriority)
|
|
|
|
|
{
|
|
|
|
|
MinMetric = Metric;
|
2020-09-01 14:07:48 -04:00
|
|
|
BestIndex = k;
|
2019-09-12 13:55:17 -04:00
|
|
|
MinPriority = TestTargets[k].Priority;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-01 14:07:48 -04:00
|
|
|
return BestIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FBasePositionSnapSolver3::FSnapTargetPoint* FBasePositionSnapSolver3::FindBestSnapInSet(const TArray<FSnapTargetPoint>& TestTargets, double& MinMetric, int& MinPriority,
|
|
|
|
|
const TFunction<FVector3d(const FVector3d&)>& GetSnapPointFromFunc)
|
|
|
|
|
{
|
|
|
|
|
const FSnapTargetPoint* BestTarget = nullptr;
|
|
|
|
|
int32 BestIndex = FindIndexOfBestSnapInSet(TestTargets, MinMetric, MinPriority, GetSnapPointFromFunc);
|
|
|
|
|
if (BestIndex >= 0)
|
|
|
|
|
{
|
|
|
|
|
BestTarget = &TestTargets[BestIndex];
|
|
|
|
|
}
|
2019-09-12 13:55:17 -04:00
|
|
|
return BestTarget;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool FBasePositionSnapSolver3::TestSnapTarget(const FSnapTargetPoint& Target, double MinMetric, int MinPriority,
|
|
|
|
|
const TFunction<FVector3d(const FVector3d&)>& GetSnapPointFromFunc)
|
|
|
|
|
{
|
|
|
|
|
if (Target.Priority <= MinPriority)
|
|
|
|
|
{
|
|
|
|
|
FVector3d SnapPoint = GetSnapPointFromFunc(Target.Position);
|
|
|
|
|
double Metric = SnapMetricFunc(SnapPoint, Target.Position);
|
|
|
|
|
if (Metric < SnapMetricTolerance && Metric < MinMetric)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FBasePositionSnapSolver3::SetActiveSnapData(const FSnapTargetPoint& TargetPoint, const FVector3d& FromPoint, const FVector3d& ToPoint, double Metric)
|
|
|
|
|
{
|
|
|
|
|
bHaveActiveSnap = true;
|
|
|
|
|
ActiveSnapTarget = TargetPoint;
|
|
|
|
|
ActiveSnapFromPoint = FromPoint;
|
|
|
|
|
ActiveSnapToPoint = ToPoint;
|
|
|
|
|
SnappedPointMetric = Metric;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FBasePositionSnapSolver3::ClearActiveSnapData()
|
|
|
|
|
{
|
|
|
|
|
bHaveActiveSnap = false;
|
|
|
|
|
}
|