// Copyright Epic Games, Inc. All Rights Reserved. #include "MinVolumeBox3.h" #include "CompGeom/ConvexHull3.h" #include "CompGeom/FitOrientedBox3.h" #include "CompGeom/DiTOrientedBox.h" #include "Util/ProgressCancel.h" #include "Util/IteratorUtil.h" using namespace UE::Geometry; using namespace UE::Math; namespace UE { namespace Geometry { template struct TMinVolumeBox3Internal { TOrientedBox3 Result; bool bSolutionOK = false; // Settings RealType SameNormalTolerance = (RealType)0.01; int32 OptimizeIterations = 10; EDiTO DiTODirections = EDiTO::DiTO_26; bool bMostAccurateFit = false; EBox3FitCriteria FitCriteria = EBox3FitCriteria::Volume; void SetSolution(TOrientedBox3 ResultIn) { Result = ResultIn; bSolutionOK = true; } bool ComputeResult(int32 NumPoints, TFunctionRef(int32)> GetPointFunc, FProgressCancel* Progress) { if (bMostAccurateFit) { Result = FitOrientedBox3Points(NumPoints, GetPointFunc, [](int32)->bool {return true;}, FitCriteria, SameNormalTolerance, Progress); if (Progress && Progress->Cancelled()) { return false; } } else { TOrientedBox3 InitialBox = ComputeOrientedBBox(DiTODirections, NumPoints, GetPointFunc); Result = OptimizeOrientedBox3Points(InitialBox, OptimizeIterations, NumPoints, GetPointFunc, [](int32)->bool {return true;}, FitCriteria, Progress); if (Progress && Progress->Cancelled()) { return false; } } // if resulting box is not finite, something went wrong, just return an empty box if (!FMathd::IsFinite(Result.Extents.SquaredLength())) { bSolutionOK = false; return false; } bSolutionOK = true; return true; } }; } // end namespace UE::Geometry } // end namespace UE template bool TMinVolumeBox3::Solve(int32 NumPoints, TFunctionRef(int32)> GetPointFunc, bool bMostAccurateFit, FProgressCancel* Progress ) { Initialize(bMostAccurateFit); check(Internal); return Internal->ComputeResult(NumPoints, GetPointFunc, Progress); } template bool TMinVolumeBox3::SolveSubsample(int32 NumPoints, int32 MaxPoints, TFunctionRef(int32)> GetPointFunc, bool bMostAccurateFit, FProgressCancel* Progress) { if (NumPoints <= MaxPoints) { return Solve(NumPoints, GetPointFunc, bMostAccurateFit, Progress); } Initialize(bMostAccurateFit); check(Internal); int32 k = 0; FModuloIteration Iter(NumPoints); int32 Index; TArray> ReducedPoints; ReducedPoints.Reserve(NumPoints); while (Iter.GetNextIndex(Index) && k < MaxPoints) { TVector Point = GetPointFunc(Index); ReducedPoints.Add(Point); } return Internal->ComputeResult(ReducedPoints.Num(), [&ReducedPoints](int32 PtIdx) {return ReducedPoints[PtIdx];}, Progress); } template bool TMinVolumeBox3::IsSolutionAvailable() const { return Internal && Internal->bSolutionOK; } template void TMinVolumeBox3::GetResult(TOrientedBox3& BoxOut) { ensure(IsSolutionAvailable()); BoxOut = Internal->Result; } template void TMinVolumeBox3::Initialize(bool bMostAccurateFit) { Internal = MakePimpl>(); Internal->bMostAccurateFit = bMostAccurateFit; } namespace UE { namespace Geometry { template class GEOMETRYALGORITHMS_API TMinVolumeBox3; template class GEOMETRYALGORITHMS_API TMinVolumeBox3; } // end namespace UE::Geometry } // end namespace UE