[从头学数学] 第265节 [计算几何] 多线段求交点(扫描线法)

来源:互联网 发布:手机淘宝注册账号申请 编辑:程序博客网 时间:2024/05/18 15:28
剧情提要:
阿伟看到了一本比较有趣的书,是关于《计算几何》的,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
原创粉丝点击