[从头学数学] 第283节 [计算几何] 多边形的单调块划分
来源:互联网 发布:java字符串换行连接 编辑:程序博客网 时间:2024/05/18 01:00
剧情提要:
阿伟看到了一本比较有趣的书,是关于《计算几何》的,2008年由北清派出版。很好奇
它里面讲了些什么,就来看看啦。
正剧开始:
星历2016年09月28日 15:47:30, 银河系厄尔斯星球中华帝国江南行省。
更多图片:
阿伟看到了一本比较有趣的书,是关于《计算几何》的,2008年由北清派出版。很好奇
它里面讲了些什么,就来看看啦。
正剧开始:
星历2016年09月28日 15:47:30, 银河系厄尔斯星球中华帝国江南行省。
[工程师阿伟]正在和[机器小伟]一起研究[计算几何]]。
<span style="font-size:18px;">#>>> [[6, 9], [2.4, 5.4], [0.8, 3.8], [1.33, 3], [2, 3], [3.33, 5], [6, 3.86], [8, 3], [6, 9]][1.33, 3] End[2, 3] Regular[8, 3] End[0.8, 3.8] Regular[6, 3.86] Regular[3.33, 5] SplitSup[Point([2.4, 5.4]), Point([0.8, 3.8]), Point([1.33, 3]), Point([2, 3]), Point([3.33, 5])][1.33, 3] End[2, 3] Regular[0.8, 3.8] Regular[3.33, 5] Regular[2.4, 5.4] Start[Point([3.33, 5]), Point([6, 3.86]), Point([8, 3]), Point([6, 9]), Point([2.4, 5.4])][8, 3] End[6, 3.86] Regular[3.33, 5] Regular[2.4, 5.4] Regular[6, 9] Start---2[[[2.4, 5.4], [0.8, 3.8], [1.33, 3], [2, 3], [3.33, 5], [2.4, 5.4]], [[3.33, 5], [6, 3.86], [8, 3], [6, 9], [2.4, 5.4], [3.33, 5]]]def tmp6(): path = [[[6, 9], [2.4, 5.4], [0.8, 3.8], [1.33, 3], [2, 3], [6, 3], [6, 3.86], [3.33, 5], [6, 9]], [[6, 9], [2.4, 5.4], [0.8, 3.8], [1.33, 3], [2, 3], [3.33, 5], [6, 3.86], [8, 3], [6, 9]], [[6, 9], [2.4, 5.4], [0.8, 3.8], [0, 3], [1.5, 1.5], [1.78, 2.33], [2, 3], [3.33, 5], [6, 9]], [[6, 9], [2.4, 5.4], [0.8, 3.8], [0, 3], [1.33, 3], [1.78, 2.33], [2, 3], [3.33, 5], [6, 9]], [[6, 9], [2.4, 5.4], [0.8, 3.8], [0, 3], [1.33, 3], [2, 3], [6, 3], [6, 3.86], [6, 9]], [[6, 9], [2.4, 5.4], [0.8, 3.8], [0, 3], [1.33, 3], [2, 3], [3.33, 5], [6, 3.86], [6, 9]], [[6, 9], [2.4, 5.4], [3.33, 5], [2, 3], [6, 3], [6, -3], [8, -7], [8, 3], [6, 9]], [[6, 9], [2.4, 5.4], [3.33, 5], [6, 3.86], [6, 3], [6, -3], [8, -7], [8, 3], [6, 9]], [[6, 9], [2.4, 5.4], [-6, 9], [-0.37, 2.56], [0, 3], [1.33, 3], [2, 3], [3.33, 5], [6, 9]], [[6, 9], [3.33, 5], [2, 3], [1.78, 2.33], [3.67, -0.5], [4.29, 0.43], [6, 3], [6, 3.86], [6, 9]], [[6, 9], [3.33, 5], [2, 3], [6, 3], [6, -3], [5.67, -3.5], [8, -7], [8, 3], [6, 9]], [[6, 9], [3.33, 5], [2, 3], [6, 3], [6, -3], [8, -7], [8, 3], [6, 3.86], [6, 9]], [[6, 9], [3.33, 5], [2, 3], [6, 3], [4.5, 0], [6, -3], [8, -7], [8, 3], [6, 9]], [[6, 9], [3.33, 5], [6, 3.86], [6, 3], [6, -3], [5.67, -3.5], [8, -7], [8, 3], [6, 9]], [[6, 9], [3.33, 5], [6, 3.86], [6, 3], [4.5, 0], [6, -3], [8, -7], [8, 3], [6, 9]], [[6, 9], [6, 3.86], [6, 3], [4.29, 0.43], [4.5, 0], [6, -3], [8, -7], [8, 3], [6, 9]], [[6, 9], [6, 3.86], [6, 3], [6, -3], [5.56, -3.33], [5.67, -3.5], [8, -7], [8, 3], [6, 9]], [[6, 9], [6, 3.86], [6, 3], [6, -3], [5.67, -3.5], [5.35, -3.97], [8, -7], [8, 3], [6, 9]], [[6, 9], [6, 3.86], [6, 3], [4.5, 0], [6, -3], [5.67, -3.5], [8, -7], [8, 3], [6, 9]], [[6, 9], [6, 3.86], [6, 3], [4.5, 0], [4, -1], [6, -3], [8, -7], [8, 3], [6, 9]]] len_path = len(path); #第几条线段作为测试 n = 1; pathArray = []; dealed = []; pathArray.append(path[n]); while (len(pathArray) > 0): path_ = pathArray.pop(0); print(path_); #把路径注册给Polygon类 poly = Polygon(path_); poly.genVertexTree(); #计算凹凸性,这步不能省,否则结果会出错。 poly.setConcave(); #把路径注册给Path类 a = Path(path_); #标记路径中是否有需要处理的点 changed = False; for item in poly.vertexTree: #print(item); stype = item.pointType(); print(item.point, stype); pitem = item.point; #如果顶点类型是汇合顶点 if (stype == 'Merge'): print('M'); downBrother = a.findDownBrother(pitem); if (downBrother != None): #这个其实可以保证,这是由Merge顶点的特性决定的。 print('down'); #找到两个顶点在路径中的序号 idx1 = a.path.index(pitem); idx2 = a.path.index(downBrother); pathArray.append(a.majorSubpath(idx1, idx2)); pathArray.append(a.minorSubpath(idx1, idx2)); changed = True; break; elif (stype == 'Split'): print('S'); upBrother = a.findUpBrother(pitem); if (upBrother != None): #这个其实可以保证,这是由Merge顶点的特性决定的。 print('up'); #找到两个顶点在路径中的序号 idx1 = a.path.index(pitem); idx2 = a.path.index(upBrother); pathArray.append(a.majorSubpath(idx1, idx2)); pathArray.append(a.minorSubpath(idx1, idx2)); changed = True; break; if (changed == False): dealed.append(path_); print('---'); print(len(dealed)); print(dealed);#</span>
<span style="font-size:18px;">#class Path(): def info(self): print(self.path); def __init__(self, path): if (path[-1] == path[0]): path = path[:-1]; if (type(path[0]) == Point): self.path = path; else: self.path = []; for i in range(len(path)): self.path.append(Point(path[i])); #判断路径相等 def __eq__(self, other): if other == None: return False; len_1 = len(self.path); len_2 = len(other.path); if (len_1 != len_2): return False; if (other[0] in self): idx = self.path.index(other[0]); for i in range(len_1): if other[i] != self.path[(idx+i)%len_1]: return False; return True; else: return False; def __len__(self): return len(self.path); def __iter__(self): for i in range(len(self)): yield self.path[i]; def __contains__(self, item): return item in self.path; def __getitem__(self, index): return self.path[index]; #路径上的顶点集 def pointSet(self): pSet = set(); for i in range(len(self.path)): pSet.add(self.path[i]); return pSet; #两个点序号之间的劣弧路径,是以通过点的数量定优劣弧的,不是根据路径长度。 def minorSubpath(self, idx1, idx2): idx1, idx2 = idx1%len(self), idx2%len(self); idx1, idx2 = min(idx1, idx2), max(idx1, idx2); len_path = len(self.path); if (idx2 - idx1) < len_path//2: subPath = self.path[idx1:idx2+1]; else: subPath = self.path[idx2:]+self.path[:idx1+1]; return subPath; #两个点序号之间的优弧路径,是以通过点的数量定优劣弧的,不是根据路径长度。 def majorSubpath(self, idx1, idx2): idx1, idx2 = idx1%len(self), idx2%len(self); idx1, idx2 = min(idx1, idx2), max(idx1, idx2); len_path = len(self.path); if (idx2 - idx1) >= len_path//2: subPath = self.path[idx1:idx2+1]; else: subPath = self.path[idx2:]+self.path[:idx1+1]; return subPath; #连接两段子路径,两段路径必须有相同的起点和终点,这样形成一个环路 def linkPath(self, path1, path2): result = []; if path1[0] == path2[0] and path1[-1] == path2[-1]: path2 = list(reversed(path2)); result = path1[:-1]+path2[:-1]; elif path1[0] == path2[-1] and path1[-1] == path2[0]: result = path1[:-1]+path2[:-1]; return result; #在路径中两个不同点增加对角线,把一条路径分割成两条路径 def addDiagonal(self, index1, index2): if (abs(index1 - index2) > 1): return [self.minorSubpath(index1, index2), self.majorSubpath(index1, index2)]; #找某点的左邻居边,也就是路径中处于给定点的左边,并且在y扫描线上最接近的那条边 def findLeftNearestEdge(self, point): edge = None; scanPoint = None; len_ = len(self.path); for i in range(len_): seg = SegLine(self.path[i].value(), self.path[(i+1)%len_].value()); #点在边的右侧 if (judgePointAgainstEdgePosition(seg, point) == 'Right'): if (edge == None): edge = seg; scanPoint = calcScanLineCrosspoint(seg, point); else: a = calcScanLineCrosspoint(seg, point); #取扫描线的交点的x值 if a[0] > scanPoint[0]: edge = seg; scanPoint = a; return [edge, scanPoint]; #找某点的右邻居边,也就是路径中处于给定点的右边,并且在y扫描线上最接近的那条边 def findRightNearestEdge(self, point): edge = None; scanPoint = None; len_ = len(self.path); for i in range(len_): seg = SegLine(self.path[i].value(), self.path[(i+1)%len_].value()); #点在边的左侧 if (judgePointAgainstEdgePosition(seg, point) == 'Left'): if (edge == None): edge = seg; scanPoint = calcScanLineCrosspoint(seg, point); else: a = calcScanLineCrosspoint(seg, point); #取扫描线的交点的x值 if a[0] < scanPoint[0]: edge = seg; scanPoint = a; return [edge, scanPoint]; #找某点的上兄弟点,这个点的y坐标大于给定点, #并且处于该点的左、右邻居边之间。 #如果没有这种点,返回左、右邻居边的上顶点中y值比较小的那一个点。 def findUpBrother(self, point): #point是Point类型 rEdge = self.findRightNearestEdge(point); lEdge = self.findLeftNearestEdge(point); rSeg, lSeg = rEdge[0], lEdge[0]; upBrother = None; if (rSeg != None and lSeg != None): len_ = len(self.path); for i in range(len_): a = self.path[i].value(); b = point.value(); if (a[1] > b[1]): if (judgePointAgainstEdgePosition(rSeg, self.path[i]) == 'Left' and\ judgePointAgainstEdgePosition(lSeg, self.path[i]) == 'Right'): if upBrother == None: upBrother = self.path[i]; else: if (upBrother < self.path[i]): upBrother = self.path[i]; if upBrother == None: upBrother = min(Point(lSeg.value()[1]), Point(rSeg.value()[1])); return upBrother; #找某点的下兄弟点,这个点的y坐标小于给定点, #并且处于该点的左、右邻居边之间。 #如果没有这种点,返回左、右邻居边的下顶点中y值比较大的那一个点。 def findDownBrother(self, point): #point是Point类型 rEdge = self.findRightNearestEdge(point); lEdge = self.findLeftNearestEdge(point); rSeg, lSeg = rEdge[0], lEdge[0]; downBrother = None; if (rSeg != None and lSeg != None): len_ = len(self.path); for i in range(len_): a = self.path[i].value(); b = point.value(); if (a[1] < b[1]): if (judgePointAgainstEdgePosition(rSeg, self.path[i]) == 'Left' and\ judgePointAgainstEdgePosition(lSeg, self.path[i]) == 'Right'): if downBrother == None: downBrother = self.path[i]; else: if (downBrother < self.path[i]): downBrother = self.path[i]; if downBrother == None: downBrother = max(Point(lSeg.value()[0]), Point(rSeg.value()[0])); return downBrother; #三个点的叉积def crossProduct(P1, P2, P3): x1, y1, x2, y2, x3, y3 = P1[0], P1[1], P2[0], P2[1], P3[0], P3[1]; # # 1 1 1 # x_1 x_2 x_3 # y_1 y_2 y_3 # #逆时针结果为正,顺时针为负 return round((x1*y2-x2*y1)-(x1*y3-x3*y1)+(x2*y3-x3*y2), 3);#判断点在边的左边还是右边def judgePointAgainstEdgePosition(seg, point): #传入SegLine类型和Point类型,这样方便比较 #SegLine是以y优先x其次由小大大排序的,终端点按排序规则大于起始端点 pValue = point.value(); sValue = seg.value(); x0, y0, x1, y1, x2, y2 = pValue[0], pValue[1], sValue[0][0], sValue[0][1],\ sValue[1][0], sValue[1][1]; #点的y值要在线段两个端点的y值中间,可以等于 if (y0 >= y1 and y0 <= y2): cross = crossProduct(pValue, sValue[0], sValue[1]); if (cross > 0): #点在线段的左边 return 'Left'; elif (cross < 0): #点在线段的右边 return 'Right'; return 'Nevermind';#获取扫描线与线段的交点#y方向的扫描线为平行于x轴且y值为某一定值的直线def calcScanLineCrosspoint(seg, point): #传入SegLine类型和Point类型,这样方便比较 #SegLine是以y优先x其次由小大大排序的,终端点按排序规则大于起始端点 pValue = point.value(); sValue = seg.value(); x0, y0, x1, y1, x2, y2 = pValue[0], pValue[1], sValue[0][0], sValue[0][1],\ sValue[1][0], sValue[1][1]; #点的y值要在线段两个端点的y值中间,可以等于 if (y0 >= y1 and y0 <= y2): if y0 == y1: return sValue[0]; elif y0 == y2: return sValue[1]; else: x = x1 + (y0 - y1)/(y2 - y1)*(x2-x1); return [round(x, 2), y0]; return [];#</span>
$split = [[[2.4, 5.4], [0.8, 3.8], [1.33, 3], [2, 3], [3.33, 5], [2.4, 5.4]], [[3.33, 5], [6, 3.86], [8, 3], [6, 9], [2.4, 5.4], [3.33, 5]]]
<span style="font-size:18px;">//if (1) {var r = 20; config.setSector(1,1,1,1); config.graphPaper2D(0, 0, r); config.axis2D(0, 0, 250, 1.2); //坐标轴设定 var scaleX = 2*r, scaleY = 2*r; var spaceX = 2, spaceY = 2; var xS = -10, xE = 10; var yS = -10, yE = 10; config.axisSpacing(xS, xE, spaceX, scaleX, 'X'); config.axisSpacing(yS, yE, spaceY, scaleY, 'Y'); var transform = new Transform(); //顶点var a = [];for (var i = 0; i < $vertex.length; i++) {a.push($vertex[i][0]);}//显示变换 if (a.length > 0) { a = transform.scale(transform.translate(a, 0, 0), scaleX/spaceX, scaleY/spaceY);}var lable = [];for (var i = 0; i < 100; i++) {lable.push(i.toFixed(0));}/*//边集var b = [];for (var i = 0; i < $seg.length; i++) {b.push([a[$seg[i][0]], a[$seg[i][1]]]);}var edges = b.length;for (var i = 0; i < edges; i++) {shape.multiLineDraw([].concat(b[i]), 'red');}*/var colorArray = ['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple'];var seg = [];var idx = xGlobal;var len = $path2.length;plot.setLineWidth(3);seg = transform.scale(transform.translate($path2[idx%len], 0, 0), scaleX/spaceX, scaleY/spaceY);shape.multiLineDraw([].concat(seg), 'pink');plot.fillText('路径: '+(idx%len).toFixed(0), 200, -150, 200);for (var i = 0; i < $split.length; i++) {seg = transform.scale(transform.translate($split[i], 0, 0), scaleX/spaceX, scaleY/spaceY);shape.multiLineDraw([].concat(seg), colorArray[i%7]);}//主要顶点shape.pointDraw([].concat(a), 'blue', 1, 1, lable);cPoint = transform.scale(transform.translate($center, 0, 0), scaleX/spaceX, scaleY/spaceY);shape.pointDraw([].concat([cPoint[idx%len]]), 'black');/*concavePoint = transform.scale(transform.translate($concave[idx%len], 0, 0), scaleX/spaceX, scaleY/spaceY);shape.pointDraw([].concat(concavePoint), 'orange');*///次要顶点var b = [];for (var i = 0; i < 6; i++) {b = [].concat($pointType[idx%len][i]);//显示变换 if (b.length > 0) { b = transform.scale(transform.translate(b, 0, 0), scaleX/spaceX, scaleY/spaceY);shape.pointDraw([].concat(b), colorArray[(i-1)%7]);}}}//</span>
更多图片:
本节到此结束,欲知后事如何,请看下回分解。
0 0
- [从头学数学] 第283节 [计算几何] 多边形的单调块划分
- [从头学数学] 第285节 [计算几何] 区域划分
- [从头学数学] 第275节 [计算几何] 多边形顶点的五种类型
- [从头学数学] 第277节 [计算几何] 任意多边形的内角
- [从头学数学] 第286节 [计算几何] 多边形的布尔运算(上)
- [从头学数学] 第287节 [计算几何] 多边形的布尔运算(中)
- [从头学数学] 第288节 [计算几何] 多边形的布尔运算(下)
- [从头学数学] 第269节 [计算几何] 点在多边形内
- [从头学数学] 第273节 [计算几何] 多边形求交集
- [从头学数学] 第278节 [计算几何] 多边形周长和面积
- [从头学数学] 第284节 [计算几何] 生成随机多边形
- [从头学数学] 第240节 计算几何 整装待发
- [从头学数学] 第263节 [计算几何] 线段生成
- [从头学数学] 第267节 [计算几何] 路径规划
- [从头学数学] 第268节 [计算几何] 环形路径
- [从头学数学] 第271节 [计算几何] 凸包
- [从头学数学] 第274节 [计算几何] 顶点树
- [从头学数学] 第279节 [计算几何] 重心
- Tmux知识总结
- Long short-term memory 论文小记
- springmvc与swagger的集成
- rz命令与sx等命令——串口终端下载文件到目标板
- MAC安装配置tomcat
- [从头学数学] 第283节 [计算几何] 多边形的单调块划分
- 车道线检测霍夫直线检测原理分析
- 编程之美2.15子数组之和的最大值(二维)
- 数据结构学习(一):入门
- Salesforce通过Apex获取API名 Comparable排序
- 关于3.5以上版本FBX模型文件导入unity后不播放动作的问题
- 华为oj之等差数列前n项和
- spring-boot freemarker 数字格式不用逗号隔开配置
- 不懂技术不要对懂技术的人说这很容易实现