Geometry 如何用角度阈值快速识别单位矢量?

Geometry 如何用角度阈值快速识别单位矢量?,geometry,computational-geometry,Geometry,Computational Geometry,我正在写一个关于计算几何的程序 在这个程序中,我需要识别单位向量。(单词标识可能不准确) i、 例如,编写一个程序来检查单位向量是否已经存在 检查两个多边形是否在一个平面上时使用此步骤。第一步是检查两个多边形的法线是否非常接近(角度1)返回false; } 返回true; } 请注意,此方法没有提供任何定义“最大偏移角度”(如您问题中的1deg)的方法,而是让我们使用ε值,该值不是角度,而是简单的线性值。随着epsilon的增加,远离单位向量的向量会被接受,但是epsilon没有“角度”性质。

我正在写一个关于计算几何的程序

在这个程序中,我需要识别单位向量。(单词
标识
可能不准确)

i、 例如,编写一个程序来检查单位向量是否已经存在

检查两个多边形是否在一个平面上时使用此步骤。第一步是检查两个多边形的法线是否非常接近(角度<1.0度)

因此,我们可以假设

  • 所有向量都是单位向量
  • 向量是随机的
  • 例如,将角度阈值设置为1.0度。我们有6个向量

    (1,0,0)
    (0,1,0)
    (1,0,1e-8)  // in program, this will be normalized
    (1,0,0)
    (sin(45), cos(45),0)
    (sin(44.9), cos(44.9),0)
    
    然后,每个向量的索引是

    0 1 0 0 2 2
    
    i、 例如,第一个/第三个/第四个矢量是相同的,因为它们的角度在1.0度范围内或只是在同一方向上。第5/6个矢量之间的角度小于1.0度

    现在,问题来了,我有几十万个单位向量要在不同阶段识别。这个过程大约花费了总时间的一半

    示例代码

    std::vector unitVecs;//所有单位向量
    //实际情况下超过100000个单位向量
    int getVectorID(const Vector3d和vec)
    {
    
    对于(int i=0;i如果你能够接受仅仅“非常接近单位向量”的向量,而不是严格小于或等于单位向量1度的向量,你可以简单地检查给定向量的3个值非常接近0,一个值非常接近1:

    int valueCloseTo(float value, float trg, float epsilon=0.0001) {
      return abs(value) - trg <= epsilon;
    }
    int isRoughlyUnitVector(float x, float y, float z, float epsilon=0.0001) {
      
      // We can quickly return false if units don't add near 1
      // Could also consider multiplying `epsilon` x 3 here to account for accumulated error
      if (!valueCloseTo(x + y + z, 1, epsilon)) return false;
      
      // Now ensure that of x, y, and z, two are ~0 and one is ~1
      int numZero = 0;
      int numOne = 0;
      std::vector<float> vec{ x, y, z };
      for (float v : vec) {
        
        // Count another ~0 value
        if (valueCloseTo(v, 0, epsilon))      numZero++;
        
        // Count another ~1 value
        else if (valueCloseTo(v, 1, epsilon)) numOne++;
        
        // If any value isn't close to 0 or 1, (x,y,z) is not a unit vector
        else                                  return false;
        
        // False if we exceed 2 values near 0, and one value near 1
        if (numZero > 2 || numOne > 1) return false;
      }
    
      return true;
    }
    
    int valueCloseTo(浮点值、浮点训练、浮点ε=0.0001){
    返回abs(值)-trg2 | | numOne>1)返回false;
    }
    返回true;
    }
    

    请注意,此方法没有提供任何定义“最大偏移角度”(如您问题中的1deg)的方法,而是让我们使用
    ε
    值,该值不是角度,而是简单的线性值。随着
    epsilon
    的增加,远离单位向量的向量会被接受,但是
    epsilon
    没有“角度”性质。

    如果你能够接受仅仅“非常接近单位向量”的向量,与严格小于或等于单位向量1度的向量相反,您只需检查给定向量的3个值是否非常接近0,一个值是否非常接近1:

    int valueCloseTo(float value, float trg, float epsilon=0.0001) {
      return abs(value) - trg <= epsilon;
    }
    int isRoughlyUnitVector(float x, float y, float z, float epsilon=0.0001) {
      
      // We can quickly return false if units don't add near 1
      // Could also consider multiplying `epsilon` x 3 here to account for accumulated error
      if (!valueCloseTo(x + y + z, 1, epsilon)) return false;
      
      // Now ensure that of x, y, and z, two are ~0 and one is ~1
      int numZero = 0;
      int numOne = 0;
      std::vector<float> vec{ x, y, z };
      for (float v : vec) {
        
        // Count another ~0 value
        if (valueCloseTo(v, 0, epsilon))      numZero++;
        
        // Count another ~1 value
        else if (valueCloseTo(v, 1, epsilon)) numOne++;
        
        // If any value isn't close to 0 or 1, (x,y,z) is not a unit vector
        else                                  return false;
        
        // False if we exceed 2 values near 0, and one value near 1
        if (numZero > 2 || numOne > 1) return false;
      }
    
      return true;
    }
    
    int valueCloseTo(浮点值、浮点训练、浮点ε=0.0001){
    返回abs(值)-trg2 | | numOne>1)返回false;
    }
    返回true;
    }
    

    请注意,此方法没有提供任何定义“最大偏移角度”(如您问题中的1deg)的方法,而是让我们使用
    ε
    值,该值不是角度,而是简单的线性值。随着
    epsilon
    的增加,距离单位向量更远的向量会被接受,但是
    epsilon
    没有“角度”性质。

    calcAngle
    大概是通过点积、归一化和计算
    acos
    来工作的?因为余弦是一个递减函数,你可以将标准化点积与1度的余弦进行比较,你只需要计算一次,节省了每次迭代时昂贵的
    acos
    。我在程序中这样做了,但有几十万个单位向量,这个过程仍然需要花费大量的时间。你能负担得起检查给定向量是否“大致非常接近单位向量”,而不是精确地在单位向量的1度以内吗?因为在这种情况下,您只需检查向量中的一个值是否较大,3是否非常小—计算非常简单!我用“1度以内”更新了我的问题。但很抱歉我不明白你的意思。给定一个单位向量,我如何知道不迭代所有向量的哪一个?也考虑某种类型的二进制空间划分。例如-单位球体被三角形网格分割。每个向量都指向某个单元格,每个单元格都存储属于它的向量列表。
    calcAngle
    大概是通过取点积、标准化和计算
    acos
    来工作的?因为余弦是一个递减函数,你可以将标准化点积与1度的余弦进行比较,你只需要计算一次,节省了每次迭代时昂贵的
    acos
    。我在程序中这样做了,但有几十万个单位向量,这个过程仍然需要花费大量的时间。你能负担得起检查给定向量是否“大致非常接近单位向量”,而不是精确地在单位向量的1度以内吗?因为在这种情况下,您只需检查向量中的一个值是否较大,3是否非常小—计算非常简单!我用“1度以内”更新了我的问题。但很抱歉我不明白你的意思。给定一个单位向量,我如何知道不迭代所有向量的哪一个?也考虑某种类型的二进制空间划分。例如-单位球体被三角形网格分割。每个向量都指向某个单元格,每个单元格都存储属于它的向量列表。谢谢您的回复。但是对于向量(sin(45),cos(45),0)和(sin(44.9),cos(44.9),0),这不起作用。请原谅,我的代码没有经过测试(有一些明显的错误和一些javascript偷偷进入我的cpp)。你能用更新的代码再试一次吗?现在100%有效了。谢谢你,格肖姆。该代码适用于单位X/Y/Z向量。但不适用于所有其他单位向量。我的问题可能会误导您,所以我更新了测试用例。谢谢您的回复。但是对于向量(sin(45),cos(45),0)和(sin(44.9),cos(44.9),0),这不起作用。请原谅,我的代码没有经过测试(有一些明显的错误和一些javascript偷偷进入我的cpp)。你能用更新的代码再试一次吗?现在100%有效了。谢谢你,格肖姆。该代码适用于单位X/Y/Z向量。但不适用于所有其他单位向量。我的问题可能会误导你