简单随机多边形切割方案

过程化处理中希望能够对某块区域生成随机多边形,以及再切割成子多边形
各种尝试之后发现一种通过python、turtle、pyclipper实现的简单方案

随机多边形

采用python直接生成随机多边形,算法原理:将360度随机拆分成各个角度,再通过随机半径连接起来

def get_random_poly(num_vertices, bounds):
    radii=[]
    for i in range(num_vertices):
        radii.append(random.uniform(0.5,1.0))
    min_weight=1.0
    max_weight=10.0
    total_weight=0.0
    angle_weights=[]
    for i in range(num_vertices):
        angle_weights.append(random.uniform(min_weight,max_weight))
        total_weight+=angle_weights[-1]
    angles=[]
    for angle_weight in angle_weights:
        angles.append(angle_weight*2*math.pi/total_weight)
    rx=(bounds[1][0]-bounds[0][0])/2
    ry=(bounds[1][1]-bounds[0][1])/2
    cx=bounds[0][0]+rx
    cy=bounds[0][1]+ry
    points=[]
    theta=0.0
    for i in range(num_vertices):
        points.append((
            cx+rx*radii[i]*math.cos(theta),
            cy+ry*radii[i]*math.sin(theta)))
        theta+=angles[i]
    return points

生成用以拆分多边形的矩形

采用中心点、法线矢量的方式生成

def get_perpendicular_rect(c,pn,hl,hw):
    p0=(c[0]+pn[1]*hl,c[1]-pn[0]*hl)
    p1=(c[0]-pn[1]*hl,c[1]+pn[0]*hl)
    rect=[]
    rect.append((p0[0]+pn[0]*hw,p0[1]+pn[1]*hw))
    rect.append((p0[0]-pn[0]*hw,p0[1]-pn[1]*hw))
    rect.append((p1[0]-pn[0]*hw,p1[1]-pn[1]*hw))
    rect.append((p1[0]+pn[0]*hw,p1[1]+pn[1]*hw))
    return rect

拆分多边形

采用pyclipper库实现任意多边形拆分,算法原型是Vatti clipping
这里采用递归的方式分割子多边形,直到面积小于指定值

import turtle
import random
import math
import pyclipper
...
# 计算多边形中心点
def get_poly_center(poly):
    c=[0,0]
    for p in poly:
        c[0]+=p[0]
        c[1]+=p[1]
    c[0]/=len(poly)
    c[1]/=len(poly)
    return c
    
# 计算两点距离的sqrt
def get_distsq(p0,p1):
    d=(p1[0]-p0[0],p1[1]-p0[1])
    return d[0]*d[0]+d[1]*d[1]
    
# 获取多边形中最远的点
def get_furthest_point(poly):
    c=get_poly_center(poly)
    f=poly[0]
    sq=get_distsq(c,f)
    for i in range(1,len(poly)):
        sq2=get_distsq(c,poly[i])
        if sq2>sq:
            sq=sq2
            f=poly[i]
    return c,f

# 计算多边形面积,正负可用来判定多边形矢量方向
def get_poly_area(poly):
    area=0
    v0=poly[0]
    v1=poly[1]
    for i in range(2,len(poly)):
        v2=poly[i]
        area+=(v1[0]-v0[0])*(v2[1]-v0[1])-(v1[1]-v0[1])*(v2[0]-v0[0])
        v1=v2
    return area*0.5

# 递归分割多边形,maxarea为最小不可分割面积
def clip_poly(poly,hl,hw,maxarea):
    ret=[]
    c,f=get_furthest_point(poly)
    d=[f[0]-c[0],f[1]-c[1]]
    l=math.sqrt(d[0]*d[0]+d[1]*d[1])
    d[0]/=l
    d[1]/=l
    pc=pyclipper.Pyclipper()
    pc.AddPath(poly,pyclipper.PT_SUBJECT,True)
    pc.AddPath(get_perpendicular_rect(c,d,hl,hw),pyclipper.PT_CLIP,True)
    for r in pc.Execute(pyclipper.CT_DIFFERENCE,pyclipper.PFT_EVENODD,pyclipper.PFT_EVENODD):
        area=get_poly_area(r)
        if area>=0:
            r.reverse()
        if math.fabs(area)<=maxarea:
            ret.append(r)
        else:
            reg=clip_poly(r,hl,hw,maxarea)
            for r2 in reg:
                ret.append(r2)
    return ret

通过turtle工具将切割效果显示出来

这里要注意turtle坐标中心点位于画布中央,x轴正向朝右,y轴正向朝上

...
# 利用鼠标点击事件可多次查看分割效果
def onmouseclick(x,y):
    radius=100
    poly=get_random_poly(10, ((x-radius,y-radius),(x+radius,y+radius)))
    reg=clip_poly(poly,900,3,300)
    for poly in reg:
        poly.append(poly[0])
        for p in poly:
            turtle.goto(p)
            turtle.down()
        turtle.up()

# python主程序入口
if __name__=='__main__':
    ts=turtle.getscreen()
    ts.onclick(onmouseclick)
    turtle.up()
    # 设置随机种子用以固定每次生成的结果
    random.seed(3)
    onmouseclick(0,0)
    turtle.done()

最终效果

在这里插入图片描述

参考

https://blog.csdn.net/bby1987/article/details/108858785
https://blog.csdn.net/qq_25737169/article/details/113843872
https://blog.csdn.net/ithiker/article/details/127712621

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值