精华内容
下载资源
问答
  • 主要介绍了基于python 凸包问题的解决方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • Python 凸包算法

    2017-10-28 09:11:45
    凸包问题是指在n个点中,寻找一个凸多边形,使所有的点在凸多边形的边界或者内部。实现语言:Python
  • python凸包问题

    2020-04-01 08:57:44
    凸包问题 什么是凸包? 举个栗子吧 有很多钉子,钉在木板上。拿根猴皮筋,拉的足够大。一松开,“啪”一声,现在的猴皮筋就是凸包 凸包是什么 或者说,让这根猴皮筋尽量小,同时能把所有的钉子包含在内。 怎么求呢?...

    凸包问题

    什么是凸包?
    举个栗子吧
    有很多钉子,钉在木板上。拿根猴皮筋,拉的足够大。一松开,“啪”一声,现在的猴皮筋就是凸包
    凸包是什么
    呵呵,有点丑。
    或者说,让这根猴皮筋尽量小,同时能把所有的钉子包含在内。
    怎么求呢?
    先插一段:
    凸包属于计算几何,计算几何很大程度上基于一个东西,叫做叉积
    而且主要用的是判断是在左边还是在右边,叉积>0在左,=0在中,<0在右。
    它当然也可以除2算三角形的面积
    为什么?
    叉积
    这时p2落在了p0->p1的左侧
    右侧呢?
    只需要交换p1和p2的位置就可以了就可以了。
    交换后面积=y1x2/2-y2x1/2
    =-原面积
    这就是为什么这样了

    class Point:
        x=0
        y=0
        @classmethod
        def multi(cls,center,fix,mov):
            x1=fix.x-center.x;y1=fix.y-center.y
            x2=mov.x-center.x;y2=mov.y-center.y
            return x1*y2-x2*y1
    

    我们直接上算法了。
    这个算法需要排序(我也不清楚为什么QwQ)
    点排序?难道是字典序?不对。
    需要构建一个极坐标系(也许我把它说的麻烦了),以最下面的点(如有多个取最左边的)为极点,按极角排序。
    或者上图吧:
    排序方法
    开两个栈,一个存储没发现的(undiscovered),一个存储当前凸包(convex)。
    先把0号元素和1号元素入convex。
    剩下的入到undiscovered。
    入栈
    每一次取出undiscovered栈顶x,convex栈顶y和次顶z
    如果x落在z->y左侧,则让z、y回家,同时x也跑到convex家里。
    否则,y不属于凸包,只能变成“无栈可归”的乞丐,z回到了convex,x回到了undiscovered
    一直重复以上,直到undiscovered为空,convex即为凸包
    为什么x跑到右侧y就被害(成乞丐)了呢?
    原因

    代码

    请不要觉得快完了。
    凸包代码效果
    注释:后来觉得慢,在里面加入了tracer相关代码,下面附上改进后的效果:
    改进后

    import turtle
    from queue import *
    from functools import cmp_to_key
    turt=turtle.Turtle()
    scr=turtle.Screen()
    class Point:
        x=0
        y=0
        @classmethod
        def multi(cls,center,fix,mov):
            x1=fix.x-center.x;y1=fix.y-center.y
            x2=mov.x-center.x;y2=mov.y-center.y
            return x1*y2-x2*y1
    points=[]
    ltl=Point()
    first=True
    undoing=0
    def convexHull():
        #region pre
        #region globals
        global points
        global undoing
        #endregion
        print(ltl.x,ltl.y)
        p=points[0]
        # for sub,i in enumerate(points):
        #     if i.x==ltl.x and i.y == ltl.y:
        #         points[sub]=p
        #         points[0]=ltl
    
        points[1:]=sorted(points[1:],
            key=cmp_to_key(
                lambda x,y:Point.multi(ltl,y,x)
            )
        )
        #endregion
        if len(points) >= 3:
            #region convex
            #region mid
            convex=LifoQueue()
            undiscovered=LifoQueue()
            convex.put(ltl)
            convex.put(points[1])
            for i in points[:1:-1]:
                undiscovered.put(i)
            #endregion
            while not undiscovered.empty():
                convextop=convex.get()
                convexsecondary=convex.get()
                udcdtop=undiscovered.get()
                if Point.multi(convexsecondary,convextop,udcdtop) > 0:
                    convex.put(convexsecondary);convex.put(convextop);convex.put(udcdtop)
                else:
                    convex.put(convexsecondary);undiscovered.put(udcdtop)
            top=convex.get()
            bot=top
            while not convex.empty():
                t=convex.get()
                turt.penup();turt.goto(t.x, t.y);turt.pendown()
                turt.goto(bot.x, bot.y)
                bot=t
                undoing+=4
            turt.penup();turt.goto(top.x, top.y);turt.pendown()
            turt.goto(bot.x, bot.y)
            undoing+=4
    
            #endregion
    
        pass
    
    lastUndoCap=0
    def getpos(x,y):
        #region globals
        global lastUndoCap
        global first
        global points
        global undoing
        #endregion
        isLtl=False
        if first:
            ltl.x=x;ltl.y=y
            isLtl=True
        else:
            if y < ltl.y:
                ltl.x = x
                ltl.y = y
                isLtl = True
            elif y == ltl.y:
                if x < ltl.x:
                    ltl.x = x
                    ltl.y = y
                    isLtl = True
        first=False
        turtle.tracer(False)
        # while turt.undobufferentries() != lastUndoCap:
        #     turt.undo()
        for i in range(0,undoing):
            turt.undo()
        undoing=0
        turtle.tracer(True)
    
        print("%d %d",x,y)
        turt.penup();turt.goto(x, y)
        radii=1
        turt.left(90);turt.backward(radii);turt.right(90)
        turt.begin_fill();turt.pendown();turt.color("blue");turt.circle(radii);turt.end_fill()
        point=Point()
        point.x=x;point.y=y
        if isLtl:
            points.insert(0,point)
        else:
            points.append(point)
        lastUndoCap=turt.undobufferentries()
        turtle.tracer(False)
        convexHull()
        turtle.tracer(True)
    
    
    turt.hideturtle();turtle.delay(0)
    lastUndoCap=turt.undobufferentries()
    scr.onclick(getpos)
    turtle.done()
    
    
    

    呵呵,代码不算好,我在代码里每次都重算,到后面就显得慢了(tracer也压不住啊),如果要搞这种递增的算法,还是建议换一个。
    另外,如果假设一个点在-\infin处,这时候按照极角排序就变成了按照x从右边到左边排序,最后获得的凸包是上凸壳(就是最左边的点到最右边的点,在这两个地方把凸包剪开,上面的就是上凸壳)。
    上图吧
    上凸壳
    如果是假设有一个点在++\infin处,那么就变成了从右往左边排序,这个时候类似的得到的就是下凸壳。
    下凸壳
    把两个凸壳拼起来就是凸包了。
    酱终于没有极角的那些捣乱了,ε=ε=ε=(~ ̄▽ ̄)~
    上面算法复杂度:mnlogn,m为次数,n为点数。要只有一次,建议使用上述算法。


    下面算法复杂度:n^2,n为点数。在多次递增时体现优势,在一次时略差。
    首先开始3个点,一定是凸包。
    每一个点要记录顺着自己逆时针走到的第一个点ccw和顺时针走到的cw。
    每一次我们要将局部解扩张到更大的局部解。
    新进来一个点,可能是凸包,可能不是,也可能自己是了同时有点又不是了。。。
    怎么弄呢?举个栗子吧。
    某某某年,人类航天技术极度繁荣,准备探索a系。我们把飞船建在了一颗小行星(局部解)上,然后飞往a系。为了探索需要,每一个飞船角需要建立一个“灯塔”(凸包上的点)。进入a系后,发现恒星(新进来的点)也是光源。而阳光把小行星分成了阴阳两面。有人就想:可以把这颗恒星变成灯塔(技术允许),然后把a系小行星带召唤过来,拼一拼,不就构成了个更大的小行星(更大的局部解)吗?同时为了省电,不露出来的灯塔(不属于新凸包的点)就要拆掉。现在灯塔很多,人有眼而不得算之,机器可以算,机器的眼睛呢?总不能把人眼拆下来吧。。。
    仔细想一想就知道,要拆掉阳面(不包括分界点)的灯塔。
    画布背景变黑是因为要模拟太空
    拆掉哪些灯塔
    那怎么去计算呢?阴阳切点的现象有什么区别?
    我们暂且把灯塔化成指向这个点的ccw点的箭头
    加箭头
    发现了吗?阳面箭头朝下,阴面箭头朝上,切点箭头朝左右。
    我们可以这样判断,随便找到一个灯塔,把自己的位置记为M。设恒星为S。
    让R为自己的ccw,L为自己的cw,做这样的判断:

    1. l在S->M线左侧,r在S->M线右侧,M在阳面阳
    2. l在S->M线右侧,r在S->M线左侧,M在阴面阴
    3. l,r都在S->M线左侧,M在切点1切点1
    4. l,r都S->M线右侧,M在切点2切点2

    如果是切点,记下来。
    然后逆时针走一格。
    如此往复,直到走完了一圈,就可以来把恒星变灯塔和召唤小行星带了。
    那这一步怎么做呢?很简单,只需要:
    S.cw=切点2
    切点2.ccw=S
    S.ccw=切点1
    切点1.cw=S
    而这一步就像链表删除一样。那些灯塔,尽管已经不再小行星内了,但它们自己还连在一起。
    现在一个更大的飞船造出来了,就可以去探访下一个星系b系了。
    等等?似乎还有一个问题。万一恒星跑到小行星里面怎么办?(其实现实不允许啦。)
    你会发现:
    戴森球
    这个小行星就成戴森球了。
    对应的现实就是不把它算作凸包点,就算把它变成灯塔,也要拆掉,又何必呢?

    代码2

    小行星算法

    import turtle
    from queue import *
    from functools import cmp_to_key
    turt=turtle.Turtle()
    scr=turtle.Screen()
    class Point:
        x=0
        y=0
        def __init__(self):
            self.ccw=self.cw=None
        @classmethod
        def multi(cls,center,fix,mov):
            x1=fix.x-center.x;y1=fix.y-center.y
            x2=mov.x-center.x;y2=mov.y-center.y
            return x1*y2-x2*y1
        def copy(self):
            a=Point()
            a.x=self.x
            a.y=self.y
            a.ccw=self.ccw
            a.cw=self.cw
            return a
    points=[]
    ltl=Point()
    first=True
    lastUndoCap=0
    undoing=0
    def ncp(a,b):
        points[a].ccw=points[b]
        points[b].cw=points[a]
    def getpos(x,y):
        #region globals
        global lastUndoCap
        global first
        global points
        global undoing
        #endregion
        isLtl=False
        if first:
            ltl.x=x;ltl.y=y
            isLtl=True
        else:
            if y < ltl.y:
                ltl.x = x
                ltl.y = y
                isLtl = True
            elif y == ltl.y:
                if x < ltl.x:
                    ltl.x = x
                    ltl.y = y
                    isLtl = True
        first=False
        turtle.tracer(False)
        # while turt.undobufferentries() != lastUndoCap:
        #     turt.undo()
        for i in range(0,undoing):
            turt.undo()
        undoing=0
        turtle.tracer(True)
        print("%d %d",x,y)
        turt.penup();turt.goto(x,y)
        radii=1
        turt.left(90);turt.backward(radii);turt.right(90)
        turt.begin_fill();turt.pendown();turt.color("blue");turt.circle(radii);turt.end_fill()
        point=Point()
        point.x=x;point.y=y
        if isLtl:
            points.insert(0,point)
        else:
            points.append(point)
        lastUndoCap=turt.undobufferentries()
        #region convex
        if len(points) == 3:
            left=(0<Point.multi(points[0],points[1],points[2]))
            if left:
                ncp(0,1)
                ncp(1,2)
                ncp(2,0)
            else:
                ncp(0,2)
                ncp(2,1)
                ncp(1,0)
        elif len(points) > 3:
            p=Point()
            orisub=0
            if isLtl:
                p=points[1]
                orisub=1
            else:
                p=points[0]
                orisub=0
            st=p.copy()
            sun=point
            q1=None
            q2=None
            while True:
                p=p.ccw
                l=p.cw
                r=p.ccw
                ll=(0 < Point.multi(sun,p,l))
                rl=(0 < Point.multi(sun,p,r))
                if ll == rl:
                    if ll:
                        q1=p
                    else:
                        q2=p
                if p.x==st.x and p.y==st.y:
                    break
            if q1 is not None:
                sun.cw = q2
                q2.ccw = sun
                sun.ccw = q1
                q1.cw = sun
        if len(points) >= 3:
            turt.penup();turt.goto(points[0].x,points[0].y);turt.pendown()
            undoing+=3
            it=points[0].copy()
            turtle.tracer(False)
            while True:
                turt.goto(it.ccw.x,it.ccw.y)
                undoing+=1
                it=it.ccw.copy()
                if it.x==points[0].x and it.y==points[0].y:
                    break
            turtle.tracer(True)
    
    
    
    
    
        #endregion
    
    
    turt.hideturtle();turtle.delay(0)
    lastUndoCap=turt.undobufferentries()
    scr.onclick(getpos)
    turtle.done()
    
    
    

    最后解释一下:到数据非常大时可能出现绘图问题,算法99%的概率没错。(不排除误判)我正在试图尽量减少这种问题,好像这种问题是撤销造成的。
    解释

    本人小白一枚,如有错误请指正!

    展开全文
  • 最近需要用到凸包算法,在网上找了一些不太对,可能是直角坐标系的。发现一篇文章,简单修改一下就可以用了,效果很不错,在这里分享给大家。def cross(A,B):return A[0] * B[1] - A[1] * B[0]def vectorMinus( a , ...

    最近需要用到凸包算法,在网上找了一些不太对,可能是直角坐标系的。

    发现一篇文章,简单修改一下就可以用了,效果很不错,在这里分享给大家。

    def cross(A,B):

    return A[0] * B[1] - A[1] * B[0]

    def vectorMinus( a , b):

    return ( (a[0] - b[0] )*1000,(a[1] - b[1] )*1000)

    def getLTDis( A, B ):

    lon1, lat1, lon2, lat2 = map(radians, [A[0], A[1], B[0], B[1]])

    dlon = lon2 - lon1

    dlat = lat2 - lat1

    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2

    c = 2 * asin(sqrt(a))

    r = 6371.393

    #print A,B

    return c * r * 1000.0

    def triangleAre(A,B,C):

    x,y,z = getLTDis(A,B),getLTDis(B,C),getLTDis(C,A)

    c = (x + y + z) /2

    return sqrt((c)*(c-y)*(c-z)*(c-x))

    def grahamScanArea(data):

    data.sort(key=lambda x:(x[0],x[1]),reverse=False)

    ans = [ 0 ] * (len(data)*2)

    m = 0

    for item in data:

    top = len(item)

    while( m > 1 and cross( vectorMinus(ans[ m -1 ] , ans [ m - 2 ]), vectorMinus( item , ans [ m - 2 ] )) <= 0 ) : m = m -1

    ans[m] = item

    m = m + 1

    k = m

    flag = True

    data.reverse()

    for item in data:

    if flag :

    flag = False

    continue

    while( m > k and cross( vectorMinus(ans[ m -1 ] , ans [ m - 2 ]), vectorMinus( item , ans [ m - 2 ] )) <= 0) : m = m - 1

    ans [m] = item

    m = m + 1

    m = m -1

    b = [ ans[i] for i in range(0, m)]

    if len(b) < 3 : return 0

    #if DEBUG : print b

    return AREA(b)

    def AREA(b):

    ans = 0.0

    for i in range(len(b)):

    if i == 0 or i + 1 >= len(b) : continue

    x , y = b[i] , b[i + 1]

    ans += triangleAre( b[0] , x , y )

    return ans 转自:http://www.cnblogs.com/shuly/p/5810253.html

    展开全文
  • python 凸包(经纬度)+面积[近似]

    千次阅读 2017-04-07 16:18:57
    最近需要用到凸包算法,在网上找了一些不太对,可能是直角坐标系的。 发现一篇文章,简单修改一下就可以用了,效果很不错,在这里分享给大家。 def cross(A,B): return A[0] * B[1] - A[1] * B[0] def ...


    最近需要用到凸包算法,在网上找了一些不太对,可能是直角坐标系的。

    发现一篇文章,简单修改一下就可以用了,效果很不错,在这里分享给大家。


    def cross(A,B):
        return A[0] * B[1] - A[1] * B[0]
    
    def vectorMinus( a , b):
        return ( (a[0] - b[0] )*1000,(a[1] - b[1] )*1000)
    
    def getLTDis( A, B ):
        lon1, lat1, lon2, lat2 = map(radians, [A[0], A[1], B[0], B[1]])
        dlon = lon2 - lon1
        dlat = lat2 - lat1
        a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
        c = 2 * asin(sqrt(a))
        r = 6371.393
        #print A,B
        return c * r * 1000.0
    
    def triangleAre(A,B,C):
        x,y,z = getLTDis(A,B),getLTDis(B,C),getLTDis(C,A)
        c  =  (x + y  + z) /2
        return sqrt((c)*(c-y)*(c-z)*(c-x))
    
    
    def grahamScanArea(data):
        data.sort(key=lambda x:(x[0],x[1]),reverse=False)
        ans = [ 0 ] * (len(data)*2)
        m = 0
        for item in data:
            top = len(item)
            while( m > 1 and cross( vectorMinus(ans[ m -1 ] , ans [ m - 2 ]), vectorMinus( item , ans [ m - 2 ] )) <= 0 ) : m = m -1
            ans[m] = item
            m = m + 1
        k = m
        flag = True
        data.reverse()
        for item in data:
            if flag :
                flag = False
                continue
            while( m > k and cross( vectorMinus(ans[ m -1 ] , ans [ m - 2 ]), vectorMinus( item , ans [ m - 2 ] )) <= 0) : m = m - 1
            ans [m] = item
            m = m + 1
        m = m -1
        b = [ ans[i] for i in range(0, m)]
        if len(b) < 3 : return 0
        #if DEBUG : print b
        return AREA(b)
    
    def AREA(b):
        ans = 0.0
        for i in range(len(b)):
            if i == 0 or i + 1 >= len(b) : continue
            x , y = b[i] , b[i + 1]
            ans += triangleAre( b[0] , x , y )
        return ans

    转自:http://www.cnblogs.com/shuly/p/5810253.html


    展开全文
  • def cross(A,B): return A[0] * B[1] - A[1] * B[0] def vectorMinus( a , b): return ( (a[0] - b[0] )*1000,(a[1] - b[1] )*1000) def getLTDis( A, B ): ... lon1, lat1, lon2, lat2 = map(ra...
    def cross(A,B):
        return A[0] * B[1] - A[1] * B[0]
    
    def vectorMinus( a , b):
        return ( (a[0] - b[0] )*1000,(a[1] - b[1] )*1000)
    
    def getLTDis( A, B ):
        lon1, lat1, lon2, lat2 = map(radians, [A[0], A[1], B[0], B[1]])
        dlon = lon2 - lon1
        dlat = lat2 - lat1
        a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
        c = 2 * asin(sqrt(a))
        r = 6371.393
        #print A,B
        return c * r * 1000.0
    
    def triangleAre(A,B,C):
        x,y,z = getLTDis(A,B),getLTDis(B,C),getLTDis(C,A)
        c  =  (x + y  + z) /2
        return sqrt((c)*(c-y)*(c-z)*(c-x))
    
    
    def grahamScanArea(data):
        data.sort(key=lambda x:(x[0],x[1]),reverse=False)
        ans = [ 0 ] * (len(data)*2)
        m = 0
        for item in data:
            top = len(item)
            while( m > 1 and cross( vectorMinus(ans[ m -1 ] , ans [ m - 2 ]), vectorMinus( item , ans [ m - 2 ] )) <= 0 ) : m = m -1
            ans[m] = item
            m = m + 1
        k = m
        flag = True
        data.reverse()
        for item in data:
            if flag :
                flag = False
                continue
            while( m > k and cross( vectorMinus(ans[ m -1 ] , ans [ m - 2 ]), vectorMinus( item , ans [ m - 2 ] )) <= 0) : m = m - 1
            ans [m] = item
            m = m + 1
        m = m -1
        b = [ ans[i] for i in range(0, m)]
        if len(b) < 3 : return 0
        #if DEBUG : print b
        return AREA(b)
    
    def AREA(b):
        ans = 0.0
        for i in range(len(b)):
            if i == 0 or i + 1 >= len(b) : continue
            x , y = b[i] , b[i + 1]
            ans += triangleAre( b[0] , x , y )
        return ans

     

    转载于:https://www.cnblogs.com/shuly/p/5810253.html

    展开全文
  • 主要介绍了Python凸包及多边形面积教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • python 解决凸包问题

    千次阅读 2017-02-08 21:48:32
    最近在看python的算法书,之前在年前买的书,一直在工作间隙的时候,学习充电,终于看到这本书,但是确实又有点难,感觉作者写的代码太炫技 了,有时候注释也不怎么能看懂,终于想到一个方法,就是里面说的算法问题...
  • 一般有两种算法来计算平面上给定n个点的凸包:Graham扫描法(Graham"s scan),时间复杂度为O(nlgn);Jarvis步进法(Jarvis march),时间复杂度为O(nh),其中h为凸包顶点的个数。这两种算法都按逆时针方向输出凸包顶点...
  • Python凸包及多边形面积

    千次阅读 2018-08-02 19:17:19
    一般有两种算法来计算平面上给定n个点的凸包:Graham扫描法(Graham’s scan),时间复杂度为O(nlgn);Jarvis步进法(Jarvis march),时间复杂度为O(nh),其中h为凸包顶点的个数。这两种算法都按逆时针方向输出凸包顶点...
  • 图形学可以说经常遇到这东西了,这里给出一个库函数的实现 from scipy.spatial import ConvexHull points = np.random.rand(10, 2) # 30 random points in 2-D hull = ConvexHull(points) import matplotlib.pyplot...
  • 凸包问题是指在n个点中,寻找一个凸多边形,使所有的点在凸多边形的边界或者内部。这是一个很有意思的计算机图形学问题,一种常用的解法是Graham扫描法,运行时间为O(nlgn)。笔者拿processing语言对整个算法过程进行...
  • 凸包问题-python

    2018-11-17 21:42:58
    凸包问题的python解决,输出围成凸包的边并绘制凸包图片。点集可以自己输入或者随机生成。 随手写的程序脚本,不喜勿喷
  • 文章目录什么是凸包 什么是凸包 凸包与轮廓近似相似,但不同,虽然有些情况下它们给出的结果是一样的。函数cv2.convexHull()可以用来检测一个曲线是否具有凸性缺陷,并能纠正缺陷。一般来说,凸性曲线总是凸出来的,...
  • python opencv 凸包

    2020-11-13 21:53:15
    # 轮廓发现 contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in range(len(contours)): # 是否为凸包 ret = cv2.isContourConvex(contours[c]) if not ret: # ...
  • 凸包python实现

    千次阅读 2013-08-05 13:05:27
    # -*- coding: utf-8 -*- import turtle import random import time f=open('point.txt','w') for i in range(100):  x=random.randrange(-250,250,10)  y=random.randrange(-200,200,10)  f.write
  • P.S.matlab有自带的函数python也有非常好的课件https://wenku.baidu.com/view/8c83928eec3a87c24028c49f.html简略解法和基本概念https://www.cnblogs.com/xzyxzy/p/10225804.html具体实现...
  • python写Graham没有c++那么好写,但是python画图简单。只需要用matplotlib里的pyplot,c++画图太难了。 Graham算法写起来比较简单,只需要想办法对最小点和其他的点所连成的直线,与x轴正半轴的夹角进行排序,然后...
  • 起语法结构如下,例如我们定义一个求平方函数和一个没有 返回值的函数:def square(x):return x**2def helloworld():print('Hello World')其中参数和返回值可以为空, 实际上Python传入值和返回值都是None,但是函数...
  • #include #include #include #include #include #include #include using namespace std;#define PR 1e-8#define N 510struct TPoint{double x, y, z;TPoint(){}TPoint(double _x, double _y, double _z):x(_x), y(_...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 209
精华内容 83
关键字:

python凸包

python 订阅