从通用平面获取轴对齐坐标
Getting axis aligned coordinates from generic plane
标题可能有误,因为我的数学知识不够用一个小句子来实际描述我的问题。
- 我有一个 3D 矢量闭环,我将其称为“3D 多边形”。
- 我需要对其执行仅二维操作,这将 return 我
不同的二维点集
- 我需要将那些新的 2D 点转换回 3D。
我目前的尝试如下:
- 得到一架 'best fit' 飞机,使制作“3D”的机会最小化
多边形在转换为 2D 时自相交。
- 通过平移平面法线得到两个垂直平面
坐标
- 对于每个 3D 点,获取到平面的距离以获得 'axis aligned coordinates'
- 将 Y 坐标保存在单独的变量中以备后用,使用 X 和 Z 进行二维操作
- 执行二维操作
- 获取新的二维点,并取最近的3个原始点的加权平均值来假设新的二维点的高度
- 将 'axis aligned coordinates' + 假设的高度乘以
各个平面法线 return 2D 指向 3D space.
问题是,这不起作用,罪魁祸首似乎是我得到 'axis aligned coordinates' 的部分,因为立即将它们还原会给出错误的结果
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;
}
问题出在这一步:
- Get the two perpendicular planes by shifting the plane normal's coordinates
这不给出垂直平面。
由于一个简单的具体示例,您可能错误地认为这会起作用,例如(1, 0, 0) => (0, 1, 0) & (0, 0, 1)
,或者说围绕坐标的切换有效地切换了坐标轴的作用,相当于旋转了90度。但是尝试使用例如(1, 1, 0)
你马上就会发现这是行不通的。
一种方法是这样的:
- 取法线
P
的dot-product带X
轴(任意选择)
- 如果这接近于 1 或 -1(设置一个阈值,例如
abs(dot(X, P)) > 0.5
),则设置一个矢量变量 Q <- Z
轴(再次,任意)。否则,设置 Q <- X
.
- 因此,两个垂直平面的法线由
U = P ^ Q
和 V = P ^ U
给出。注意它们没有归一化,{U, V, P}
给出一组right-handed轴。
您可以进行的另一个小优化是将 - centeroid
并入平面方程本身,以避免必须对每个点明确地这样做。
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
标题可能有误,因为我的数学知识不够用一个小句子来实际描述我的问题。
- 我有一个 3D 矢量闭环,我将其称为“3D 多边形”。
- 我需要对其执行仅二维操作,这将 return 我 不同的二维点集
- 我需要将那些新的 2D 点转换回 3D。
我目前的尝试如下:
- 得到一架 'best fit' 飞机,使制作“3D”的机会最小化 多边形在转换为 2D 时自相交。
- 通过平移平面法线得到两个垂直平面 坐标
- 对于每个 3D 点,获取到平面的距离以获得 'axis aligned coordinates'
- 将 Y 坐标保存在单独的变量中以备后用,使用 X 和 Z 进行二维操作
- 执行二维操作
- 获取新的二维点,并取最近的3个原始点的加权平均值来假设新的二维点的高度
- 将 'axis aligned coordinates' + 假设的高度乘以 各个平面法线 return 2D 指向 3D space.
问题是,这不起作用,罪魁祸首似乎是我得到 'axis aligned coordinates' 的部分,因为立即将它们还原会给出错误的结果
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;
}
问题出在这一步:
- Get the two perpendicular planes by shifting the plane normal's coordinates
这不给出垂直平面。
由于一个简单的具体示例,您可能错误地认为这会起作用,例如(1, 0, 0) => (0, 1, 0) & (0, 0, 1)
,或者说围绕坐标的切换有效地切换了坐标轴的作用,相当于旋转了90度。但是尝试使用例如(1, 1, 0)
你马上就会发现这是行不通的。
一种方法是这样的:
- 取法线
P
的dot-product带X
轴(任意选择) - 如果这接近于 1 或 -1(设置一个阈值,例如
abs(dot(X, P)) > 0.5
),则设置一个矢量变量Q <- Z
轴(再次,任意)。否则,设置Q <- X
. - 因此,两个垂直平面的法线由
U = P ^ Q
和V = P ^ U
给出。注意它们没有归一化,{U, V, P}
给出一组right-handed轴。
您可以进行的另一个小优化是将 - centeroid
并入平面方程本身,以避免必须对每个点明确地这样做。
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