明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 872|回复: 8

[其它] 正交点集-外轮廓线 算法实现

[复制链接]
发表于 2023-2-6 23:55 | 显示全部楼层 |阅读模式
本帖最后由 landsat99 于 2023-2-7 09:15 编辑

// 分布于正交栅格网的散点集合(允许有内部空洞),生成正交点集合的外轮廓线。


说明:
1.  此算法分区施加右手法则,贴合正交外轮廓。
2.  对任意散点的集合,外轮廓线不唯一。 需附加约束条件,比如面积最大、 轮廓线周长最大、最小等。
3.  Python演示算法及图形说明。
4.  此正交算法 为纯原创代码,未参考其它几何算法集。不严谨之处 多多交流指正。



  1. # RecVec_grid.py
  2. import matplotlib.pyplot as plt
  3. import GenList as Gen
  4. import MaxP as MP


  5. def Direc(UpDown, A, B):
  6.     alpha = 360 + 10
  7.     if UpDown == 1:  # 象限号
  8.         if B[1] == A[1] and B[0] > A[0]:
  9.             alpha = 0  #
  10.         elif B[1] == A[1] and B[0] < A[0]:
  11.             alpha = 180
  12.         elif B[0] == A[0] and B[1] > A[1]:
  13.             alpha = 90
  14.         elif B[0] == A[0] and B[1] < A[1]:
  15.             alpha = 270
  16.         else:
  17.             pass
  18.     if UpDown == 2:  # 象限号
  19.         if B[0] == A[0] and B[1] > A[1]:
  20.             alpha = 0
  21.         elif B[0] == A[0] and B[1] < A[1]:
  22.             alpha = 180
  23.         elif B[1] == A[1] and B[0] > A[0]:
  24.             alpha = 270
  25.         elif B[1] == A[1] and B[0] < A[0]:
  26.             alpha = 90
  27.         else:
  28.             pass
  29.     if UpDown == 3:  # 象限号
  30.         if B[1] == A[1] and B[0] < A[0]:
  31.             alpha = 0
  32.         elif B[1] == A[1] and B[0] > A[0]:
  33.             alpha = 180
  34.         elif B[0] == A[0] and B[1] < A[1]:
  35.             alpha = 90
  36.         elif B[0] == A[0] and B[1] > A[1]:
  37.             alpha = 270
  38.         else:
  39.             pass
  40.     if UpDown == 4:  # 象限号
  41.         if B[0] == A[0] and B[1] < A[1]:
  42.             alpha = 0
  43.         elif B[0] == A[0] and B[1] > A[1]:
  44.             alpha = 180
  45.         elif B[1] == A[1] and B[0] < A[0]:
  46.             alpha = 270
  47.         elif B[1] == A[1] and B[0] > A[0]:
  48.             alpha = 90
  49.         else:
  50.             pass
  51.     return alpha



  52. def Dist(A, B):
  53.     return (B[1] - A[1])**2 + (B[0] - A[0])**2


  54. def NextPoi(UpDown, Poi, PList):
  55.     Dire = 360 + 10
  56.     Unit = 1
  57.     for id, p in enumerate(PList):
  58.         if Direc(UpDown, Poi, p) <= Dire and Dist(Poi, p) == Unit:
  59.             Dire = Direc(UpDown, Poi, p)
  60.             dis = Dist(Poi, p)
  61.             Num = id
  62.     return PList[Num]


  63. def plot2D(x, y, x_out, y_out):
  64.     plt.scatter(x, y)  # 画散点图
  65.     plt.plot(x_out, y_out)  # 画连线图
  66.     plt.show()

  67. if __name__ == '__main__':
  68.     Points = Gen.GenList()
  69.     XMaxPoi, Num = MP.XMaxPoint(Points)
  70.     YMaxPoi, Num = MP.YMaxPoint(Points)
  71.     XMinPoi, Num = MP.XMinPoint(Points)
  72.     YMinPoi, Num = MP.YMinPoint(Points)
  73.     PPs = Points.copy()
  74.     PPs.remove(XMaxPoi)
  75.     Poi_A = XMaxPoi
  76.     RList = [XMaxPoi]
  77.     Poi_B = []
  78.     while Poi_B != YMaxPoi:
  79.         Poi_B = NextPoi(1, Poi_A, PPs)
  80.         RList.append(Poi_B)
  81.         PPs.remove(Poi_B)
  82.         Poi_A = Poi_B
  83.     Poi_A = YMaxPoi
  84.     Poi_B = []
  85.     while Poi_B != XMinPoi:
  86.         Poi_B = NextPoi(2, Poi_A, PPs)
  87.         RList.append(Poi_B)
  88.         PPs.remove(Poi_B)
  89.         Poi_A = Poi_B
  90.     Poi_A = XMinPoi
  91.     Poi_B = []
  92.     while Poi_B != YMinPoi:
  93.         Poi_B = NextPoi(3, Poi_A, PPs)
  94.         RList.append(Poi_B)
  95.         PPs.remove(Poi_B)
  96.         Poi_A = Poi_B
  97.     Poi_A = YMinPoi
  98.     Poi_B = []
  99.     PPs = [XMaxPoi] + PPs  # 加回第一点
  100.     while Poi_B != XMaxPoi:
  101.         Poi_B = NextPoi(4, Poi_A, PPs)
  102.         RList.append(Poi_B)
  103.         PPs.remove(Poi_B)
  104.         Poi_A = Poi_B
  105.     print(RList)

  106.     XList = [i[0] for i in Points]
  107.     YList = [i[1] for i in Points]
  108.     X_OutList = [i[0] for i in RList]
  109.     Y_OutList = [i[1] for i in RList]
  110.     plot2D(XList, YList, X_OutList, Y_OutList)


  1. # MaxP.py
  2. def XMaxPoint(PList):
  3.     Xmax = PList[0][0]
  4.     Ymax = PList[0][1]
  5.     for id, poi in enumerate(PList):
  6.         if poi[0] > Xmax:
  7.             Xmax = poi[0]
  8.             Ymax = poi[1]
  9.             Num = id
  10.         if poi[0] >= Xmax and poi[1] > Ymax:
  11.             Xmax = poi[0]
  12.             Num = id
  13.     return PList[Num], Num


  14. def YMaxPoint(PList):
  15.     Xmax = PList[0][0]
  16.     Ymax = PList[0][1]
  17.     for id, poi in enumerate(PList):
  18.         if poi[1] > Ymax:
  19.             Ymax = poi[1]
  20.             Xmax = poi[0]
  21.             Num = id
  22.         if poi[1] >= Ymax and poi[0] < Xmax:
  23.             Ymax = poi[1]
  24.             Num = id
  25.     return PList[Num], Num


  26. def XMinPoint(PList):
  27.     Xmin = PList[0][0]
  28.     Ymin = PList[0][1]
  29.     for id, poi in enumerate(PList):
  30.         if poi[0] < Xmin:
  31.             Xmin = poi[0]
  32.             Ymin = poi[1]
  33.             Num = id
  34.         if poi[0] <= Xmin and poi[1] < Ymin:
  35.             Xmin = poi[0]
  36.             Num = id
  37.     return PList[Num], Num


  38. def YMinPoint(PList):
  39.     Xmin = PList[0][0]
  40.     Ymin = PList[0][1]
  41.     for id, poi in enumerate(PList):
  42.         if poi[1] < Ymin:
  43.             Ymin = poi[1]
  44.             Xmin = poi[0]
  45.             Num = id
  46.         if poi[1] <= Ymin and poi[0] > Xmin:
  47.             Ymin = poi[1]
  48.             Num = id
  49.     return PList[Num], Num


  1. # GenList.py
  2. def GenList():
  3.     Points = []
  4.     for i in range(6, 9):
  5.         for j in range(14, 17):
  6.             Points.append([i, j])
  7.     for i in range(4, 12):
  8.         for j in range(12, 14):
  9.             Points.append([i, j])
  10.     for i in range(5, 10):
  11.         for j in range(10, 12):
  12.             Points.append([i, j])
  13.     for i in range(2, 13):
  14.         for j in range(6, 10):
  15.             Points.append([i, j])
  16.     for i in range(4, 13):
  17.         for j in range(4, 6):
  18.             Points.append([i, j])
  19.     for i in range(3, 8):
  20.         for j in range(0, 4):
  21.             Points.append([i, j])
  22.     for i in range(9, 12):
  23.         for j in range(2, 5):
  24.             Points.append([i, j])
  25.     return Points





