C# 如何确定点在立方体内部或外部?

C# 如何确定点在立方体内部或外部?,c#,geometry,C#,Geometry,给定三维空间中具有8个顶点的立方体。如何确定myPoint在多维数据集内部还是外部 cube[0] = (x0, y0, z0); cube[1] = (x1, y1, z1); cube[2] = (x2, y2, z2); cube[3] = (x3, y3, z3); cube[4] = (x4, y4, z4); cube[5] = (x5, y5, z5); cube[6] = (x6, y6, z6); cube[7] = (x7, y7, z7); myPoint = (x, y

给定三维空间中具有8个顶点的立方体。如何确定
myPoint
在多维数据集内部还是外部

cube[0] = (x0, y0, z0);
cube[1] = (x1, y1, z1);
cube[2] = (x2, y2, z2);
cube[3] = (x3, y3, z3);
cube[4] = (x4, y4, z4);
cube[5] = (x5, y5, z5);
cube[6] = (x6, y6, z6);
cube[7] = (x7, y7, z7);

myPoint = (x, y, z);

我正试图在3D中实现这一点,可能最简单的方法是为绑定立方体的6个平面中的每个平面计算平面方程,将点插入每个平面,并确保得到的符号为正(或负,取决于计算的平面是向内还是向外)。平面方程为p*法线+k=0,通过取两条边之间的叉积计算法线,然后将其中一个点插入平面方程得到k


更高级的方法是想象立方体定义X、Y和Z轴以及偏移量(由立方体[0]定义),并将其插入矩阵,以转换两个空间之间的点。用这个矩阵的倒数来转换你的点会把它放在“立方体空间”中,立方体与x/y/z轴对齐,这样你就可以对边做一个幅度比较。

如果你想从链接的帖子中实现思想,那么考虑轴对齐立方体(实际上是平行六面体)是有意义的。在这种情况下,检查是
xmin1。从立方体的四条对角线中选择任意一条
2.检查您的点是否在对角线点的范围内。
例如。您选择了开始(0,9,1)和结束(10,3,-1)的对角线

P1(5,6,0)的So P.x(5)>Start.x(0)&P.x(5)End.x(3) P.z(0)End.x(-1) P1在里面 对于P2(5,6,6) P.x(5)>Start.x(0)&P.x(5)End.x(3)
P.z(6)>Start.x(1)&P.z(6)>End.x(-1)

