明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 3465|回复: 11

[其它] 多边形Ploygon并集轮廓线 算法实现

  [复制链接]
发表于 2023-2-12 14:36:40 | 显示全部楼层 |阅读模式
本帖最后由 landsat99 于 2023-2-15 20:57 编辑

n个多边形随机放置,每个多边形边数(m>=3)。

条件:已知每个多边形 顶点有序坐标集。
算法实现:n个多边形的并集轮廓线,并消除 集内孤岛区域。





// ------------------------------------------------------------------
// 2023.02.15  修改
// ------------------------------------------------------------------




    基本实现。尚在不定期更新中:  PloyContour (landsat99.github.io)
    原创代码,未参考其它几何算法集。
    欢迎大家提供 测试数据。

  1. import operator
  2. from copy import deepcopy
  3. import matplotlib.pyplot as plt
  4. from PloyData_1 import *


  5. def XYMaxPoint(PList):
  6.     Xmax = max(i[0] for i in PList)
  7.     Xlist = []
  8.     for poi in PList:
  9.         if poi[0] == Xmax:
  10.             Xlist.append(poi)
  11.     Ymax = max(i[1] for i in Xlist)
  12.     for i in PList:
  13.         if i[0] == Xmax and i[1] == Ymax:
  14.             return i


  15. def RegulaPloy(ploy):
  16.     # x极值点 正则判断的需要
  17.     Xmax = max([i[0] for i in ploy])
  18.     for id, item in enumerate(ploy):
  19.         if item[0] == Xmax:
  20.             Num = id
  21.             break
  22.     # 两侧延长数据
  23.     tempPloy = ploy.copy()
  24.     tempPloy.append(ploy[0])
  25.     tempPloy.insert(0, ploy[len(ploy) - 1])
  26.     # 顶点正则判断
  27.     [x1, y1] = tempPloy[Num]
  28.     [x2, y2] = tempPloy[Num + 1]
  29.     [x3, y3] = tempPloy[Num + 2]
  30.     Wise = (x3 - x2) * (y1 - y2) - (x1 - x2) * (y3 - y2)
  31.     if Wise < 0:
  32.         ploy.reverse()
  33.     return ploy



  34. def IsCross(line1, line2):
  35.     [[Ax1, Ay1], [Ax2, Ay2]] = line1
  36.     [[Bx1, By1], [Bx2, By2]] = line2
  37.     m1 = (Bx1 - Ax1) * (Ay2 - Ay1) - (Ax2 - Ax1) * (By1 - Ay1)  # line1 2-sides
  38.     m2 = (Bx2 - Ax1) * (Ay2 - Ay1) - (Ax2 - Ax1) * (By2 - Ay1)
  39.     k1 = (Ax1 - Bx1) * (By2 - By1) - (Bx2 - Bx1) * (Ay1 - By1)  # line2 2-sides
  40.     k2 = (Ax2 - Bx1) * (By2 - By1) - (Bx2 - Bx1) * (Ay2 - By1)
  41.     return m1 * m2 <= 0 and k1 * k2 <= 0


  42. def CrossPoi(line1, line2):
  43.     [[Ax1, Ay1], [Ax2, Ay2]] = line1
  44.     [[Bx1, By1], [Bx2, By2]] = line2
  45.     Left = (Bx2 - Bx1) * (Ay1 - Ay2) - (Ax2 - Ax1) * (By1 - By2)
  46.     Right = (Ay1 - By1) * (Ax2 - Ax1) * (Bx2 - Bx1) + Bx1 * \
  47.         (By2 - By1) * (Ax2 - Ax1) - Ax1 * (Ay2 - Ay1) * (Bx2 - Bx1)
  48.     x = Right / Left

  49.     Left = (Ax1 - Ax2) * (By2 - By1) - (Ay2 - Ay1) * (Bx1 - Bx2)
  50.     Right = Ay2 * (Ax1 - Ax2) * (By2 - By1) + (Bx2 - Ax2) * \
  51.         (By2 - By1) * (Ay1 - Ay2) - By2 * (Bx1 - Bx2) * (Ay2 - Ay1)
  52.     y = Right / Left
  53.     return [x, y]


  54. def Dis(p1, p2):
  55.     return (p2[0] - p1[0])**2 + (p2[1] - p1[1])**2


  56. def RouteSec(XYRpoi, StartPoi):
  57.     T = 0
  58.     # print(XYRpoi)
  59.     ployName = XYRpoi[2]
  60.     for poi in Data[ployName]:
  61.         if T == 1:
  62.             if poi[0] == StartPoi[0] and poi[1] == StartPoi[1]:
  63.                 print("轮廓线 绘制完毕!")
  64.                 return "OK"
  65.             if len(poi) == 2:
  66.                 ContourLine.append([poi[0], poi[1]])
  67.             if len(poi) > 2:
  68.                 T = 0
  69.                 if poi[2] == ployName:
  70.                     nextName = poi[4]
  71.                 elif poi[4] == ployName:
  72.                     nextName = poi[2]
  73.                 else:
  74.                     print("Error: 交叉点路由信息错误。[From:轮廓线生成函数 RouteSec]")
  75.                 return [poi[0], poi[1], nextName]
  76.         if poi[0] == XYRpoi[0] and poi[1] == XYRpoi[1]:  # 注意 浮点精度问题
  77.             ContourLine.append([poi[0], poi[1]])
  78.             T = 1


  79. def plot2D():
  80.     for ploy in Data.values():
  81.         x = [i[0] for i in ploy]
  82.         y = [i[1] for i in ploy]
  83.         x.append(x[0])
  84.         y.append(y[0])
  85.         plt.scatter(x, y)
  86.         plt.plot(x, y)
  87.     x = [i[0] for i in ContourLine]
  88.     y = [i[1] for i in ContourLine]
  89.     x.append(x[0])
  90.     y.append(y[0])
  91.     plt.scatter(x, y)
  92.     plt.plot(x, y, lw=6, color='navy')
  93.     plt.show()


  94. if __name__ == "__main__":
  95.     for val in Data.values():
  96.         val = RegulaPloy(val)
  97.     PlotData = deepcopy(Data)

  98.     PloyPair = []
  99.     KList = [i for i in Data.keys()]
  100.     for i in range(len(KList)):
  101.         for j in range(i + 1, len(KList)):
  102.             PloyPair.append([KList, KList[j]])

  103.     AllCrossP = []
  104.     for pair in PloyPair:
  105.         for id, Aline in enumerate(SidePloy(Data[pair[0]])):
  106.             for jd, Bline in enumerate(SidePloy(Data[pair[1]])):
  107.                 if IsCross(Aline, Bline):
  108.                     xy = CrossPoi(Aline, Bline)
  109.                     info = [pair[0], id, pair[1], jd]
  110.                     xy.extend(info)
  111.                     AllCrossP.append(xy)

  112.     for name, ploy in Data.items():
  113.         for i in range(len(ploy) - 1, -1, -1):
  114.             insPoiList = IndexCrossPoi(name, ploy, i, AllCrossP)
  115.             if insPoiList != []:
  116.                 insPoiList.reverse()
  117.                 for j in insPoiList:
  118.                     ploy.insert(i + 1, j)

  119.     for key, val in Data.items():
  120.         Data[key] = Data[key] * 2

  121.     AllployPoi = []
  122.     for name, val in PlotData.items():
  123.         for i in val:
  124.             i.append(name)
  125.             AllployPoi.append(i)
  126.     StartPoi = XYMaxPoint(AllployPoi)
  127.     Poi_A = StartPoi
  128.     Poi_B = []

  129.     # 生成轮廓线
  130.     ContourLine = []
  131.     while Poi_B != "OK":
  132.         Poi_B = RouteSec(Poi_A, StartPoi)
  133.         Poi_A = Poi_B

  134.     # 绘图
  135.     plot2D()


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 1明经币 +1 金钱 +15 收起 理由
qjchen + 1 + 15 赞一个!