本帖子中包含更多资源

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

x

评分

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

查看全部评分

 楼主| 发表于 2023-2-7 00:11 | 显示全部楼层
此算法的右手航向角 取为正交判断(针对正交栅格散点集合)。

对任意散点集合,需设定另外的约束条件。
发表于 2023-2-7 08:44 | 显示全部楼层
删掉的点都是以该点为中心八方向都有点的点。
 楼主| 发表于 2023-2-7 09:24 | 显示全部楼层
mahuan1279 发表于 2023-2-7 08:44
删掉的点都是以该点为中心八方向都有点的点。

您这个思路很棒!确实可以解决很多阴角歧点、回头线等问题。
目前我用的四分区的办法(集合4个极值分区)分别制定航向规则,来解决阴角歧点、回头线问题。

您的方案, 估计算法上会更佳。赞一个
发表于 2023-2-7 09:54 | 显示全部楼层
感觉题目定义可能会导致一些无解的情况
比如矩形格点只有3个点的情况,或者有单独几点伸出的情况,也可能如楼主说的,需要限制条件
https://karobben.github.io/2022/03/07/Python/point_outline/
此处也有一个类似的问题,用了α来限制
 楼主| 发表于 2023-2-7 11:27 | 显示全部楼层
本帖最后由 landsat99 于 2023-2-7 11:29 编辑
qjchen 发表于 2023-2-7 09:54
感觉题目定义可能会导致一些无解的情况
比如矩形格点只有3个点的情况,或者有单独几点伸出的情况,也可能 ...

