The title is probably wrong because I don't know enough math to actually describe my problem in a small sentence.
My current attempt is as follow:
The issue is, this is not working, the culprit seems to be the part where I get the 'axis aligned coordinates', as reverting them back immediately gives the wrong result
public static List<Vector2> Planify3Dto2DPoints2(Vector3[] points, Vector3 centroid, Plane ply, out Vector3[] oldHeights) {
var pz = ply.normal.z;
var px = ply.normal.x;
var py = ply.normal.y;
Plane plx = new Plane(new Vector3(pz, px, py), 0);
Plane plz = new Plane(new Vector3(py, pz, px), 0);
oldHeights = new Vector3[points.Length];
List<Vector2> m_points = new List<Vector2>();
int i = 0;
foreach (Vector3 v3 in points) {
Vector3 v4 = v3 - centroid;
float x = plx.GetDistanceToPoint(v4);//this part is wrong, attempting to get the v4
float z = plz.GetDistanceToPoint(v4);//vector back from the x, z, y coordinates is not
float y = ply.GetDistanceToPoint(v4);//working. removing x * plx.Normal from v4 before
m_points.Add(new Vector2(x, z));// extracting the z coordinate reduces the error, but does not remove it
oldHeights[i++] = new Vector3(x, z, y);
}
return m_points;
}
public static List<Vector3> Spacefy2Dto3DPoints(Vector2[] points, Vector3 centroid, Plane ply, Vector3[] oldHeights = null) {
List<Vector3> m_points = new List<Vector3>();
var pn = new Vector3(ply.normal.x, ply.normal.y, ply.normal.z);
for (int i = 0; i < points.Length; i++) {
Vector3 mp = MoveInPlane(ply, points[i]);
if (oldHeights != null) {
mp += pn * oldHeights[i].z;//AverageOf3ClosestHeight(points[i], oldHeights); not needed yet, but working fine, it's weighted average
}
mp += centroid;
m_points.Add(mp);
}
return m_points;
}
private static Vector3 MoveInPlane(Plane plane, Vector2 vector2) {
var z = plane.normal.z;
var x = plane.normal.x;
var y = plane.normal.y;
return new Vector3(z, x, y) * vector2.x + new Vector3(y, z, x) * vector2.y;
}
The issue lies in this step:
- Get the two perpendicular planes by shifting the plane normal's coordinates
This does not give perpendicular planes.
You may have mistakenly thought this would work due to a simple specific example, e.g. (1, 0, 0) => (0, 1, 0) & (0, 0, 1)
, or that switching around the coordinates effectively switches the roles of the axes, which would be equivalent to rotation by 90 degrees. But try it with e.g. (1, 1, 0)
and you immediately see this does not work.
One approach would be this:
P
with the X
axis (arbitrary choice).abs(dot(X, P)) > 0.5
), then set a vector variable Q <- Z
axis (again, arbitrary). Otherwise, set Q <- X
.U = P ^ Q
and V = P ^ U
. Note that they are not normalized, and {U, V, P}
give a set of right-handed axes.Another minor optimization you could make is to incorporate the - centeroid
into the plane equations themselves to avoid having to do so for every point explicitly.
Vector3 Q = (Math.Abs(ply.normal.x) > 0.5) ? new Vector3D(0.0, 1.0, 0.0)
: new Vector3D(1.0, 0.0, 0.0);
Vector3 U = Vector3.Normalize(Vector3.CrossProduct(ply.normal, Q));
Vector3 V = Vector3.CrossProduct(ply.normal, U);
// no need to normalize V because U and P are already orthonormal
Plane plx = new Plane(U, Vector3.DotProduct(U, centeroid));
Plane plz = new Plane(V, Vector3.DotProduct(V, centeroid));
// ...
foreach (Vector3 v3 in points) {
/* Vector3 v4 = v3 - centroid; // erase this line */
float x = plx.GetDistanceToPoint(v3); // v4 -> v3 for all code following