找到相交线之间的所有四边形?

时间:2015-08-28 16:11:18

标签: php bash imagemagick linear-algebra rectangles

如何找到几条相交线之间的所有四边形?只有条件是四边形的每一边都是一条线。

我找到了this理论解释,但没有找到它的代码。

到目前为止,我几乎都在开始。我有我的线(每条线两个x,y点)并找到它们的所有交点(x,y点)。如果您对该脚本感兴趣,请参阅here

到目前为止,我的脚本基于php,但我很感谢任何建议,也使用其他语言。

实施例

这里有一组行。

line 715.341 0 757.297 600, 
line 0 249.169 800 179.178, 
line 0 256.196 800 186.205, 
line 0 284.225 800 200.142, 
line 396.716 0 481.041 600, 
line 0 311.374 800 227.29, 
line 0 355.76 800 229.053, 
line 0 521.525 800 437.442, 
line 696.134 0 611.809 600

在我的例子中,交叉点将是以下。每个点都有一个数字,x和y坐标以及两行ID。

 Point 1. 728.309, 185.45, 0, 1
 Point 2. 728.797, 192.434, 0, 2
 Point 3. 729.852, 207.515, 0, 3
 Point 4. 731.736, 234.465, 0, 5
 Point 5. 732.11, 239.806, 0, 6
 Point 6. 746.324, 443.084, 0, 7
 Point 7. 426.491, 211.856, 1, 4
 Point 8. 669.346, 190.609, 1, 8
 Point 9. 427.466, 218.798, 2, 4
 Point 10. 668.346, 197.723, 2, 8
 Point 11. 430.305, 238.998, 3, 4
 Point 12. 666.027, 214.223, 3, 8
 Point 13. 434.065, 265.752, 4, 5
 Point 14. 436.988, 286.548, 4, 6
 Point 15. 463.17, 472.844, 4, 7
 Point 16. 662.154, 241.778, 5, 8
 Point 17. 660.845, 251.093, 6, 8
 Point 18. 632.176, 455.081, 7, 8
convert -size 800x600 xc:skyblue \
    -fill red -stroke red -strokewidth 2 \
    -draw "line 715.341 0 757.297 600, line 0 249.169 800 179.178, line 0 256.196 800 186.205, line 0 284.225 800 200.142, line 396.716 0 481.041 600, line 0 311.374 800 227.29, line 0 355.76 800 229.053, line 0 521.525 800 437.442, line 696.134 0 611.809 600" \
    -font Courier -pointsize 14 -draw "fill none stroke blue circle 728.309,185.45 726.309,183.45 circle 728.797,192.434 726.797,190.434 circle 729.852,207.515 727.852,205.515 circle 731.736,234.465 729.736,232.465 circle 732.11,239.806 730.11,237.806 circle 746.324,443.084 744.324,441.084 circle 426.491,211.856 424.491,209.856 circle 669.346,190.609 667.346,188.609 circle 427.466,218.798 425.466,216.798 circle 668.346,197.723 666.346,195.723 circle 430.305,238.998 428.305,236.998 circle 666.027,214.223 664.027,212.223 circle 434.065,265.752 432.065,263.752 circle 436.988,286.548 434.988,284.548 circle 463.17,472.844 461.17,470.844 circle 662.154,241.778 660.154,239.778 circle 660.845,251.093 658.845,249.093 circle 632.176,455.081 630.176,453.081" \
    -draw "fill blue stroke blue text 738.309,190.45 '1' text 738.797,197.434 '2' text 739.852,212.515 '3' text 741.736,239.465 '4' text 742.11,244.806 '5' text 756.324,448.084 '6' text 436.491,216.856 '7' text 679.346,195.609 '8' text 437.466,223.798 '9' text 678.346,202.723 '10' text 440.305,243.998 '11' text 676.027,219.223 '12' text 444.065,270.752 '13' text 446.988,291.548 '14' text 473.17,477.844 '15' text 672.154,246.778 '16' text 670.845,256.093 '17' text 642.176,460.081 '18'" \
    lines-intersection.jpg

intersection points of lines

所以现在最大的问题是,我如何利用这些信息找到每一边是一行的点之间的所有四边形...

我正在寻找的四边形之一是第13,4,6和15点:

quadrilateral between point 13, 4, 6 and 15

2 个答案:

答案 0 :(得分:2)

我建议以这种方式解决问题:

  1. 在问题集中找到基本的四边形
  2. 找出这些基本四边形中的共同边缘
  3. 生成允许组合的列表或矩阵以显示所有可能的四边形
  4. 找到基本的四边形: 我建议首先使用Voronoi / Delaunay过程来查找Voronoi图。

    如果您不熟悉(或其他人遇到此问题但不是),您提出的是一组线条中的一组图形点(和连接边缘)。 Voronoi图定义了一组与最近的当前点等距的点 - 基本上,您将找到封闭区域的中心,加上一些额外的。 (Wikipedia更详细解释)。

    您所需的封闭区域(矩形,三角形等)由Voronoi点的子集标识,您可以执行其他测试以编程方式查找该子集。从您的示例中,您可能想要或不想丢弃生成的三角形;如果你这样做,那么一旦你确定了封闭区域,你就可以计算周围的边/面。

    我不是PHP专家,但我的Google-fu在GitHub显示了PHP实现。我自己的研究工作是图形结构和机器人技术,这种用法经常出现。

    Voronoi图的一种解释是新点基于“最近邻居” - 每个点位于由原始点创建的固定或无限多边形内。

    如果您正在寻找四边形,那么找到每个Voronoi点最近的4个点。如果有一组边直接连接4个点(pt1-pt2-pt3-pt4-pt1),则位于四边形内。如果没有,那么你是在另一个形状内或在导致无穷大的外部区域之一。

    (这是大锤的方法,正如我的旧航空航天教练所说的那样。我确信有更优雅的解决方案,但是我已经涵盖了对形状进行分类。如果我发现 - 或有人建议 - - 更好的答案,我会更新。)

    找出这些基本四边形中的共同边缘   对于“堆叠”四边形,如更新后的问题所示,您可以在基本四边形中找到共同边,然后生成组合列表。例如,如果四边形A具有四边形B的公共边,那么您将生成更大的四边形四边形AB。

    生成允许组合的列表或矩阵之后,您可能需要重新测试,直到所有可能的组合都用完为止。你需要测试的一件事是附加的形状仍然是一个四边形 - 如果你向上或向左添加一行,你会得到一个不再有效的“L”型形状。

    不漂亮或优雅,但可能有效。

答案 1 :(得分:1)

好的,我找到了一个解决方案。不幸的是,我无法使用 angus_thermophyale 推荐的Voronoi图表来解决这个问题。

我的想法是,使用这个事实,每个四边形必须具有360°的总和角度。

example quadrilateral

基本上我是按照以下方式做到的:

  1. 创建一个列表,其中包含链中4个交叉点的所有可能组合。
  2. 然后我justed使用两个点在一行上的每个组合。为了过滤这个,我使用了为每个点保存的行ID。
  3. 在点之间创建矢量并计算角度。每个角度必须大于0°且小于180°
  4. 将4个角度相加并检查它是否为360°
  5. 结果

    all possible quadrilaterals

    如果有人对代码详情感兴趣,请告诉我。