同意您的观点。

对有单点的分支凸起,此算法会中断。单点凸起的轮廓线,是需要单独定义。

如果轮廓线定义为: 散点集合的最大面积轮廓线,则算法将会大大简化。
发表于 2023-2-7 15:34 | 显示全部楼层
landsat99 发表于 2023-2-7 11:27
同意您的观点。

对有单点的分支凸起,此算法会中断。单点凸起的轮廓线,是需要单独定义。

那不就是求凸包么?
 楼主| 发表于 2023-2-8 17:32 | 显示全部楼层
本帖最后由 landsat99 于 2023-2-8 17:38 编辑

是的。凸包算法将大为简化算法。即便手写算法,也无需分区制定规则。尤其Convex的成熟包很多,稳定 效率优秀。


Scipy的ConvexHull实例


  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from scipy.spatial import ConvexHull

  4. x = np.random.normal(0, 1, 100)
  5. y = np.random.normal(0, 1, 100)
  6. xy = np.hstack((x[:, np.newaxis], y[:, np.newaxis]))
  7. hull = ConvexHull(xy)
  8. plt.scatter(x, y)
  9. plt.plot(x[hull.vertices], y[hull.vertices])
  10. plt.plot(np.append(x[hull.vertices], x[hull.vertices][0]), np.append(y[hull.vertices], y[hull.vertices][0]))
  11. plt.show()






本帖子中包含更多资源

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

x
 楼主| 发表于 2023-2-14 10:09 | 显示全部楼层
本帖最后由 landsat99 于 2023-2-14 10:13 编辑

// 2023.02.14
  
改为正则矢量法,可得到较优方案。普式性、简洁性均较大改善。
点集/线集序列应用,在较多情况下 正则矢量法会优于航向角法。
改进过程 不定期更新中.  https://landsat99.github.io/GridContour.html

同时欢迎您提供 数据测试




  1. #
  2. # 不支持 “单线分支”的图形集合
  3. #
  4. import matplotlib.pyplot as plt
  5. import Data1 as Data

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

  14. def NextPoi(P, PList):
  15.     Unit = 1.0
  16.     Poi_B = []
  17.     TList = []
  18.     Grid_4 = [[P[0] + Unit, P[1]], [P[0] - Unit, P[1]],
  19.               [P[0], P[1] + Unit], [P[0], P[1] - Unit]]
  20.     for i in Grid_4:
  21.         if i in PList:
  22.             TList.append(i)
  23.     for A in TList:
  24.         k = 1
  25.         for B in TList:
  26.             Wise = (A[0] - P[0]) * (B[1] - P[1]) - \
  27.                 (A[1] - P[1]) * (B[0] - P[0])
  28.             if Wise < 0:
  29.                 k = 0
  30.         if k == 1:
  31.             Poi_B = A
  32.     return Poi_B

  33. def plot2D(x, y, x_out, y_out):
  34.     plt.scatter(x, y)
  35.     plt.plot(x_out, y_out)
  36.     plt.show()

  37. if __name__ == '__main__':
  38.     PPs = Data.Points.copy()
  39.     PoiStart = XYMaxPoint(Data.Points)
  40.     Poi_A = PoiStart
  41.     RList = []
  42.     Poi_B = []
  43.     n = 0
  44.     while Poi_B != PoiStart:
  45.         Poi_B = NextPoi(Poi_A, PPs)
  46.         RList.append(Poi_A)
  47.         PPs.remove(Poi_A)
  48.         Poi_A = Poi_B
  49.         n = n + 1
  50.         if n == 2:
  51.             PPs.append(PoiStart)
  52.     RList.append(PoiStart)
  53.     XList = [i[0] for i in Data.Points]
  54.     YList = [i[1] for i in Data.Points]
  55.     X_OutList = [i[0] for i in RList]
  56.     Y_OutList = [i[1] for i in RList]
  57.     plot2D(XList, YList, X_OutList, Y_OutList)






本帖子中包含更多资源

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

x
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-25 14:11 , Processed in 1.729254 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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