从通用平面获取轴对齐的坐标 [英] Getting axis aligned coordinates from generic plane

查看:83
本文介绍了从通用平面获取轴对齐的坐标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

标题可能是错误的,因为我所掌握的数学知识不足以用一句话来描述我的问题.

The title is probably wrong because I don't know enough math to actually describe my problem in a small sentence.

  1. 我有一个3D矢量闭环,我将其称为"3D多边形".
  2. 我需要对其执行仅2D操作,这将返回一个 不同的2D点集
  3. 我需要将这些新的2D点转换回3D.
  1. I have a closed loop of 3D vectors, which I will call '3D polygon'.
  2. I need to perform a 2D-only operation on it, which will return me a different set of 2D points
  3. I need to convert those new 2D points back to 3D.

我当前的尝试如下:

  1. 获得最合适"的平面,以最大程度地降低制作"3D"的机会 转换为2D时,多边形自身相交.
  2. 通过移动法线的垂直方向获得两个垂直平面 坐标
  3. 对于每个3D点,获取到平面的距离以获取轴对齐坐标"
  4. 将Y坐标保存在以后的单独变量中,使用X和Z进行2D操作
  5. 执行2D操作
  6. 获取新的2D点,并获得最接近的3个原始点的加权平均值,以假设新2D点的高度
  7. 将轴对齐坐标" +假定的高度乘以 相应的平面法线将2D点返回3D空间.
  1. Get a 'best fit' plane that minimizes the chances of making the '3D' polygon self intersect when converted to 2D.
  2. Get the two perpendicular planes by shifting the plane normal's coordinates
  3. For each 3D point, get the distances to the planes to get 'axis aligned coordinates'
  4. Save the Y coordinate for later in a separate variable, use X and Z to do the 2D operations
  5. Perform the 2D operations
  6. Get the new 2D points, and get a weighted average of the closest 3 original points to assume the height of the new 2D points
  7. Multiply the 'axis aligned coordinates' + the assumed height by the respective planes normals to return the 2D point to 3D space.

问题是,这不起作用,罪魁祸首似乎是我得到轴对齐坐标"的部分,因为立即将它们还原回会给出错误的结果

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;
    }

推荐答案

问题出在这一步:

  1. 通过移动平面法​​线的坐标来获取两个垂直平面

这不提供垂直平面.

由于一个简单的特定示例,例如: (1, 0, 0) => (0, 1, 0) & (0, 0, 1),或者在坐标周围切换有效地切换了轴的角色,这等效于旋转90度.但是请尝试使用(1, 1, 0),您会立即发现它不起作用.

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.

一种方法是:

  • 取法线PX轴的点积(任意选择).
  • 如果该值接近于1或-1(设置阈值,例如abs(dot(X, P)) > 0.5),则设置矢量变量Q <- Z轴(再次任意).否则,设置Q <- X.
  • 因此,两个垂直平面的法线由U = P ^ QV = P ^ U给出.请注意,它们未标准化,并且{U, V, P}给出了一组右手轴.
  • Take the dot-product of the normal P with the X axis (arbitrary choice).
  • If this is close to 1 or -1 (set a threshold, e.g. abs(dot(X, P)) > 0.5), then set a vector variable Q <- Z axis (again, arbitrary). Otherwise, set Q <- X.
  • The two perpendicular planes' normals are therefore given by U = P ^ Q and V = P ^ U. Note that they are not normalized, and {U, V, P} give a set of right-handed axes.

您可以做的另一项小优化是将- centeroid合并到平面方程本身中,以避免不必为每个点都明确地这样做.

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

这篇关于从通用平面获取轴对齐的坐标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