// Copyright Epic Games, Inc. All Rights Reserved. #include "MinVolumeBox3.h" #if defined(_MSC_VER) && USING_CODE_ANALYSIS #pragma warning(push) #pragma warning(disable : 28020) // disable this warning that occurs in GteMinimumVolumeBox3.h #endif THIRD_PARTY_INCLUDES_START #include "ThirdParty/GTEngine/Mathematics/GteBSNumber.h" #include "ThirdParty/GTEngine/Mathematics/GteBSRational.h" #include "ThirdParty/GTEngine/Mathematics/GteUIntegerFP32.h" #include "ThirdParty/GTEngine/Mathematics/GteUIntegerAP32.h" #include "ThirdParty/GTEngine/Mathematics/GteConvexHull3.h" #include "ThirdParty/GTEngine/Mathematics/GteMinimumVolumeBox3.h" THIRD_PARTY_INCLUDES_END #if defined(_MSC_VER) && USING_CODE_ANALYSIS #pragma warning(pop) #endif #include "CompGeom/ConvexHull3.h" #include "GteUtil.h" #include "Util/ProgressCancel.h" #include "Util/IteratorUtil.h" using namespace UE::Geometry; using namespace UE::Math; namespace UE { namespace Geometry { template struct TMinVolumeBox3Internal { using PreciseHullNumberType = gte::BSNumber>; // 197 is from ConvexHull3 documentation using PreciseBoxNumberType = gte::BSRational; using DVector3 = gte::Vector3; bool bUseExactBox; TArray DoubleInput; TOrientedBox3 Result; bool bSolutionOK; void SetPoint(int32 Index, const TVector& Point) { DoubleInput[Index] = DVector3{ {(double)Point.X, (double)Point.Y, (double)Point.Z} }; } bool ComputeResult(FProgressCancel* Progress) { gte::OrientedBox3 MinimalBox = gte::OrientedBox3(); FConvexHull3d HullCompute; bSolutionOK = HullCompute.Solve(DoubleInput.Num(), [this](int32 Index) { return FVector3d{ DoubleInput[Index][0], DoubleInput[Index][1], DoubleInput[Index][2]}; }); if (!bSolutionOK) { return false; } int NumIndices = 3 * HullCompute.GetTriangles().Num(); if (NumIndices < 1) { bSolutionOK = false; return false; } if (Progress && Progress->Cancelled()) { return false; } const int* Indices = static_cast(&(HullCompute.GetTriangles()[0][0])); // Eww if (bUseExactBox) { gte::MinimumVolumeBox3 BoxCompute; MinimalBox = BoxCompute(DoubleInput.Num(), &DoubleInput[0], NumIndices, Indices, Progress); } else { gte::MinimumVolumeBox3 DoubleCompute; MinimalBox = DoubleCompute(DoubleInput.Num(), &DoubleInput[0], NumIndices, Indices, Progress); } bSolutionOK = true; // if resulting box is not finite, something went wrong, just return an empty box FVector3d Extents = Convert(MinimalBox.extent); if (!FMathd::IsFinite(Extents.SquaredLength())) { bSolutionOK = false; MinimalBox = gte::OrientedBox3(); } Result.Frame = TFrame3( TVector((RealType)MinimalBox.center[0], (RealType)MinimalBox.center[1], (RealType)MinimalBox.center[2]), TVector((RealType)MinimalBox.axis[0][0], (RealType)MinimalBox.axis[0][1], (RealType)MinimalBox.axis[0][2]), TVector((RealType)MinimalBox.axis[1][0], (RealType)MinimalBox.axis[1][1], (RealType)MinimalBox.axis[1][2]), TVector((RealType)MinimalBox.axis[2][0], (RealType)MinimalBox.axis[2][1], (RealType)MinimalBox.axis[2][2]) ); Result.Extents = TVector((RealType)MinimalBox.extent[0], (RealType)MinimalBox.extent[1], (RealType)MinimalBox.extent[2]); return true; } }; } // end namespace UE::Geometry } // end namespace UE template bool TMinVolumeBox3::Solve(int32 NumPoints, TFunctionRef(int32)> GetPointFunc, bool bUseExactBox, FProgressCancel* Progress ) { Initialize(NumPoints, bUseExactBox); check(Internal); for (int32 k = 0; k < NumPoints; ++k) { TVector Point = GetPointFunc(k); Internal->SetPoint(k, Point); } return Internal->ComputeResult(Progress); } template bool TMinVolumeBox3::SolveSubsample(int32 NumPoints, int32 MaxPoints, TFunctionRef(int32)> GetPointFunc, bool bUseExactBox, FProgressCancel* Progress) { if (NumPoints <= MaxPoints) { return Solve(NumPoints, GetPointFunc, bUseExactBox, Progress); } Initialize(MaxPoints, bUseExactBox); check(Internal); int32 k = 0; FModuloIteration Iter(NumPoints); int32 Index; while (Iter.GetNextIndex(Index) && k < MaxPoints) { TVector Point = GetPointFunc(Index); Internal->SetPoint(k, Point); k++; } return Internal->ComputeResult(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(int32 NumPoints, bool bUseExactBox) { Internal = MakePimpl>(); Internal->bUseExactBox = bUseExactBox; Internal->DoubleInput.SetNum(NumPoints); } namespace UE { namespace Geometry { template class GEOMETRYALGORITHMS_API TMinVolumeBox3; template class GEOMETRYALGORITHMS_API TMinVolumeBox3; } // end namespace UE::Geometry } // end namespace UE