这是我用来解决类似问题的算法,我的立方体没有与三维空间的轴对齐。这可能不是最快的选择,但它确实有效

  • 拾取点abcd,这样a将成为立方体的原点,而bcd将形成立方体的轴(ab通过边连接,与ac以及ad相同)。它不必与3D空间的轴对齐
  • 使用以下公式计算立方体的边长(例如从ab的距离):

    distance = sqrt(sqr(a.X - b.X) + (a.Y - b.Y) + (a.Z - b.Z))
    
  • 确定点是否在立方体内部

    double latA = a DistanceTo(myPoint);
    double latB = b.DistanceTo(myPoint);
    if (Math.Abs(latA + latB - edgeLength) < 0.0001)
    {
        return true;
    }
    double angleA = CalculateAngleA(latA, latB, edgeLength);
    if (angleA > 90.0001) return false;
    double angleB = CalculateAngleA(latB, latA, edgeLength);
    if (angleB > 90.0001) return false;
    
    latB = e.DistanceTo(myPoint);
    if (Math.Abs(latA + latB - edgeLength) < 0.0001)
    {
        return true;
    }
    angleA = CalculateAngleA(latA, latB, edgeLength);
    if (angleA > 90.0001) return false;
    angleB = CalculateAngleA(latB, latA, edgeLength);
    if (angleB > 90.0001) return false;
    
    latB = d.DistanceTo(myPoint);
    if (Math.Abs(latA + latB - edgeLength) < 0.001)
    {
        return true;
    }
    angleA = CalculateAngleA(latA, latB, edgeLength);
    if (angleA > 90.0001) return false;
    angleB = CalculateAngleA(latB, latA, edgeLength);
    if (angleB > 90.0001) return false;
    
    //if all validations pass
    return true;
    
  • 特殊情况#1(轴对齐立方体)

    如图所示,您可以简单地检查所考虑点的X、Y、Z坐标是否位于立方体的X、Y、Z坐标的最小值和最大值

    X_min <= X <= X_max and Y_min <= Y <= Y_max  and Z_min <= Z <= Z_max
    
    1)确定每个面(F1,F2,…)的平面方程(ax+by+cz+d=0)

    1.1计算F1的法向量(将该向量指向对象的外部!!!):

    n1=(n1x,n1y,n1z)

    1.2在F1平面方程中的系数上设置n1

    n1xPx+n1yPy+n1z*Pz-d=val

    在java中,它如下所示:

    private Vector3f normal;
    private float d;
    public PlaneEquation(Vector3f normal, Vector v1){
        this.normal = normal;
        this.d = normal.x*v1x + normal.y*v1y+ normal.z*v1z;
    }
    public float relativePosition(Vector3f p){
        return  normal.x*p.x + normal.y*p.y+ normal.z*p.z - d;
    }
    
    这个方程是一个函数F1(Px,Py,Pz),因此p是一个测试点

    1.3通过在上述等式上设置F1的共面点来计算d的值。我选择v1,因此:

    d=n1xv1x+n1yv1y+n1z*v1z

    2)使用平面函数法relativePosition(矢量3F p)在对象的所有面上执行循环,测试点坐标为F1(Px,Py,Pz),F2(Px,Py,Pz)等。

        boolean OUT = false;
        boolean IN = false;
        boolean ON = false;
        for(PlaneEquation plane : planeList){
           if(plane.relativePosition(point) > 0){
               OUT = true;
               ON = false;
               break;
           }
           if(plane.relativePosition(point) == 0){
              ON = true;
           }
        }
        if(OUT == false && ON == false){
            IN = true;
        }
    
    2.2)如果所有结果F1(p),F2(p)。。。都是负数,所以点在OBCT内,否则为OUT或ON。或者,如果某个结果是肯定的,那么这一点就指出了。

        boolean OUT = false;
        boolean IN = false;
        boolean ON = false;
        for(PlaneEquation plane : planeList){
           if(plane.relativePosition(point) > 0){
               OUT = true;
               ON = false;
               break;
           }
           if(plane.relativePosition(point) == 0){
              ON = true;
           }
        }
        if(OUT == false && ON == false){
            IN = true;
        }
    
    2.3)如果没有结果为正,但至少有一个结果为零,则该点位于对象上。

        boolean OUT = false;
        boolean IN = false;
        boolean ON = false;
        for(PlaneEquation plane : planeList){
           if(plane.relativePosition(point) > 0){
               OUT = true;
               ON = false;
               break;
           }
           if(plane.relativePosition(point) == 0){
              ON = true;
           }
        }
        if(OUT == false && ON == false){
            IN = true;
        }
    
    方法2-重心坐标

    import org.joml.Vector3f;
    
    public class HexaedronEquation {
        // a is origin point
        private Vector3f a,b,c,d;//vertices of parallelepiped
        private Vector3f u,v,w; //direction vectors
        private Vector3f vXu; //v cross u
        private Vector3f wXu; //w croos u
        
        public HexaedronEquation(Vector3f a,Vector3f b,Vector3f c,Vector3f d ) {
            this.a = a;
            this.b = b;
            this.c = c;
            this.d = d;
            this.u = this.b.sub(a,new Vector3f());  // b - a
            this.v = this.c.sub(a, new Vector3f()); // c - a
            this.w = this.d.sub(a, new Vector3f()); // d - a
            this.vXu = this.v.cross(u, new Vector3f());
            this.wXu = this.w.cross(u, new Vector3f());
        }
        
        public float[] getParams(Vector3f p) {
            /* baricentric coordinates
             * solve the system
             * px = ax +t1*ux +t2*vx + t3*wx
             * py = ay +t1*uy +t2*vy + t3*wy
             * pz = az +t1*uz +t2*vz + t3*wz
             */
            float t1 = 0; 
            float t2 = 0; 
            float t3 = 0; 
            Vector3f s = p.sub(a, new Vector3f());
            Vector3f sXu = s.cross(u, new Vector3f());
            
            if(vXu.length() != 0 && w.length()!=0) {
                t3 = s.dot(vXu)/w.dot(vXu);
            }
            
            if(vXu.x != 0) {
                t2 = (sXu.x - t3*wXu.x)/vXu.x;
            }
            if(vXu.y != 0) {
                t2 = (sXu.y - t3*wXu.y)/vXu.y;
            }
            if(vXu.z != 0) {
                t2 = (sXu.z - t3*wXu.z)/vXu.z;
            }
            
            if(u.x != 0) {
                t1 = (s.x - v.x*t2 -w.x*t3)/u.x;
            }
            if(u.y != 0) {
                t1 = (s.y - v.y*t2 -w.y*t3)/u.y;
            }
            if(u.z != 0) {
                t1 = (s.z - v.z*t2 -w.z*t3)/u.z;
            }
            
            return new float[] {t1, t2, t3};
        }
        
        public boolean isInside(Vector3f p) {
            float[] params = getParams(p);
            if(params[0]< 0 || params[0] > 1) return false;
            if(params[1]< 0 || params[1] > 1) return false;
            if(params[2]< 0 || params[2] > 1) return false;
            
            if(params[0]>0 || params[0] <1) return true;
            if(params[1]>0 || params[1] <1) return true;
            if(params[2]>0 || params[2] <1) return true;
            return false;
        }
        
        public boolean isOn(Vector3f p) {
            float[] params = getParams(p);
            if(params[0]< 0 || params[0] > 1) return false;
            if(params[1]< 0 || params[1] > 1) return false;
            if(params[2]< 0 || params[2] > 1) return false;
            
            if(params[0]==0 || params[0] ==1) return true;
            if(params[1]==0 || params[1] ==1) return true;
            if(params[2]==0 || params[2] ==1) return true;
            return false;
        }
        
        public boolean isOnInside(Vector3f p) {
            float[] params = getParams(p);
            System.out.println("params: "+ getParamsString(params));
            if(params[0]< 0 || params[0] > 1) return false;
            if(params[1]< 0 || params[1] > 1) return false;
            if(params[2]< 0 || params[2] > 1) return false;
            return true;
        }
        
        public boolean isOut(Vector3f p) {
            float[] params = getParams(p);
            if(params[0]<0 || params[0] >1) return true;
            if(params[1]<0 || params[1] >1) return true;
            if(params[2]<0 || params[2] >1) return true;
            return false;
        }
    
    import org.joml.Vector3f;
    公共类六面体方程{
    //a是原点
    私有向量3f a,b,c,d;//平行六面体的顶点
    私有向量3f u,v,w;//方向向量
    专用向量3f vXu;//v交叉u
    私有向量3f wXu;//w croos u
    公共六面体方程(向量3F a,向量3F b,向量3F c,向量3F d){
    这个a=a;
    这个.b=b;
    这个.c=c;
    这个。d=d;
    this.u=this.b.sub(a,新向量3f());//b-a
    this.v=this.c.sub(a,新向量3f());//c-a
    this.w=this.d.sub(a,新向量3f());//d-a
    this.vXu=this.v.cross(u,新向量3f());
    this.wXu=this.w.cross(u,新向量3f());
    }
    公共浮点[]获取参数(向量3f p){
    /*重心坐标
    *解系统
    *px=ax+t1*ux+t2*vx+t3*wx
    *py=ay+t1*uy+t2*vy+t3*wy
    *pz=az+t1*uz+t2*vz+t3*wz
    */
    浮点数t1=0;
    浮动t2=0;
    浮动t3=0;
    向量3f s=p.sub(a,新向量3f());
    向量3f sXu=s.cross(u,新向量3f());
    如果(vXu.length()!=0和&w.length()!=0){
    t3=s.dot(vXu)/w.dot(vXu);
    }
    如果(vXu.x!=0){
    t2=(sXu.x-t3*wXu.x)/vXu.x;
    }
    如果(vXu.y!=0){
    t2=(sXu.y-t3*wXu.y)/vXu.y;
    }
    如果(vXu.z!=0){
    t2=(sXu.z-t3*wXu.z)/vXu.z;
    }
    如果(u.x!=0){
    t1=(s.x-v.x*t2-w.x*t3)/u.x;
    }
    如果(u.y!=0){
    t1=(s.y-v.y*t2-w.y*t3)/u.y;
    }
    如果(u.z!=0){
    t1=(s.z-v.z*t2-w.z*t3)/u.z;
    }
    返回新的浮点[]{t1,t2,t3};
    }
    公共布尔isInside(向量3f p){
    float[]params=getParams(p);
    if(params[0]<0 | | params[0]>1)返回false;
    if(params[1]<0 | | params[1]>1)返回false;
    
    import org.joml.Vector3f;
    
    public class HexaedronEquation {
        // a is origin point
        private Vector3f a,b,c,d;//vertices of parallelepiped
        private Vector3f u,v,w; //direction vectors
        private Vector3f vXu; //v cross u
        private Vector3f wXu; //w croos u
        
        public HexaedronEquation(Vector3f a,Vector3f b,Vector3f c,Vector3f d ) {
            this.a = a;
            this.b = b;
            this.c = c;
            this.d = d;
            this.u = this.b.sub(a,new Vector3f());  // b - a
            this.v = this.c.sub(a, new Vector3f()); // c - a
            this.w = this.d.sub(a, new Vector3f()); // d - a
            this.vXu = this.v.cross(u, new Vector3f());
            this.wXu = this.w.cross(u, new Vector3f());
        }
        
        public float[] getParams(Vector3f p) {
            /* baricentric coordinates
             * solve the system
             * px = ax +t1*ux +t2*vx + t3*wx
             * py = ay +t1*uy +t2*vy + t3*wy
             * pz = az +t1*uz +t2*vz + t3*wz
             */
            float t1 = 0; 
            float t2 = 0; 
            float t3 = 0; 
            Vector3f s = p.sub(a, new Vector3f());
            Vector3f sXu = s.cross(u, new Vector3f());
            
            if(vXu.length() != 0 && w.length()!=0) {
                t3 = s.dot(vXu)/w.dot(vXu);
            }
            
            if(vXu.x != 0) {
                t2 = (sXu.x - t3*wXu.x)/vXu.x;
            }
            if(vXu.y != 0) {
                t2 = (sXu.y - t3*wXu.y)/vXu.y;
            }
            if(vXu.z != 0) {
                t2 = (sXu.z - t3*wXu.z)/vXu.z;
            }
            
            if(u.x != 0) {
                t1 = (s.x - v.x*t2 -w.x*t3)/u.x;
            }
            if(u.y != 0) {
                t1 = (s.y - v.y*t2 -w.y*t3)/u.y;
            }
            if(u.z != 0) {
                t1 = (s.z - v.z*t2 -w.z*t3)/u.z;
            }
            
            return new float[] {t1, t2, t3};
        }
        
        public boolean isInside(Vector3f p) {
            float[] params = getParams(p);
            if(params[0]< 0 || params[0] > 1) return false;
            if(params[1]< 0 || params[1] > 1) return false;
            if(params[2]< 0 || params[2] > 1) return false;
            
            if(params[0]>0 || params[0] <1) return true;
            if(params[1]>0 || params[1] <1) return true;
            if(params[2]>0 || params[2] <1) return true;
            return false;
        }
        
        public boolean isOn(Vector3f p) {
            float[] params = getParams(p);
            if(params[0]< 0 || params[0] > 1) return false;
            if(params[1]< 0 || params[1] > 1) return false;
            if(params[2]< 0 || params[2] > 1) return false;
            
            if(params[0]==0 || params[0] ==1) return true;
            if(params[1]==0 || params[1] ==1) return true;
            if(params[2]==0 || params[2] ==1) return true;
            return false;
        }
        
        public boolean isOnInside(Vector3f p) {
            float[] params = getParams(p);
            System.out.println("params: "+ getParamsString(params));
            if(params[0]< 0 || params[0] > 1) return false;
            if(params[1]< 0 || params[1] > 1) return false;
            if(params[2]< 0 || params[2] > 1) return false;
            return true;
        }
        
        public boolean isOut(Vector3f p) {
            float[] params = getParams(p);
            if(params[0]<0 || params[0] >1) return true;
            if(params[1]<0 || params[1] >1) return true;
            if(params[2]<0 || params[2] >1) return true;
            return false;
        }