如何确定一个点是在立方体内部还是外部?

时间:2014-01-10 06:04:04

标签: c# geometry

给出一个在3D空间中有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中实现此data filter technique

6 个答案:

答案 0 :(得分:5)

可能最简单的方法是计算绑定立方体的6个平面中的每个平面的平面方程,将点插入每个平面并确保结果符号为正(或者为负,取决于您是否计算你的飞机面向内或向外)。平面方程是p * normal + k = 0,通过取两个边之间的叉积来计算法线,然后将其中一个点插入平面方程中得到k。

更高级的方法是想象定义X,Y和Z轴的立方体和偏移(由立方体[0]定义)并将它们插入矩阵以转换两个空间之间的点。通过该矩阵的逆转换您的点将其置于“立方体空间”中,其中立方体与X / Y / Z轴对齐,因此您可以仅对边进行幅度比较。

答案 1 :(得分:5)

如果你想从链接的帖子中实现想法,那么考虑轴对齐的立方体(实际上是平行六面体)是有意义的。在这种情况下,支票为xmin<=x<=xmax && ymin<=y<=ymax && zmin<=z<=zmax

答案 2 :(得分:3)

特殊情况#1(轴对齐立方体)

maxim1000's answer所示,您可以简单地检查所考虑点的X,Y,Z坐标是否位于多维数据集的X,Y,Z坐标的最小值和最大值中。

X_min <= X <= X_max and Y_min <= Y <= Y_max  and Z_min <= Z <= Z_max

如果满足上述条件,则该点位于立方体内部,否则就不在立方体内。

常规案例(定向多维数据集)

有两种方法可以解决此问题。首先,将点引入立方体的局部坐标系并应用上述特殊情况。第二种情况是关于向量投影的概念。第一种情况比第二种情况稍微复杂一点,因为您需要计算旋转矩阵,该矩阵将点从世界坐标系转换为多维数据集的局部坐标系。考虑下图所示的多维数据集。

enter image description here

对于这两种方法,我们都需要从多维数据集表示中得出一些基本信息。让我们将原点固定在立方体左下角的立方体的局部坐标系中;在这种情况下,它是点D。现在,在三个维度上计算单位方向矢量,并计算这些方向上的立方体范围。可以按照以下步骤进行。

enter image description here

X local ,Y local 和Z local 在图中以蓝色,红色,绿色表示。和X length ,Y length 和Z length 是沿轴的范围。

现在让我们重新解决问题。

方法#1 :在Cube的局部坐标系中考虑这一点。为此,我们需要估算旋转矩阵。在这种情况下,旋转矩阵是3 x 3矩阵,其中X local ,Y local 和Z local 作为列。

enter image description here

使用旋转矩阵R,可以将点带入局部坐标系,然后应用轴对齐立方体的特殊情况。

方法2

构造从立方体中心到所考虑点的方向向量,并将其投影到每个局部轴上,并检查投影是否沿该轴超出了立方体的范围。如果投影在沿每个轴的范围内,则点在内部,否则在立方体的外部。

enter image description here

立方体的中心是I,如图所示。从立方体中心到点P的方向向量为V。向量V在X local ,Y local 和Z local 的计算公式如下。

enter image description here

现在,仅当满足以下所有条件时,点P才在立方体内。

enter image description here

这是方法2中的python快速实现。

import numpy as np

def inside_test(points , cube3d):
    """
    cube3d  =  numpy array of the shape (8,3) with coordinates in the clockwise order. first the bottom plane is considered then the top one.
    points = array of points with shape (N, 3).

    Returns the indices of the points array which are outside the cube3d
    """
    b1,b2,b3,b4,t1,t2,t3,t4 = cube3d

    dir1 = (t1-b1)
    size1 = np.linalg.norm(dir1)
    dir1 = dir1 / size1

    dir2 = (b2-b1)
    size2 = np.linalg.norm(dir2)
    dir2 = dir2 / size2

    dir3 = (b4-b1)
    size3 = np.linalg.norm(dir3)
    dir3 = dir3 / size3

    cube3d_center = (b1 + t3)/2.0

    dir_vec = points - cube3d_center

    res1 = np.where( (np.absolute(np.dot(dir_vec, dir1)) * 2) > size1 )[0]
    res2 = np.where( (np.absolute(np.dot(dir_vec, dir2)) * 2) > size2 )[0]
    res3 = np.where( (np.absolute(np.dot(dir_vec, dir3)) * 2) > size3 )[0]

    return list( set().union(res1, res2, res3) )

答案 3 :(得分:0)

1。从立方体的四个对角线中选择任意一个

2。检查你的点是否在对角点范围内。

例子。你选择了具有开始(0,9,1)和结束(10,3,-1)的对角线

So for P1(5,6,0) 
P.x (5) > Start.x(0) & P.x(5) < End.x(10)  
P.y (6) < Start.x(9) & P.y(6) > End.x(3)  
P.z (0) < Start.x(1) & P.z(0) > End.x(-1)

P1 is inside

for P2(5,6,6)
P.x (5) > Start.x(0) & P.x(5) < End.x(10)  
P.y (6) < Start.x(9) & P.y(6) > End.x(3)  
P.z (6) > Start.x(1) & P.z(6) > End.x(-1) <-- Not Within Range

P2 is out side

答案 4 :(得分:0)

这是我用来解决类似问题的算法,其中我的立方体未与3d空间的轴对齐。它可能不是最快的选择,但它有效。

  1. 选择 a b c d ,以便 a 将是您的多维数据集的来源,并且 b c d 将形成多维数据集的轴( a < / strong>和 b 通过边连接, a c 相同, a d )。它不必与3D空间的轴对齐。
  2. 使用以下公式计算多维数据集的 edgeLength (例如,从 a b 的距离):

    distance = sqrt(sqr(a.X - b.X) + (a.Y - b.Y) + (a.Z - b.Z))
    
  3. 确定点是否在多维数据集内

    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;
    

    计算angless(以度为单位)的公式:

    double CalculateAngleA(double latA, double latB, double latC)
    {
        return Math.Acos((latA*latA + latC*latC - latB*latB)/(2*latA*latC))*(180.0/Math.PI);
    }
    

答案 5 :(得分:0)

1)确定每个面(F1,F2,...)的平面方程(ax + by + cz + d = 0)

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

n1 =(n1x,n1y,n1z)

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

n1x Px + n1y Py + 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 = n1x v1x + n1y v1y + n1z * v1z

2)使用平面函数方法relativePosition(Vector3f p),以测试点坐标F1(Px,Py,Pz),F2(Px,Py, Pz)等...

2.2)如果所有结果F1(P),F2(P),...均为负,则该点为对象的INSIDE,否则为OUT或ON。或者,如果某些结果是肯定的,则说明是OUT。

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