查看全部评分

发表于 2023-2-12 15:32:30 | 显示全部楼层
AI的提出的方法
实现这个问题,可以使用扫描线算法。扫描线算法是一种计算几何算法,它通过维护扫描线上交点的次序,来计算几何图形的并集。
首先,将所有多边形的所有边按照x坐标从左到右排序,每次处理的时候选择x坐标最小的边,如果该边的两个端点在扫描线的同一侧,则不处理,如果在不同侧,则加入交点,并在扫描线上删除该边。接下来,扫描线向右移动,并继续执行上述操作,直到所有边都被处理完。

最终得到的并集轮廓线就是所有交点按照x坐标从左到右排列的线段集合。可以使用深度优先搜索算法消除并集内的孤岛区域。

实现起来可能比较复杂,但是如果你有足够的编程经验和数学知识,应该能够实现。
 楼主| 发表于 2023-2-14 10:21:19 | 显示全部楼层
jun353835273 发表于 2023-2-12 15:32
AI的提出的方法
实现这个问题,可以使用扫描线算法。扫描线算法是一种计算几何算法,它通过维护扫描线上交 ...

感谢您的提示和建议。

准备用正则矢量法试试。目前预估算法上可行,近期找时间代码实现看看。届时核各位朋友交流.
 楼主| 发表于 2024-4-25 21:24:32 | 显示全部楼层
dcl1214 发表于 2023-8-14 21:31
CGAL有源码公布,建议您看看

嗯。谢谢。

此算法有别于Cgal的凸包,并没有参考cgal的 Convex Hulls算法。区别是,Cgal的 Extreme Points以及Convex Hulls采用了其他的航向模式,可生成3D凸包,舍弃了部分2D的效率
发表于 2023-2-14 21:24:07 | 显示全部楼层
可以用regon后union,得到的图形炸开后,然后用pe合并得到pline,扫描线法可以得到最近点外轮廓的方法,没有学会,请知道的大神指教,感谢。
 楼主| 发表于 2023-2-15 20:26:08 | 显示全部楼层
本帖最后由 landsat99 于 2023-2-15 20:38 编辑

// 2023.02.15  -- 问题首层 已更新

基本实现。不定期完善中。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
发表于 2023-2-16 22:51:27 来自手机 | 显示全部楼层
简单,全部求交点,打断,中点射线法判断
发表于 2023-4-21 13:48:23 | 显示全部楼层
可以参考点集(所有交点、顶点的数组)的最小凸包算法。
发表于 2023-4-21 13:49:34 | 显示全部楼层
这是什么语言的代码?
发表于 2023-4-21 17:05:54 | 显示全部楼层
chixun99 发表于 2023-4-21 13:49
这是什么语言的代码?

用的是Python
发表于 2023-4-29 07:04:38 来自手机 | 显示全部楼层
有一个不是算法快捷方法。外面画个大矩形,直接用bo快捷键,就生成轮廓线。但是bo需要内部图元少
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-11-25 05:36 , Processed in 0.192933 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表