在一组坐标中找到一个正方形

时间:2014-08-19 03:43:05

标签: c++ c geometry coordinates angle

好的,我在寻找解决方案方面遇到了一些麻烦,这似乎是一个简单的几何问题。

我有一个形成方角的三重坐标列表。

在所有这些三重坐标之间,我想找到一对形成正方形的对象。

我相信我能做的最好的例证就是展示一张图片:

Some triple-coordinates in the space

  1. 和2.无关紧要。 3.和4.是我正在寻找的。

    对于每个三重坐标,我有中间点,角度在哪里,另外两个点描述形成角度的两个分段。

    总结一下,给出6个点,2个对角线+ 4个其他点,我怎样才能找到这些是否为正方形?

    obs:制作角度的两条线是一致的但不具有相同的尺寸。

    obs2:来自不同三元组的线可能不相交

    感谢您抽出时间,提供任何帮助和见解。

    如果我使用的任何术语不正确或者只是很难理解,请告诉我,我不是母语为英语的人。

    编辑:现有代码。

    //for all triples
    for (size_t i = 0; i < toTry.size() - 1; i++) {
    
                Vec2i center_i = toTry[i].avg;
                //NormalizedDiagonal = ((Side1 - Center) + (Side2 - Center)); 
                Vec2i a = toTry[i].p, b = toTry[i].q;
                Vec2f normalized_i = normalizedDiagonal(center_i, toTry[i].p, toTry[i].q);
    
                for (size_t j = i + 1; j < toTry.size(); j++) {
    
                    Vec2i center_j = toTry[j].avg;
                    //Se os pontos sao proximos, nao importam
                    if (areClose(center_i, center_j, 25))
                        continue;
    
                    Vec2f normalized_j = normalizedDiagonal(center_j, toTry[j].p, toTry[j].q);
                    line(src, Point(center_i[0], center_i[1]), Point(center_i[0] + 1 * normalized_i[0], center_i[1] + 1 * normalized_i[1]), Scalar(255, 255, 255), 1);
    
                    //test if antiparallel
                    if (abs(normalized_i[0] - normalized_j[0]) > 0.1 || abs(normalized_i[1] - normalized_j[1] > 0.1))
                        continue;
    
                    Vec2f delta;
                    delta[0] = center_j[0] - center_i[0]; delta[1] = center_j[1] - center_i[1];
                    double dd = sqrt(pow((center_i[0] - center_j[0]), 2) + pow((center_i[1] - center_j[1]), 2));
                    //delta[0] = delta[0] / dd;
                    //delta[1] = delta[1] / dd;
    
                    float dotProduct = normalized_i[0] * delta[0] + normalized_i[1] * delta[1];
    
                    //test if do product < 0
                    if (dotProduct < 0)
                        continue;
    
                    float deltaDotDiagonal = delta[0] * normalized_i[0] + delta[1] * normalized_i[1];
                    menor_d[0] = delta[0] - deltaDotDiagonal * normalized_i[0];
                    menor_d[1] = delta[1] - deltaDotDiagonal * normalized_i[1];
                    dd = sqrt(pow((center_j[0] - menor_d[0]), 2) + pow((center_j[1] - menor_d[1]), 2));
    
                    if(dd < 25)
                       [...]
    

3 个答案:

答案 0 :(得分:1)

解决这个问题有两种方法。一种是非常直接的方法,涉及找到两行段的交集。

您只需使用三坐标来计算中点,以及从中突出的两个线段(平凡)。对两个三组都这样做。

现在计算延伸线段的所有四种可能排列的交叉点(如果存在)。从最初的答案到类似的问题:

  

您可以查看我为Computational Geometry in C编写的代码,   它详细讨论了这个问题(第1章,第5节)。该   代码可以从该网站的链接以SegSegInt的形式获得。

     

简而言之,我建议采用不同的方法,使用签名区域   三角形。然后比较适当的三点,一个可以   区分正确的交叉点和所有退化的交叉点   案例。一旦他们被区分,找到交叉点   很容易。

另一种图像处理方法是渲染线条,为线条定义一种独特的颜色,然后将种子/填充填充算法应用于找到的第一个白色区域,将新的独特颜色应用于未来区域,直到你填充一个没有触及图像边界的封闭区域。

祝你好运!

<强>参考


  1. 在2d中找到两个线段的交集(具有潜在的退化),访问2014-08-18,<https://math.stackexchange.com/questions/276735/finding-the-intersection-of-two-line-segments-in-2d-with-potential-degeneracies>

答案 1 :(得分:1)

  1. 在一对段中,调用一个“基本段”,通过逆时针旋转基段π/ 2获得的一个是“另一个段”。
  2. 对于每个三元组,计算基线段和X轴之间的角度。称之为主角。
  3. 按主角排序三元组。
  4. 现在对于主角为α的每个三元组,任何可能的方形成形配合都具有α+π(mod2π)的主角。通过二分查找很容易找到。
  5. 此外,对于顶点 a a'以及主角α和α+π的两个候选三元组,矢量 aa'应为α+π/ 4。
  6. 最后,如果这四个段中的每一段至少是| aa'| /√2长,我们就有一个正方形。

答案 2 :(得分:1)

为了清楚起见,侧段的实际长度是无关紧要的,对吧?你关心的是两个三元组的侧段形成的半无限线是否形成一个正方形?或者实际的片段是否需要交叉?

假设前者,检查两个三元组是否形成正方形的方法如下。让我们使用Point3D命名空间中的Vector3DSystem.Windows.Media.Media3D来定义一些术语,因为它们是支持基本线性代数方法的通用3d双精度点和向量。这些是c#所以你不能直接使用它们,但我希望能够参考那里提到的一些基本方法。

以下是检查两个三元组是否相交的基本方法:

  1. 按如下方式定义三元组:Center,Side1和Side2为三个Point3D结构。

  2. 对于每个三元组,将标准化对角线矢量定义为

    NormalizedDiagonal = ((Side1 - Center) + (Side2 - Center)); NormalizedDiagonal.Normalize()

    (您可能希望将其缓存以提高性能。)

  3. 检查两个中心在您定义的某个线性容差范围内是否相等。如果相等,则返回false - 这是一个退化的情况。

  4. 检查两个对角线矢量是否在您定义的某个角度公差范围内反平行。 (即NormalizedDiagonal1 == -NormalizedDiagonal2有一定宽容。)如果没有,则返回false,而不是正方形。

  5. 计算从triple2.Center到triple2.Center的向量:delta = triple2.Center - triple1.Center

  6. 如果double deltaDotDiagonal = DotProduct(delta, triple1.NormalizedDiagonal) < 0,则返回false - 两个三元组相互指远。

  7. 最后,计算从triple2的中心到穿过中心triple1的(无限)对角线的距离。如果为零(在线性公差范围内),则它们形成一个正方形。

    计算该距离:distance = (delta - deltaDotDiagonal*triple1.NormalizedDiagonal).Length

    注意:deltaDotDiagonal*triple1.NormalizedDiagonaldelta向量到triple1.NormalizedDiagonal的投影,因此delta - deltaDotDiagonal*triple1.NormalizedDiagonaldelta的垂直于该对角线的组件。它的长度是我们寻求的距离。

  8. 最后,如果你对方形的定义要求实际的侧面段相交,你可以额外检查所有侧面段的长度是否小于sqrt(2) * delta.Length

    enter image description here

    此方法检查两个三元组是否形成正方形。找到形成正方形的所有三元组当然是O(N平方)。如果这是一个问题,您可以将它们放在一个数组中,然后按angle = Atan2(NormalizedDiagonal.Y, NormalizedDiagonal.X)进行排序。完成后,您可以在角度公差范围内找到可能形成具有给定三元组的正方形的三元组,通过二进制搜索数组,从当前三元组的角度使用角度= +/-π进行三元组搜索。 (当角度接近π时,您需要检查数组的开头和结尾。)

    <强>更新

    好的,让我们看看我是否可以在课堂上做这件事。我没有Vec2iVec2f的定义,所以我可能会弄错...

    double getLength(Vec2f vector)
    {
        return sqrt(pow(vector[0], 2) + pow(vector[1], 2));
    }
    
    Vec2f scaleVector(Vec2f vec, float scale)
    {
        Vec2f scaled;
        scaled[0] = vec[0] * scale;
        scaled[1] = vec[1] * scale;
        return scaled;
    }
    
    Vec2f subtractVectorsAsFloat(Vec2i first, Vec2i second)
    {
        // return first - second as float.
        Vec2f diff;
        diff[0] = first[0] - second[0];
        diff[1] = first[1] - second[1];
        return diff;
    }
    
    Vec2f subtractVectorsAsFloat(Vec2f first, Vec2f second)
    {
        // return first - second as float.
        Vec2f diff;
        diff[0] = first[0] - second[0];
        diff[1] = first[1] - second[1];
        return diff;
    }
    
    double dot(Vec2f first, Vec2f second)
    {
        return first[0] * second[0] + first[1] * second[1];
    }
    
    //for all triples
    for (size_t i = 0; i < toTry.size() - 1; i++) {
    
            Vec2i center_i = toTry[i].avg;
            //NormalizedDiagonal = ((Side1 - Center) + (Side2 - Center)); 
            Vec2i a = toTry[i].p, b = toTry[i].q;
            Vec2f normalized_i = normalizedDiagonal(center_i, toTry[i].p, toTry[i].q);
    
            for (size_t j = i + 1; j < toTry.size(); j++) {
    
                Vec2i center_j = toTry[j].avg;
                //Se os pontos sao proximos, nao importam
                if (areClose(center_i, center_j, 25))
                    continue;
    
                Vec2f normalized_j = normalizedDiagonal(center_j, toTry[j].p, toTry[j].q);
    
                //test if antiparallel
                if (abs(normalized_i[0] - normalized_j[0]) > 0.1 || abs(normalized_i[1] - normalized_j[1] > 0.1))
                    continue;
    
                // get a vector pointing from center_i to center_j.
                Vec2f delta = subtractVectorsAsFloat(center_j, center_i);
    
                //test if do product < 0
                float deltaDotDiagonal = dot(delta, normalized_i);
                if (deltaDotDiagonal < 0)
                    continue;
    
                Vec2f deltaProjectedOntoDiagonal = scaleVector(normalized_i, deltaDotDiagonal);
    
                // Subtracting the dot product of delta projected onto normalized_i will leave the component
                // of delta which is perpendicular to normalized_i...
                Vec2f distanceVec = subtractVectorsAsFloat(deltaProjectedOntoDiagonal, center_j);
    
                // ... the length of which is the distance from center_j 
                // to the diagonal through center_i.
                double distance = getLength(distanceVec);
    
                if(distance < 25) {
                }
            }