288 lines
13 KiB
C#
288 lines
13 KiB
C#
namespace DrawXXL
|
|
{
|
|
using UnityEngine;
|
|
|
|
public class InternalDXXL_Plane
|
|
{
|
|
///plane equation: a*x + b*y + c*z = d
|
|
|
|
///meaning of the parameters:
|
|
/// x-axisInterception = d / a
|
|
/// y-axisInterception = d / b
|
|
/// z-axisInterception = d / c
|
|
/// a, b und c define the planes normal vector as (a,b,c)
|
|
/// a = inverse of x-axisInterception * d
|
|
/// b = inverse of y-axisInterception * d
|
|
/// c = inverse of z-axisInterception * d
|
|
/// d = perpendicular distance to origin?
|
|
|
|
public float a;
|
|
public float b;
|
|
public float c;
|
|
public float d;
|
|
|
|
public Vector3 normalDir; //not necessarily normalized
|
|
|
|
//not defined for every plane:
|
|
Vector3 triangleMountingPoint;
|
|
Vector3 triangleMountingPoint_toFirstTriangleCorner;
|
|
Vector3 triangleMountingPoint_toSecondTriangleCorner;
|
|
|
|
//saving GC.Alloc:
|
|
public static InternalDXXL_Plane horizPlane_throughZeroOrigin = new InternalDXXL_Plane(Vector3.zero, Vector3.up);
|
|
public static InternalDXXL_Plane xyPlane_throughZeroOrigin = new InternalDXXL_Plane(Vector3.zero, Vector3.forward);
|
|
public static InternalDXXL_Plane zyPlane_throughZeroOrigin = new InternalDXXL_Plane(Vector3.zero, Vector3.right);
|
|
|
|
public void Recreate(Vector3 point1, Vector3 point2, Vector3 point3)
|
|
{
|
|
triangleMountingPoint = point1;
|
|
triangleMountingPoint_toFirstTriangleCorner = point2 - point1;
|
|
triangleMountingPoint_toSecondTriangleCorner = point3 - point1;
|
|
normalDir = Vector3.Cross(triangleMountingPoint_toFirstTriangleCorner, triangleMountingPoint_toSecondTriangleCorner);
|
|
normalDir = UtilitiesDXXL_Math.ScaleNonZeroVectorIntoRegionOfFloatPrecision(normalDir);
|
|
|
|
a = normalDir.x;
|
|
b = normalDir.y;
|
|
c = normalDir.z;
|
|
d = triangleMountingPoint.x * a + triangleMountingPoint.y * b + triangleMountingPoint.z * c;
|
|
|
|
ErrorLogForInvalidPlanes();
|
|
}
|
|
|
|
public void Recreate(Vector3 point1, Vector3 point2, Vector3 point3, bool skipErrorOfNonValidPlane)
|
|
{
|
|
triangleMountingPoint = point1;
|
|
triangleMountingPoint_toFirstTriangleCorner = point2 - point1;
|
|
triangleMountingPoint_toSecondTriangleCorner = point3 - point1;
|
|
normalDir = Vector3.Cross(triangleMountingPoint_toFirstTriangleCorner, triangleMountingPoint_toSecondTriangleCorner);
|
|
normalDir = UtilitiesDXXL_Math.ScaleNonZeroVectorIntoRegionOfFloatPrecision(normalDir);
|
|
|
|
a = normalDir.x;
|
|
b = normalDir.y;
|
|
c = normalDir.z;
|
|
d = triangleMountingPoint.x * a + triangleMountingPoint.y * b + triangleMountingPoint.z * c;
|
|
|
|
if (skipErrorOfNonValidPlane == false) { ErrorLogForInvalidPlanes(); }
|
|
}
|
|
|
|
void ErrorLogForInvalidPlanes()
|
|
{
|
|
if (CheckIfPlaneIsValid() == false)
|
|
{
|
|
Debug.LogError("All plane parameters are zero. Seems like you wanted to create a plane with three points that lie on a line and therefore don't describe a plane.");
|
|
}
|
|
}
|
|
|
|
public bool CheckIfPlaneIsValid()
|
|
{
|
|
if (UtilitiesDXXL_Math.ApproximatelyZero(a))
|
|
{
|
|
if (UtilitiesDXXL_Math.ApproximatelyZero(b))
|
|
{
|
|
if (UtilitiesDXXL_Math.ApproximatelyZero(c))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool CheckIfPlaneIsValid(float floatCalculationErrorTolerancePadding)
|
|
{
|
|
if (UtilitiesDXXL_Math.CheckIfValueLiesInsideDistanceNearAnotherValue(0.0f, a, floatCalculationErrorTolerancePadding))
|
|
{
|
|
if (UtilitiesDXXL_Math.CheckIfValueLiesInsideDistanceNearAnotherValue(0.0f, b, floatCalculationErrorTolerancePadding))
|
|
{
|
|
if (UtilitiesDXXL_Math.CheckIfValueLiesInsideDistanceNearAnotherValue(0.0f, c, floatCalculationErrorTolerancePadding))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public InternalDXXL_Plane(Vector3 aPointOnThePlane, Vector3 normalOfThePlane_notNecessarilyNormalized)
|
|
{
|
|
normalDir = normalOfThePlane_notNecessarilyNormalized;
|
|
normalDir = UtilitiesDXXL_Math.ScaleNonZeroVectorIntoRegionOfFloatPrecision(normalDir);
|
|
|
|
if (UtilitiesDXXL_Math.ApproximatelyZero(normalDir))
|
|
{
|
|
Debug.LogError("Cannot create a plane with normal that has 0 lenght: " + UtilitiesDXXL_Log.Get_vectorComponentsAsString(normalDir));
|
|
}
|
|
|
|
a = normalDir.x;
|
|
b = normalDir.y;
|
|
c = normalDir.z;
|
|
d = a * aPointOnThePlane.x + b * aPointOnThePlane.y + c * aPointOnThePlane.z;
|
|
}
|
|
|
|
public void Recreate(Vector3 aPointOnThePlane, Vector3 normalOfThePlane_notNecessarilyNormalized)
|
|
{
|
|
normalDir = normalOfThePlane_notNecessarilyNormalized;
|
|
normalDir = UtilitiesDXXL_Math.ScaleNonZeroVectorIntoRegionOfFloatPrecision(normalDir);
|
|
|
|
if (UtilitiesDXXL_Math.ApproximatelyZero(normalDir))
|
|
{
|
|
Debug.LogError("Cannot create a plane with normal that has 0 lenght: " + UtilitiesDXXL_Log.Get_vectorComponentsAsString(normalDir));
|
|
}
|
|
|
|
a = normalDir.x;
|
|
b = normalDir.y;
|
|
c = normalDir.z;
|
|
d = a * aPointOnThePlane.x + b * aPointOnThePlane.y + c * aPointOnThePlane.z;
|
|
}
|
|
|
|
public InternalDXXL_Plane()
|
|
{
|
|
//default: xy-plane through origin
|
|
normalDir = new Vector3(0.0f, 0.0f, 1.0f);
|
|
a = normalDir.x;
|
|
b = normalDir.y;
|
|
c = normalDir.z;
|
|
d = 0.0f;
|
|
}
|
|
|
|
public void TryRecreateAsCopyOfOther(InternalDXXL_Plane planeToCopyFieldsFrom)
|
|
{
|
|
if (planeToCopyFieldsFrom != null)
|
|
{
|
|
normalDir = planeToCopyFieldsFrom.normalDir;
|
|
a = planeToCopyFieldsFrom.a;
|
|
b = planeToCopyFieldsFrom.b;
|
|
c = planeToCopyFieldsFrom.c;
|
|
d = planeToCopyFieldsFrom.d;
|
|
}
|
|
}
|
|
|
|
public bool CheckIfLineIsParallel(InternalDXXL_Line line3D)
|
|
{
|
|
return UtilitiesDXXL_Math.Check_ifVectors_arePerp(normalDir, line3D.direction_normalized);
|
|
}
|
|
|
|
public static void Calc_intersectionLine_ofTwoPlanes(ref InternalDXXL_Line alreadyConstructedLineToFill, InternalDXXL_Plane plane1, InternalDXXL_Plane plane2)
|
|
{
|
|
Vector3 directionOfLine3D = Vector3.Cross(plane1.normalDir, plane2.normalDir);
|
|
directionOfLine3D = UtilitiesDXXL_Math.ScaleNonZeroVectorIntoRegionOfFloatPrecision(directionOfLine3D);
|
|
Vector3 aValidPointOnTheLine3D = default;
|
|
|
|
bool lineIsParallelTo_yzPlane = UtilitiesDXXL_Math.ApproximatelyZero(directionOfLine3D.x);
|
|
if (lineIsParallelTo_yzPlane == false)
|
|
{
|
|
aValidPointOnTheLine3D.x = 0.0f;
|
|
aValidPointOnTheLine3D.z = (((plane2.d * plane1.b) - (plane1.d * plane2.b)) / ((plane2.c * plane1.b) - (plane1.c * plane2.b)));
|
|
|
|
if (plane1.b != 0.0f)
|
|
{
|
|
aValidPointOnTheLine3D.y = ((plane1.d - plane1.c * aValidPointOnTheLine3D.z) / plane1.b);
|
|
}
|
|
else
|
|
{
|
|
aValidPointOnTheLine3D.y = ((plane2.d - plane2.c * aValidPointOnTheLine3D.z) / plane2.b);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool lineIsParallelTo_xzPlane = UtilitiesDXXL_Math.ApproximatelyZero(directionOfLine3D.y);
|
|
if (lineIsParallelTo_xzPlane == false)
|
|
{
|
|
aValidPointOnTheLine3D.y = 0.0f;
|
|
aValidPointOnTheLine3D.x = (((plane2.c * plane1.d) - (plane1.c * plane2.d)) / ((plane2.c * plane1.a) - (plane1.c * plane2.a)));
|
|
|
|
if (plane1.c != 0.0f)
|
|
{
|
|
aValidPointOnTheLine3D.z = ((plane1.d - plane1.a * aValidPointOnTheLine3D.x) / plane1.c);
|
|
}
|
|
else
|
|
{
|
|
aValidPointOnTheLine3D.z = ((plane2.d - plane2.a * aValidPointOnTheLine3D.x) / plane2.c);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool lineIsParallelTo_xyPlane = UtilitiesDXXL_Math.ApproximatelyZero(directionOfLine3D.z);
|
|
if (lineIsParallelTo_xyPlane == false)
|
|
{
|
|
aValidPointOnTheLine3D.z = 0.0f;
|
|
aValidPointOnTheLine3D.y = (((plane2.a * plane1.d) - (plane1.a * plane2.d)) / ((plane2.a * plane1.b) - (plane1.a * plane2.b)));
|
|
|
|
if (plane1.a != 0.0f)
|
|
{
|
|
aValidPointOnTheLine3D.x = ((plane1.d - plane1.b * aValidPointOnTheLine3D.y) / plane1.a);
|
|
}
|
|
else
|
|
{
|
|
aValidPointOnTheLine3D.x = ((plane2.d - plane2.b * aValidPointOnTheLine3D.y) / plane2.a);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//-> "directionOfLine3D" is zero
|
|
//-> the two planes are parallel
|
|
//-> "aValidPointOnTheLine3D" is undefined (=left at default of 0/0/0)
|
|
//-> "alreadyConstructedLineToFill.Recreate" will notify this via ErrorCode-Log
|
|
}
|
|
}
|
|
}
|
|
alreadyConstructedLineToFill.Recreate(aValidPointOnTheLine3D, directionOfLine3D, false);
|
|
}
|
|
|
|
public Vector3 GetIntersectionWithLine(InternalDXXL_Line intersectingLine)
|
|
{
|
|
return intersectingLine.Get_intersectionPoint_withPlane_withoutParallelCheck(this);
|
|
}
|
|
|
|
|
|
static InternalDXXL_Line perpLine = new InternalDXXL_Line();
|
|
public Vector3 Get_perpProjectionOfPointOnPlane(Vector3 pointToProjectOntoPlane)
|
|
{
|
|
if (UtilitiesDXXL_Math.ApproximatelyZero(normalDir))
|
|
{
|
|
Debug.LogError("not allowed: normal is zero: " + UtilitiesDXXL_Log.Get_vectorComponentsAsString(normalDir));
|
|
normalDir = Vector3.forward;
|
|
}
|
|
|
|
perpLine.Recreate(pointToProjectOntoPlane, normalDir, false);
|
|
return perpLine.Get_intersectionPoint_withPlane_withoutParallelCheck(this);
|
|
}
|
|
|
|
public Vector3 Get_perpVector_fromPlaneToPoint(Vector3 point_toWhichResultingVectorWillPoint)
|
|
{
|
|
Vector3 perpProjection_ofPointOnPlane = Get_perpProjectionOfPointOnPlane(point_toWhichResultingVectorWillPoint);
|
|
return (point_toWhichResultingVectorWillPoint - perpProjection_ofPointOnPlane);
|
|
}
|
|
|
|
static InternalDXXL_Line customProjectionDirLine = new InternalDXXL_Line();
|
|
public Vector3 Get_projectionOfPointOnPlane_alongCustomDir(Vector3 pointToProjectOntoPlane, Vector3 dir_alongWhichToProject)
|
|
{
|
|
customProjectionDirLine.Recreate(pointToProjectOntoPlane, dir_alongWhichToProject, false);
|
|
return customProjectionDirLine.Get_intersectionPoint_withPlane_withoutParallelCheck(this);
|
|
}
|
|
|
|
public bool CheckIf_twoPoints_lieOnDifferentSidesOfThePlane_returnsFalseIfAGivenPointIsONplane(Vector3 point1, Vector3 point2)
|
|
{
|
|
return UtilitiesDXXL_Math.Check_ifVectorsPointAwayFromEachOther_perpCountsAsPointingInSameDir(Get_perpVector_fromPlaneToPoint(point1), Get_perpVector_fromPlaneToPoint(point2));
|
|
}
|
|
|
|
public Vector3 Get_projectionOfVectorOntoPlane(Vector3 vector_toProject)
|
|
{
|
|
return (Get_perpProjectionOfPointOnPlane(vector_toProject) - Get_perpProjectionOfPointOnPlane(Vector3.zero));
|
|
}
|
|
|
|
public Vector3 Get_projectionOfVectorOntoPlane_alongCustomDir(Vector3 vector_toProject, Vector3 dir_alongWhichToProject)
|
|
{
|
|
//-> doesn't contain parallel-check. Caller has to ensure that "dir_alongWhichToProject" is not parallel to plane
|
|
return (Get_projectionOfPointOnPlane_alongCustomDir(vector_toProject, dir_alongWhichToProject) - Get_projectionOfPointOnPlane_alongCustomDir(Vector3.zero, dir_alongWhichToProject));
|
|
}
|
|
|
|
public static bool IsHorizontal(InternalDXXL_Plane planeToCheckIfItIsHorizontal)
|
|
{
|
|
return (UtilitiesDXXL_Math.ApproximatelyZero(planeToCheckIfItIsHorizontal.normalDir.x) && UtilitiesDXXL_Math.ApproximatelyZero(planeToCheckIfItIsHorizontal.normalDir.z));
|
|
}
|
|
|
|
}
|
|
|
|
}
|