[从头学数学] 第265节 [计算几何] 多线段求交点(扫描线法)
来源:互联网 发布:手机淘宝注册账号申请 编辑:程序博客网 时间:2024/05/18 15:28
剧情提要:
阿伟看到了一本比较有趣的书,是关于《计算几何》的,2008年由北清派出版。很好奇
它里面讲了些什么,就来看看啦。
正剧开始:
星历2016年09月19日 11:58:08, 银河系厄尔斯星球中华帝国江南行省。
阿伟看到了一本比较有趣的书,是关于《计算几何》的,2008年由北清派出版。很好奇
它里面讲了些什么,就来看看啦。
正剧开始:
星历2016年09月19日 11:58:08, 银河系厄尔斯星球中华帝国江南行省。
[工程师阿伟]正在和[机器小伟]一起研究[计算几何]]。
本节的程序并没有最终完成,目前仅仅是没有语法错误,能运行而已,但运算逻辑上有一点问题,计算结果并不准确。
<span style="font-size:18px;">#class Point(): def __init__(self, point): self.point = point; def __lt__(self, other): if (type(other.point) != type([0, 0])): return self.point < other.point; else: p1 = self.point; p2 = other.point; if p1[1] < p2[1]: return True; elif p1[1] > p2[1]: return False; else: return p1[0] < p2[0]; def __eq__(self, other): if other == None: return False; else: return self.point == other.point; def __str__(self): return str(self.point); def __repr__(self): return 'Point('+str(self)+')'; def __hash__(self): return hash(str(self));#</span>
<span style="font-size:18px;">##线段类class SegLine(): def __init__(self, pStart=[1e6,1e6], pEnd=[1e6, 1e6]): #按照y值由小到大,x值由小到大的顺序排列 if pStart[1] > pEnd[1]: pStart, pEnd = pEnd, pStart; elif pStart[1] == pEnd[1]: if pStart[0] > pEnd[0]: pStart, pEnd = pEnd, pStart; self.pStart = pStart; self.pEnd = pEnd; #<号的判定是根据起点和终点的位置 #y值权重优先 def __lt__(self, other): if type(self) == type(None) or type(other) == type(None): return False; if self.pStart == other.pStart: if self.pEnd[1] < other.pEnd[1]: return True; elif self.pEnd[1] == other.pEnd[1]: if self.pEnd[0] < other.pEnd[0]: return True; else: return False; else: if self.pStart[1] < other.pStart[1]: return True; elif self.pStart[1] == other.pStart[1]: if self.pStart[0] < other.pStart[0]: return True; else: return False; def __eq__(self, other): if type(self) == type(None) or type(other) == type(None): return False; if self.pStart == other.pStart and self.pEnd == other.pEnd: return True; return False; def __gt__(self, other): if self == other or self < other: return False; return True; def __ge__(self, other): return (not self < other) or (self == other); def __str__(self): x1, y1 = self.pStart[0], self.pStart[1]; x2, y2 = self.pEnd[0], self.pEnd[1]; return '[['+str(x1)+', '+str(y1)+'], ['+str(x2)+', '+str(y2)+']]'; def __hash__(self): return hash(str(self)); def __repr__(self): return 'SegLine('+str(self)[1:-1]+')';#</span>
<span style="font-size:18px;">##扫描线求线段交点class Inter(): def __init__(self): #事件队列,携带事件点和相应线段 self.Q = None; #事件点的键值 self.K = []; #线段树 self.T = AVL.AVLTree(); #交点集 self.Inter = set(); #已处理交点 self.dealed = []; #两条线段求交点 def cross_2Seg(self, seg1, seg2): cp = geo.crossPointOfTwoLine(seg1, seg2); if cp != [] and (geo.pointInSeg(cp, seg1) and geo.pointInSeg(cp, seg2)): return cp; else: return []; def findIntersections(self, seg, n = 2): #空的事件队列Q self.Q = dict(); for i in range(len(seg)): self.Q[Point(seg[i][0])] = []; self.Q[Point(seg[i][1])] = []; for i in range(len(seg)): self.Q[Point(seg[i][0])].append(SegLine(seg[i][0], seg[i][1])); len_ = len(self.Q); i = 0; while (len_ > 0 and i < n): self.K = sorted(list(self.Q.keys())); #print(k); self.dealed.append(self.K[0]); p = [self.K[0], self.Q.pop(self.K[0])]; #print(p); #处理顶点事件 self.handleEventPoint(p); len_ = len(self.Q); i+= 1; def handleEventPoint(self, p): #以顶点为起始点的线段 U_p = p[1]; #以顶点为终结点的线段 L_p = []; #内部包含此顶点的线段 C_p = []; #从第一个顶点事件开始,累加线段元素的线段树self.T for item in self.T: if type(item) == SegLine: if item.pStart == p[0].point: pass; elif item.pEnd == p[0].point: L_p.append(item); else: #点在线段中 if geo.pointInLine(p[0].point, item.pStart, item.pEnd): C_p.append(item); if len(set(U_p+L_p+C_p)) > 1: self.Inter.add(p[0]); lc = set(L_p+C_p); for item in lc: self.T.delete(item); uc = set(U_p+C_p); for item in uc: self.T.insert(item); # #以下部分的处理逻辑有待改正 if len(uc) == 0: pass; else: uc = sorted(uc); min_ = uc[0]; #print('---', type(min_), min_); node = self.T.find(min_); if (node != None): s_l = node.getLeft(); if (s_l != None): self.findNewEvent(s_l.getVal(), min_, p); else: s_l = self.T.parent(self.T.root, node); if (s_l != None): self.findNewEvent(s_l.getVal(), min_, p); max_ = uc[-1]; #print('---', type(max_), max_); node = self.T.find(max_) if (node != None): s_r = node.getRight(); if (s_r != None): self.findNewEvent(s_r.getVal(), max_, p); else: s_r = self.T.parent(self.T.root, node); if (s_r != None): self.findNewEvent(s_r.getVal(), max_, p); def findNewEvent(self, s_l, s_r, p): seg_l = [s_l.pStart, s_l.pEnd]; seg_r = [s_r.pStart, s_r.pEnd]; inter = self.cross_2Seg(seg_l, seg_r); if inter != []: p_1 = Point(inter); if (p_1 not in self.dealed) and p_1 > p[0]: self.Q[p_1] = [SegLine(inter, s_l.pEnd), SegLine(inter,s_r.pEnd)]; self.Inter.add(p_1); def result(self): print('交点'); print(self.Inter); print('线段树'); self.T.info(); def tmp8(): debug = 1; seg=[[[0, 3], [2, 3]], [[0, 5], [-6, 9]], [[2, -9], [-2, -5]], [[-2, -9], [8, 3]], [[8, -7], [4, -1]], [[6, -3], [0, 5]], [[-10, -9], [2, -7]], [[2, -3], [2, 3]], [[4, 1], [6, 9]], [[6, 3], [-4, 5]], ]; task = Inter(); task.findIntersections(seg, 8); task.result();#</span>
<span style="font-size:18px;">##判定点在线段上def pointInSeg(Point_1, Seg): Point_2, Point_3 = Seg[0], Seg[1]; if Point_1 == [] or Point_2 == [] or Point_3 == []: return False; x1, y1, x2, y2, x3, y3 = Point_1[0], Point_1[1], Point_2[0], Point_2[1], Point_3[0], Point_3[1]; delta = abs((x1*y2-y1*x2)+(x2*y3-y2*x3)+(x3*y1-y3*x1)); if delta > 1e-6: return False; x = sorted([x2, x3]); y = sorted([y2, y3]); if ((x1 >= x[0] and x1 <= x[1]) and (y1 >= y[0] and y1 <= y[1])): return True; else: return False;#</span>
<span style="font-size:18px;">##### @usage 平衡二叉树# @author mw# @date 2016年07月28日 星期四 15:36:42 # @param# @return####class AVLTree(object): def info(self): a = []; for x in self: a.append(x); print(a); def __iter__(self): if self.root != None: return self.root.__iter__() else: return [].__iter__() def __contains__(self, val): for x in self: if (x == val): return True; return False; def __len__(self): a = []; for x in self: a.append(x); return len(a); class __AVLNode(object): def __init__(self, key, height = 0, left = None, right = None): self.key=key self.left=left self.right=right self.height=0 def getVal(self): return self.key def setVal(self,newval): self.key = newval def getLeft(self): return self.left def getRight(self): return self.right def setLeft(self,newleft): self.left = newleft def setRight(self,newright): self.right = newright def __iter__(self): if self.left != None: for elem in self.left: yield elem if (self.key != None): yield self.key if self.right != None: for elem in self.right: yield elem #迭代的是Node类型,用于删除结点 def iternodes(self): if self.left != None: for elem in self.left.iternodes(): yield elem if self != None and self.key != None: yield self if self.right != None: for elem in self.right.iternodes(): yield elem def info(self): s = 'Key='+str(self.key)+', '+\ 'LChild='+str(self.left)+', '+\ 'RChild='+str(self.right)+', '+\ 'H='+str(self.height); print(s); def __str__(self): return str(self.key); def __repr__(self): if self != None: s_1 = str(self.key); else: s_1 = 'None'; if self.left != None: s_2 = str(self.left.key); else: s_2 = 'None'; if self.right != None: s_3 = str(self.right.key); else: s_3 = 'None'; s_4 = str(self.height); return '__AVLNode('+s_1+', ' + s_2 +', ' + s_3 +', '+s_4+')'; def __init__(self): self.root=None def find(self,key): if self.root is None: return None else: return self._find(key, self.root) def _find(self, key, node): if node is None: return None elif key < node.key: return self._find(key, node.left) elif key > node.key: return self._find(key, node.right) else: return node #找最小元素 def findMin(self): if self.root is None: return None else: return self._findMin(self.root) def _findMin(self,node): if node.left: return self._findMin(node.left) else: return node #找最大元素 def findMax(self): if self.root is None: return None else: return self._findMax(self.root) def _findMax(self,node): if node.right: return self._findMax(node.right) else: return node #求结点高度 def height(self, node): if (node == None): return 0; else: m = self.height(node.left); n = self.height(node.right); return max(m, n)+1; #LL def singleLeftRotate(self,node): k1=node.left node.left=k1.right k1.right=node node.height=max(self.height(node.right),self.height(node.left))+1 k1.height=max(self.height(k1.left),node.height)+1 return k1 #RR def singleRightRotate(self,node): k1=node.right node.right=k1.left k1.left=node node.height=max(self.height(node.right),self.height(node.left))+1 k1.height=max(self.height(k1.right),node.height)+1 return k1 #RL def doubleLeftRotate(self,node): node.left=self.singleRightRotate(node.left) return self.singleLeftRotate(node) #LR def doubleRightRotate(self,node): node.right=self.singleLeftRotate(node.right) return self.singleRightRotate(node) #插入 def insert(self, key): if not self.root: self.root=AVLTree.__AVLNode(key) else: self.root=self._insert(self.root, key) def _insert(self, node, key): if node is None: node=AVLTree.__AVLNode(key) elif key<node.key: node.left=self._insert(node.left, key) if (self.height(node.left)-self.height(node.right))==2: if key<node.left.key: node=self.singleLeftRotate(node) else: node=self.doubleLeftRotate(node) elif key>node.key: node.right=self._insert(node.right, key) if (self.height(node.right)-self.height(node.left))==2: if key<node.right.key: node=self.doubleRightRotate(node) else: node=self.singleRightRotate(node) node.height=max(self.height(node.right),self.height(node.left))+1 return node #删除 def delete(self, key): if key in self: self.root=self.remove(key, self.root) def remove(self, key, node): if node is None: raise KeyError('Error,key not in tree'); elif key<node.key: node.left=self.remove(key,node.left) if (self.height(node.right)-self.height(node.left))==2: if self.height(node.right.right)>=self.height(node.right.left): node=self.singleRightRotate(node) else: node=self.doubleRightRotate(node) node.height=max(self.height(node.left),self.height(node.right))+1 elif key>node.key: node.right=self.remove(key,node.right) if (self.height(node.left)-self.height(node.right))==2: if self.height(node.left.left)>=self.height(node.left.right): node=self.singleLeftRotate(node) else: node=self.doubleLeftRotate(node) node.height=max(self.height(node.left),self.height(node.right))+1 elif node.left and node.right: if node.left.height<=node.right.height: minNode=self._findMin(node.right) node.key=minNode.key node.right=self.remove(node.key,node.right) else: maxNode=self._findMax(node.left) node.key=maxNode.key node.left=self.remove(node.key,node.left) node.height=max(self.height(node.left),self.height(node.right))+1 else: if node.right: node=node.right else: node=node.left return node #传回结点的原始信息 def iternodes(self): if self.root != None: return self.root.iternodes() else: return [None]; #寻找节点路径 def findNodePath(self, root, node): path = []; if root == None or root.key == None: path = []; return path while (root != node): if node.key < root.key: path.append(root); root = root.left; elif node.key >= root.key: path.append(root); root = root.right; else: break; path.append(root); return path; #寻找父结点 def parent(self, root, node): path = self.findNodePath(root, node); if (len(path)>1): return path[-2]; else: return None; #是否左孩子 def isLChild(self, parent, lChild): if (parent.getLeft() != None and parent.getLeft() == lChild): return True; return False; #是否右孩子 def isRChild(self, parent, rChild): if (parent.getRight() != None and parent.getRight() == rChild): return True; return False; #求某元素是在树的第几层 #约定根为0层 #这个计算和求结点的Height是不一样的 def level(self, elem): if self.root != None: node = self.root; lev = 0; while (node != None): if elem < node.key: node = node.left; lev+=1; elif elem > node.key: node = node.right; lev+=1; else: return lev; return -1; else: return -1; if __name__ == '__main__': avl = AVLTree(); a = [20, 30, 40, 120, 13, 39, 38, 40, 18, 101]; b = [[10, 1], [3, 0], [4, 0], [13, -1], [2, 0], [18, 0], [40, -1], [39, 0], [12, 0]]; c = [4, 2, 6, 1, 3, 7]; for item in c: avl.insert(item); for i in range(-10, 10, 2): avl.insert(i); avl.info(); print(45 in avl); print(len(avl)); ''' avl.delete(40); avl.info(); avl.delete(100); avl.info(); avl.insert(1001); avl.info(); ''' for item in avl.iternodes(): item.info(); print(avl.findNodePath(avl.root, item)); print('Parent:', avl.parent(avl.root, item)); print('Level:', avl.level(item.key)); print('\n');#</span>
上图是例题:
可以看出结果并不准确。主要是算法逻辑还不太清晰。
本节到此结束,欲知后事如何,请看下回分解。
0 0
- [从头学数学] 第265节 [计算几何] 多线段求交点(扫描线法)
- [从头学数学] 第266节 [计算几何] 多线段求交点
- [从头学数学] 第263节 [计算几何] 线段生成
- [从头学数学] 第264节 [计算几何] 点和线段
- [从头学数学] 第272节 [计算几何] 从线段集连通区域
- [从头学数学] 第273节 [计算几何] 多边形求交集
- [从头学数学] 第240节 计算几何 整装待发
- [从头学数学] 第267节 [计算几何] 路径规划
- [从头学数学] 第268节 [计算几何] 环形路径
- [从头学数学] 第271节 [计算几何] 凸包
- [从头学数学] 第274节 [计算几何] 顶点树
- [从头学数学] 第279节 [计算几何] 重心
- [从头学数学] 第280节 [计算几何] 路径合并
- [从头学数学] 第281节 [计算几何] 路径分解
- [从头学数学] 第285节 [计算几何] 区域划分
- [从头学数学] 第286节 [计算几何] 多边形的布尔运算(上)
- [从头学数学] 第287节 [计算几何] 多边形的布尔运算(中)
- [从头学数学] 第288节 [计算几何] 多边形的布尔运算(下)
- 堆栈窗口 QStackedWidget 测试
- HDU 5900 区间dp
- python基础回顾
- 【JZOJ 4788】 序列
- ListView使用
- [从头学数学] 第265节 [计算几何] 多线段求交点(扫描线法)
- Android 5.0 CardView
- 同步时序电路动态约束
- char *和char[]的区别
- tableView reloadData
- 决定未来的八大核心科技
- ASCII字符集中的功能/控制字符
- 多台机器批量执行命令
- Ubuntu 64 位安装Mongodb,添加数据库用户校验等等