Files
UnrealEngineUWP/Engine/Plugins/Runtime/MeshModelingToolset/Source/ModelingComponents/Private/Mechanics/CubeGrid.cpp
michael balzer b8a1c9b6cf GeometryCore: Remove ExplicitUseGeometryMathTypes.h
#ROBOMERGE-AUTHOR: michael.balzer
#ROBOMERGE-SOURCE: CL 18227685 in //UE5/Release-5.0/... via CL 18229350
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v895-18170469)
#ROBOMERGE[STARSHIP]: UE5-Main

[CL 18231457 by michael balzer in ue5-release-engine-test branch]
2021-11-17 19:02:44 -05:00

129 lines
4.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Mechanics/CubeGrid.h"
#include "BaseGizmos/GizmoMath.h"
using namespace UE::Geometry;
#define LOCTEXT_NAMESPACE "CubeGrid"
namespace CubeGridLocals {
FVector3d Floor(const FVector3d& VectorIn)
{
return FVector3d(
FMath::Floor(VectorIn.X),
FMath::Floor(VectorIn.Y),
FMath::Floor(VectorIn.Z));
}
}
FCubeGrid::FCubeFace::FCubeFace(const FVector3d& PointOnFace, EFaceDirection DirectionIn, uint8 SourceCubeGridPower)
: Direction(DirectionIn)
, CubeGridPower(SourceCubeGridPower)
{
FVector3d MinCorner = CubeGridLocals::Floor(PointOnFace);
Center = FVector3d(0.5, 0.5, 0.5);
Center[DirToFlatDim(DirectionIn)] = 0;
Center += MinCorner;
}
FVector3d FCubeGrid::FCubeFace::GetMinCorner() const
{
return CubeGridLocals::Floor(Center);
}
FVector3d FCubeGrid::FCubeFace::GetMaxCorner() const
{
return FVector3d(
FMath::CeilToDouble(Center.X),
FMath::CeilToDouble(Center.Y),
FMath::CeilToDouble(Center.Z));
}
bool FCubeGrid::GetHitGridFaceBasedOnRay(const FVector3d& WorldHitPoint, const FVector3d& NormalOrTowardCameraRay,
FCubeGrid::FCubeFace& FaceOut, bool bPierceToBack, double PlaneTolerance) const
{
// TODO: Scale plane tolerance to grid space
FVector3d GridSpaceHitPoint = ToGridPoint(WorldHitPoint);
FVector3d GridSpaceRayDirection = GridFrame.ToFrameVector(NormalOrTowardCameraRay);
FVector3d CellMinCorner = CubeGridLocals::Floor(GridSpaceHitPoint);
// Generally, we start from the point in grid space and hit test the faces of the enclosing cell using the
// given ray direction to figure out which face to select. However, there is ambiguity about which cell to
// place our point when it lies on a face. In those cases, if the ray direction is inward into the current
// cell, we need to choose the adjacent one so that the direction is outward. We also clamp the point to
// the face because it makes it easier to treat the case properly based on what we do to t=0 during our
// ray cast later, and guarantees that the point is inside (boundary-inclusive) our cell.
for (int32 i = 0; i < 3; ++i)
{
double LowerFace = CellMinCorner[i];
double UpperFace = LowerFace + 1;
if ((UpperFace - GridSpaceHitPoint[i]) * CurrentCellSize <= PlaneTolerance)
{
GridSpaceHitPoint[i] = UpperFace;
// Shift the chosen cell up if ray is going in the negative direction
CellMinCorner[i] += GridSpaceRayDirection[i] < 0 ? 1 : 0;
}
else if ((GridSpaceHitPoint[i] - LowerFace) * CurrentCellSize <= PlaneTolerance)
{
GridSpaceHitPoint[i] = LowerFace;
// Shift the chosen cell down if ray is going in the positive direction
CellMinCorner[i] += GridSpaceRayDirection[i] > 0 ? -1 : 0;
}
}
// Now do ray cast:
GridSpaceRayDirection *= bPierceToBack ? -1 : 1;
double BestT = TNumericLimits<double>::Max();
// We're going iterate over XYZ dimensions and the min and max face in each dimension.
for (int Dimension = 0; Dimension < 3; ++Dimension)
{
for (int Face = 0; Face < 2; ++Face) // 0 for min, 1 for other side
{
if (GridSpaceRayDirection[Dimension] == 0)
{
continue; // ray is parallel
}
// Since all of our planes are axis-aligned, getting the intersection T is just a matter of dividing
// the difference of the relevant coordinate by our dt in that direction (i.e. ray direction coordinate)
double PlaneCoordInDimension = CellMinCorner[Dimension] + Face;
double PlaneT = (PlaneCoordInDimension - GridSpaceHitPoint[Dimension]) / GridSpaceRayDirection[Dimension];
if (PlaneT == 0 && bPierceToBack)
{
// If on a face and piercing back, we don't want to select that same face
continue;
}
if (PlaneT >= 0 && PlaneT < BestT)
{
BestT = PlaneT;
FVector3d ArbitraryPointOnPlane = GridSpaceHitPoint;
ArbitraryPointOnPlane[Dimension] = PlaneCoordInDimension;
EFaceDirection FaceDirection = static_cast<EFaceDirection>(Dimension + 1);
// Face direction should actually be flipped either if this is the lower face or if it's
// a pierce to back, and the two flips can cancel themselves out.
FaceDirection = (bPierceToBack ^ (Face == 0)) ? FlipDir(FaceDirection) : FaceDirection;
FaceOut = FCubeGrid::FCubeFace(ArbitraryPointOnPlane, FaceDirection, GetGridPower());
}
}
}
return BestT >= 0 && BestT != TNumericLimits<double>::Max();
}
#undef LOCTEXT_NAMESPACE