blendercam/scripts/addons/cam/polygon_utils_cam.py

264 wiersze
5.6 KiB
Python

import math
from math import *
import mathutils
from mathutils import *
import curve_simplify
import Polygon
try:
import shapely
from shapely.geometry import polygon as spolygon
from shapely import ops
from shapely import geometry
SHAPELY=True
except:
SHAPELY=False
def Polygon2Shapely(p):
conts=[]
sp=geometry.Polygon()
holes=[]
contours=[]
#print(len(p))
#print(p)
for ci,c in enumerate(p):
#print(ci)
shapely_p=spolygon.Polygon(c)
if p.nPoints(ci)>2 and shapely_p.is_valid:
if p.isHole(ci):
#print('ishole')
holes.append(shapely_p)
else:
contours.append(shapely_p)
#for c in contours:
#sp=sp.union(spolygon.Polygon(c)
sp=shapely.ops.unary_union(contours)
for h in holes:
sp=sp.difference(h)
#sp=geometry.asMultiPolygon(conts)
#sp=ops.cascaded_union(sp)
return sp
def Shapely2Polygon(sp):
gt=sp.geometryType()
p=Polygon.Polygon()
if gt=='Polygon':
if sp.exterior!=None:
p.addContour(sp.exterior.coords,False)
for sc in sp.interiors:
p.addContour(sc.coords,True)
else:
p=Polygon.Polygon()
for spsub in sp:
p.addContour(spsub.exterior.coords,False)
for sc in spsub.interiors:
p.addContour(sc.coords,True)
return p
def Circle(r,np):
c=[]
pi=math.pi
v=mathutils.Vector((r,0,0))
e=mathutils.Euler((0,0,2.0*pi/np))
for a in range(0,np):
c.append((v.x,v.y))
v.rotate(e)
p=Polygon.Polygon(c)
return p
def nRect(l,r):
s=((-l/2.0,-r/10.0),(l/2.0,-r/10.0),(l/2.0,r),(-l/2,r))
r= Polygon.Polygon(s)
return r
def getLength(p,i=None):#i is contour index
if i==None:
contours=p
else:
contours=[p[i]]
length=0.0
for c in contours:
for vi,v1 in enumerate(c):
#print(len(self.points),vi)
v2=Vector(v1)#this is for case of last point and not closed chunk..
if vi==len(c)-1:
v2=Vector(c[0])
else:
v2=Vector(c[vi+1])
v1=Vector(v1)
v=v2-v1
length+=v.length
return length
def polyRemoveDoubles(p,optimize_threshold):
#vecs=[]
pnew=Polygon.Polygon()
soptions=['distance','distance',0.0,5,optimize_threshold,5,optimize_threshold]
for ci,c in enumerate(p):# in range(0,len(p)):
veclist=[]
for v in c:
veclist.append(Vector((v[0],v[1])))
#progress(len(veclist))
s=curve_simplify.simplify_RDP(veclist, soptions)
#progress(len(s))
nc=[]
for i in range(0,len(s)):
nc.append(c[s[i]])
if len(nc)>2:
pnew.addContour(nc,p.isHole(ci))
else:
pnew.addContour(p[ci],p.isHole(ci))
#progress(time.time()-t)
return pnew
def outlinePoly(p,r,circle_detail,optimize,optimize_threshold,offset = True):
'''offsets or insets polygon by radius'''
#t=Polygon.getTolerance()
#e=0.0001
#Polygon.setTolerance(e)
vref=mathutils.Vector((1,0))
#p.simplify()
#print(p)
if p.nPoints()>2:
if SHAPELY:
sp=Polygon2Shapely(p)
if not offset:
r=-r
sp=sp.buffer(r)
pr=Shapely2Polygon(sp)
'''
sp=spolygon.Polygon()
for ci,c in enumerate(p):
hole=p.isHole(ci)
nsp=Polygon2Shapely(Polygon.Polygon(c))
if not offset:
r=-r
if hole:
r=-r
nsp=nsp.buffer(r)
if hole:
sp=sp.difference(nsp)
else:
sp=sp.union(nsp)
pr=Shapely2Polygon(sp)
'''
else:
ci=0
pr=Polygon.Polygon()
pr = Polygon.Polygon(p)#try a copy instead pr+p#TODO fix this. this probably ruins depth in outlines! should add contours instead, or do a copy
circle=Circle(r,circle_detail)
polygons=[]
for c in p:
if len(c)>2:
hole=p.isHole(ci)
orientation=p.orientation(ci)
vi=0
clen=p.nPoints(ci)
for v in c:
v1=mathutils.Vector(v)
if vi>0:
v2=mathutils.Vector(c[vi-1])
else:
v2=mathutils.Vector(c[-1])
if vi<clen-1:
v3=mathutils.Vector(c[vi+1])
else:
v3= mathutils.Vector(c[0])
vect=v1-v2
fo=v1+(v2-v1)/2.0
rect=nRect(vect.length,r)
rr=0.0
if not offset:
rr=math.pi
if (orientation==-1 and hole) or (orientation==1 and not hole):
rr+=math.pi
if vect.length>0:
rect.rotate(vect.angle_signed(vref)+rr,0.0,0.0)
rect.shift(fo[0],fo[1])
# this merges the rect with 1 circle and is actually faster... probably because it reduces the circle.
#TODO: implement proper arcs here, to save computation time , and avoid tiny bugs..
circle.shift(v[0],v[1])
shape=rect+circle
circle.shift(-v[0],-v[1])
if offset:
pr=pr+shape
else:
pr=pr-shape
vi+=1
ci+=1
#pr.simplify()
#Polygon.setTolerance(e)
if pr.nPoints()>2:
if optimize:
pr=polyRemoveDoubles(pr,optimize_threshold)
p=pr
return p
def polyToMesh(name,p,z):
import bpy,bmesh
from bpy_extras import object_utils
verts=[]
edges=[]
vi=0
ci=0
for c in p:
vi0=vi
ei=0
clen=p.nPoints(ci)
for v in c:
verts.append((v[0],v[1],z))
if ei>0:
edges.append((vi-1,vi))
if ei==clen-1:
edges.append((vi,vi0))
vi+=1
ei+=1
ci+=1
mesh = bpy.data.meshes.new("test")
bm = bmesh.new()
for v_co in verts:
bm.verts.new(v_co)
for e in edges:
bm.edges.new((bm.verts[e[0]],bm.verts[e[1]]))
bm.to_mesh(mesh)
mesh.update()
object_utils.object_data_add(bpy.context, mesh)
ob=bpy.context.active_object
ob.name=name
ob.location=(0,0,0)
bpy.ops.object.convert(target='CURVE')
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
return bpy.context.active_object