kopia lustrzana https://github.com/vilemduha/blendercam
Shapely replaces Polygon Library - BIG COMMIT
this commit might brake stuff, but it was very needed, to eradicate the old and not updated Polygon Library with the Shapely lib, which gets developed more actively. Lots of functions changed, but so far, things look good, so I commit. Polishing and deleting old functions come after this.pull/7/merge
rodzic
a1114f0d5b
commit
46ac43eaa5
|
|
@ -3,8 +3,8 @@ import Polygon
|
|||
import shapely
|
||||
from shapely.geometry import polygon as spolygon
|
||||
from shapely import ops
|
||||
from shapely import geometry
|
||||
|
||||
from shapely import geometry as sgeometry
|
||||
from cam import polygon_utils_cam
|
||||
from cam import simple
|
||||
from cam.simple import *
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ class camPathChunk:
|
|||
#self.unsortedchildren=False
|
||||
# return self
|
||||
|
||||
def getNextClosest(self,o,pos):#this should be deprecated after reworking sortchunks a bit
|
||||
def getNextClosest(self,o,pos):
|
||||
mind=100000000000
|
||||
|
||||
self.cango=False
|
||||
|
|
@ -155,10 +155,10 @@ class camPathChunk:
|
|||
ch=chtest
|
||||
mind=d
|
||||
if ch!=None:
|
||||
print('found some')
|
||||
#print('found some')
|
||||
return ch
|
||||
#self.unsortedchildren=False
|
||||
print('returning none')
|
||||
#print('returning none')
|
||||
return None
|
||||
|
||||
|
||||
|
|
@ -540,7 +540,7 @@ def limitChunks(chunks,o, force=False):#TODO: this should at least add point on
|
|||
nch1=nch
|
||||
closed=True
|
||||
for s in ch.points:
|
||||
sampled=o.ambient.isInside(s[0],s[1])
|
||||
sampled=o.ambient.contains(sgeometry.Point(s[0],s[1]))
|
||||
if not sampled and len(nch.points)>0:
|
||||
nch.closed=False
|
||||
closed=False
|
||||
|
|
@ -569,8 +569,8 @@ def parentChildPoly(parents,children,o):
|
|||
#print(parent.poly)
|
||||
for child in children:
|
||||
#print(child.poly)
|
||||
if child!=parent and len(child.poly)>0:
|
||||
if parent.poly.isInside(child.poly[0][0][0],child.poly[0][0][1]):
|
||||
if child!=parent:# and len(child.poly)>0
|
||||
if parent.poly.contains(sgeometry.Point(child.poly.boundary.coords[0])):
|
||||
parent.children.append(child)
|
||||
child.parents.append(parent)
|
||||
|
||||
|
|
@ -610,7 +610,7 @@ def parentChild(parents, children, o):
|
|||
if parent!=child:
|
||||
parent.children.append(child)
|
||||
child.parents.append(parent)
|
||||
|
||||
'''
|
||||
def chunksToShapely(chunks):#this does more cleve chunks to Poly with hierarchies... ;)
|
||||
#print ('analyzing paths')
|
||||
#verts=[]
|
||||
|
|
@ -631,6 +631,73 @@ def chunksToShapely(chunks):#this does more cleve chunks to Poly with hierarchie
|
|||
returnpolys.append(ch.poly)
|
||||
#print(len(returnpolys))
|
||||
return returnpolys
|
||||
'''
|
||||
|
||||
def chunksToShapely(chunks):#this does more cleve chunks to Poly with hierarchies... ;)
|
||||
#print ('analyzing paths')
|
||||
#verts=[]
|
||||
#pverts=[]
|
||||
polys=[]
|
||||
for ch in chunks:#first convert chunk to poly
|
||||
if len(ch.points)>2:
|
||||
pchunk=[]
|
||||
ch.poly=sgeometry.Polygon(ch.points)
|
||||
|
||||
for ppart in chunks:#then add hierarchy relations
|
||||
for ptest in chunks:
|
||||
|
||||
#if ppart!=ptest and len(ptest.poly)>0 and len(ppart.poly)>0 and ptest.poly.nPoints(0)>0 and ppart.poly.nPoints(0)>0:
|
||||
if ppart!=ptest :
|
||||
if ptest.poly.contains(ppart.poly):
|
||||
#hierarchy works like this: - children get milled first.
|
||||
#ptest.children.append(ppart)
|
||||
ppart.parents.append(ptest)
|
||||
|
||||
|
||||
for ch in chunks:#now make only simple polygons with holes, not more polys inside others
|
||||
#print(len(chunks[polyi].parents))
|
||||
found=False
|
||||
if len(ch.parents)%2==1:
|
||||
|
||||
for parent in ch.parents:
|
||||
if len(parent.parents)+1==len(ch.parents):
|
||||
ch.nparents=[parent]#nparents serves as temporary storage for parents, not to get mixed with the first parenting during the check
|
||||
found=True
|
||||
break
|
||||
|
||||
if not found:
|
||||
ch.nparents=[]
|
||||
|
||||
for ch in chunks:#then subtract the 1st level holes
|
||||
ch.parents=ch.nparents
|
||||
ch.nparents=None
|
||||
if len(ch.parents)>0:
|
||||
#print(len(ch.parents))
|
||||
#ch.parents[0].poly=ch.parents[0].poly-ch.poly
|
||||
#print(ch.parents[0].poly,[ch.poly])
|
||||
print('addparent')
|
||||
#polygon_utils_cam.shapelyToCurve('crust',ch.parents[0].poly,0)
|
||||
#polygon_utils_cam.shapelyToCurve('hole',ch.poly,0)
|
||||
ch.parents[0].poly = ch.parents[0].poly.difference(ch.poly)#sgeometry.Polygon( ch.parents[0].poly, ch.poly)
|
||||
|
||||
|
||||
returnpolys=[]
|
||||
|
||||
for polyi in range(0,len(chunks)):#export only the booleaned polygons
|
||||
ch=chunks[polyi]
|
||||
if len(ch.parents)==0:
|
||||
#ch.poly.simplify()#TODO:THIS CHECK
|
||||
returnpolys.append(ch.poly)
|
||||
#if len(ch.poly.interiors)>0:
|
||||
# print(ch.poly.interiors[0].coords[0])
|
||||
#polygon_utils_cam.shapelyToCurve('test',ch.poly,0)
|
||||
#print(ch.poly.boundary)
|
||||
print('shapely hierarchies')
|
||||
#print(len(returnpolys))
|
||||
|
||||
|
||||
return returnpolys
|
||||
|
||||
|
||||
def chunksToPolys(chunks):#this does more cleve chunks to Poly with hierarchies... ;)
|
||||
#print ('analyzing paths')
|
||||
|
|
@ -734,6 +801,7 @@ def meshFromCurveToChunk(object):
|
|||
chunk.points.append((mesh.vertices[lastvi].co.x+x,mesh.vertices[lastvi].co.y+y,mesh.vertices[lastvi].co.z+z))
|
||||
#else:
|
||||
# print('itisnot')
|
||||
|
||||
chunks.append(chunk)
|
||||
return chunks
|
||||
|
||||
|
|
@ -816,6 +884,32 @@ def polyToChunks(p,zlevel):#
|
|||
#
|
||||
return chunks
|
||||
|
||||
def shapelyToChunks(p,zlevel):#
|
||||
chunks=[]
|
||||
#p=sortContours(p)
|
||||
seq=polygon_utils_cam.shapelyToCoords(p)
|
||||
i=0
|
||||
for s in seq:
|
||||
#progress(p[i])
|
||||
if len(s)>2:
|
||||
chunk=camPathChunk([])
|
||||
chunk.poly=spolygon.Polygon(s)#this should maybe be LineString? but for sorting, we need polygon inside functions.
|
||||
for v in s:
|
||||
#progress (v)
|
||||
|
||||
if len(v)>2:
|
||||
chunk.points.append((v[0],v[1],v[2]))
|
||||
else:
|
||||
chunk.points.append((v[0],v[1],zlevel))
|
||||
|
||||
chunk.points.append((chunk.points[0][0],chunk.points[0][1],chunk.points[0][2]))#last point =first point
|
||||
chunk.closed=True
|
||||
chunks.append(chunk)
|
||||
i+=1
|
||||
chunks.reverse()#this is for smaller shapes first.
|
||||
#
|
||||
return chunks
|
||||
|
||||
def chunkToPoly(chunk):
|
||||
pverts=[]
|
||||
|
||||
|
|
@ -826,6 +920,16 @@ def chunkToPoly(chunk):
|
|||
p=Polygon.Polygon(pverts)
|
||||
return p
|
||||
|
||||
def chunkToShapely(chunk):
|
||||
#pverts=[]
|
||||
|
||||
#for v in chunk.points:
|
||||
|
||||
# pverts.append((v[0],v[1]))
|
||||
|
||||
p=spolygon.Polygon(chunk.points)
|
||||
return p
|
||||
|
||||
def chunksRefine(chunks,o):
|
||||
'''add extra points in between for chunks'''
|
||||
for ch in chunks:
|
||||
|
|
|
|||
|
|
@ -1446,9 +1446,9 @@ def imageToChunks(o,image, with_border=False):
|
|||
else:
|
||||
return []
|
||||
|
||||
def imageToPoly(o,i, with_border=False):
|
||||
def imageToShapely(o,i, with_border=False):
|
||||
polychunks=imageToChunks(o,i, with_border)
|
||||
polys=chunksToPolys(polychunks)
|
||||
polys=chunksToShapely(polychunks)
|
||||
|
||||
#polys=orderPoly(polys)
|
||||
t=time.time()
|
||||
|
|
|
|||
|
|
@ -789,13 +789,13 @@ class CamObjectSilhouete(bpy.types.Operator):
|
|||
def execute(self, context):#this is almost same as getobjectoutline, just without the need of operation data
|
||||
ob=bpy.context.active_object
|
||||
self.silh=utils.getObjectSilhouete('OBJECTS', objects=bpy.context.selected_objects)
|
||||
poly=Polygon.Polygon()
|
||||
for p in self.silh:
|
||||
for ci in range(0,len(p)):
|
||||
poly.addContour(p[ci])
|
||||
#poly=Polygon.Polygon()
|
||||
#for p in self.silh:
|
||||
# for ci in range(0,len(p)):
|
||||
# poly.addContour(p[ci])
|
||||
bpy.context.scene.cursor_location=(0,0,0)
|
||||
polygon_utils_cam.polyToMesh(ob.name+'_silhouette',poly,0)#
|
||||
bpy.ops.object.convert(target='CURVE')
|
||||
polygon_utils_cam.shapelyToCurve(ob.name+'_silhouette',self.silh,0)#
|
||||
#bpy.ops.object.convert(target='CURVE')
|
||||
bpy.context.scene.cursor_location=ob.location
|
||||
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
|
||||
return {'FINISHED'}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ from cam.simple import *
|
|||
from cam.chunk import *
|
||||
from cam import polygon_utils_cam
|
||||
from cam.polygon_utils_cam import *
|
||||
import shapely
|
||||
from shapely import geometry as sgeometry
|
||||
|
||||
def getPathPatternParallel(o,angle):
|
||||
#minx,miny,minz,maxx,maxy,maxz=o.min.x,o.min.y,o.min.z,o.max.x,o.max.y,o.max.z
|
||||
|
|
@ -324,8 +326,9 @@ def getPathPattern(operation):
|
|||
pathchunks=[]
|
||||
chunks=[]
|
||||
for p in polys:
|
||||
p=outlinePoly(p,o.dist_between_paths/3,o.circle_detail,o.optimize,o.optimize_threshold,False)#first, move a bit inside, because otherwise the border samples go crazy very often changin between hit/non hit and making too many jumps in the path.
|
||||
chunks.extend(polyToChunks(p,0))
|
||||
#p=outlinePoly(p,o.dist_between_paths/3,o.circle_detail,o.optimize,o.optimize_threshold,False)#first, move a bit inside, because otherwise the border samples go crazy very often changin between hit/non hit and making too many jumps in the path.
|
||||
p=p.buffer(-o.dist_between_paths/3,o.circle_detail)#first, move a bit inside, because otherwise the border samples go crazy very often changin between hit/non hit and making too many jumps in the path.
|
||||
chunks.extend(shapelyToChunks(p,0))
|
||||
|
||||
pathchunks.extend(chunks)
|
||||
lastchunks=chunks
|
||||
|
|
@ -340,10 +343,11 @@ def getPathPattern(operation):
|
|||
|
||||
for porig in polys:
|
||||
p=porig
|
||||
while p.nPoints()>0:
|
||||
p=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,False)
|
||||
if p.nPoints()>0:
|
||||
nchunks=polyToChunks(p,zlevel)
|
||||
while not p.is_empty:#:p.nPoints()>0:
|
||||
#p=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,False)
|
||||
p=p.buffer(-o.dist_between_paths,o.circle_detail)
|
||||
if not p.is_empty:
|
||||
nchunks=shapelyToChunks(p,zlevel)
|
||||
#parentChildPoly(lastchunks,nchunks,o)
|
||||
pathchunks.extend(nchunks)
|
||||
lastchunks=nchunks
|
||||
|
|
@ -362,9 +366,10 @@ def getPathPattern(operation):
|
|||
dist+=o.pixsize*0.85# this is here only because silhouette is still done with zbuffer method, even if we use bullet collisions.
|
||||
else:
|
||||
dist+=o.pixsize*2.5
|
||||
p=outlinePoly(p,dist,o.circle_detail,o.optimize,o.optimize_threshold,True)
|
||||
if p.nPoints()>0:
|
||||
chunks=polyToChunks(p,zlevel)
|
||||
p=p.buffer(dist,o.circle_detail)
|
||||
#p=outlinePoly(p,dist,o.circle_detail,o.optimize,o.optimize_threshold,True)
|
||||
if not p.is_empty:
|
||||
chunks=shapelyToChunks(p,zlevel)
|
||||
pathchunks.extend(chunks)
|
||||
lastchunks=chunks
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import Polygon
|
|||
import shapely
|
||||
from shapely.geometry import polygon as spolygon
|
||||
from shapely import ops
|
||||
from shapely import geometry
|
||||
from shapely import geometry as sgeometry
|
||||
SHAPELY=True
|
||||
#except:
|
||||
# SHAPELY=False
|
||||
|
|
@ -17,7 +17,7 @@ SHAPELY=True
|
|||
|
||||
def Polygon2Shapely(p):
|
||||
conts=[]
|
||||
sp=geometry.Polygon()
|
||||
sp=sgeometry.Polygon()
|
||||
holes=[]
|
||||
contours=[]
|
||||
#print(len(p))
|
||||
|
|
@ -39,7 +39,7 @@ def Polygon2Shapely(p):
|
|||
for h in holes:
|
||||
sp=sp.difference(h)
|
||||
|
||||
#sp=geometry.asMultiPolygon(conts)
|
||||
#sp=sgeometry.asMultiPolygon(conts)
|
||||
#sp=ops.cascaded_union(sp)
|
||||
return sp
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ def Circle(r,np):
|
|||
c.append((v.x,v.y))
|
||||
v.rotate(e)
|
||||
|
||||
p=Polygon.Polygon(c)
|
||||
p=spolygon.Polygon(c)
|
||||
return p
|
||||
|
||||
def nRect(l,r):
|
||||
|
|
@ -264,6 +264,53 @@ def polyToMesh(name,p,z):
|
|||
|
||||
return bpy.context.active_object
|
||||
|
||||
def shapelyToCoords(anydata):
|
||||
p=anydata
|
||||
seq=[]
|
||||
#print(p.type)
|
||||
#print(p.geom_type)
|
||||
if p.is_empty:
|
||||
return seq
|
||||
elif p.type=='Polygon':
|
||||
|
||||
#print('polygon')
|
||||
clen=len(p.exterior.coords)
|
||||
#seq = sgeometry.asMultiLineString(p)
|
||||
seq=[p.exterior.coords]
|
||||
#print(len(p.interiors))
|
||||
for interior in p.interiors:
|
||||
seq.append(interior.coords)
|
||||
elif p.type=='MultiPolygon':
|
||||
clen=0
|
||||
seq=[]
|
||||
for sp in p:
|
||||
clen+=len(sp.exterior.coords)
|
||||
seq.append(sp.exterior.coords)
|
||||
for interior in sp.interiors:
|
||||
seq.append(interior.coords)
|
||||
|
||||
elif p.type=='MultiLineString':
|
||||
seq=[]
|
||||
for linestring in p:
|
||||
seq.append(linestring.coords)
|
||||
elif p.type=='MultiPoint':
|
||||
return;
|
||||
elif p.type=='GeometryCollection':
|
||||
#print(dir(p))
|
||||
#print(p.geometryType, p.geom_type)
|
||||
clen=0
|
||||
seq=[]
|
||||
#print(p.boundary.coordsd)
|
||||
for sp in p:
|
||||
clen+=len(sp.exterior.coords)
|
||||
seq.append(sp.exterior.coords)
|
||||
for interior in sp.interiors:
|
||||
seq.extend(interior.coords)
|
||||
#for g in p.geom:
|
||||
# print(g.type)
|
||||
|
||||
return seq
|
||||
|
||||
def shapelyToCurve(name,p,z):
|
||||
import bpy,bmesh
|
||||
from bpy_extras import object_utils
|
||||
|
|
@ -274,24 +321,7 @@ def shapelyToCurve(name,p,z):
|
|||
#for c in p.exterior.coords:
|
||||
|
||||
print(p.type)
|
||||
if p.type=='Polygon':
|
||||
clen=len(p.exterior.coords)
|
||||
seq=[p.exterior.coords]
|
||||
if p.type=='MultiPolygon':
|
||||
clen=0
|
||||
seq=[]
|
||||
for sp in p:
|
||||
clen+=len(sp.exterior.coords)
|
||||
seq.append(sp.exterior.coords)
|
||||
|
||||
|
||||
elif p.type=='MultiLineString':
|
||||
seq=[]
|
||||
for linestring in p:
|
||||
seq.append(linestring.coords)
|
||||
elif p.type=='MultiPoint':
|
||||
return;
|
||||
|
||||
seq = shapelyToCoords(p)
|
||||
w = 1 # weight
|
||||
|
||||
|
||||
|
|
@ -312,7 +342,7 @@ def shapelyToCurve(name,p,z):
|
|||
|
||||
return objectdata#bpy.context.active_object
|
||||
|
||||
|
||||
'''#outdated?
|
||||
def orderPoly(polys): #sor poly, do holes e.t.c.
|
||||
p=Polygon.Polygon()
|
||||
levels=[[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
|
||||
|
|
@ -345,4 +375,5 @@ def orderPoly(polys): #sor poly, do holes e.t.c.
|
|||
p.simplify()
|
||||
li+=1
|
||||
|
||||
return p
|
||||
return p
|
||||
'''
|
||||
|
|
@ -55,14 +55,13 @@ from cam.image_utils import *
|
|||
from . import nc
|
||||
from cam.opencamlib.opencamlib import oclSample, oclSamplePoints, oclResampleChunks, oclGetWaterline
|
||||
|
||||
try:
|
||||
from shapely.geometry import polygon as spolygon
|
||||
from shapely import ops as sops
|
||||
from shapely import geometry as sgeometry
|
||||
#from shapely.geometry import * not possible until Polygon libs gets out finally..
|
||||
SHAPELY=True
|
||||
except:
|
||||
SHAPELY=False
|
||||
|
||||
from shapely.geometry import polygon as spolygon
|
||||
from shapely import ops as sops
|
||||
from shapely import geometry as sgeometry
|
||||
from shapely import affinity
|
||||
#from shapely.geometry import * not possible until Polygon libs gets out finally..
|
||||
SHAPELY=True
|
||||
|
||||
def positionObject(operation):
|
||||
ob=bpy.data.objects[operation.object_name]
|
||||
|
|
@ -394,7 +393,7 @@ def sampleChunks(o,pathSamples,layers):
|
|||
n+=1
|
||||
x=s[0]
|
||||
y=s[1]
|
||||
if not o.ambient.isInside(x,y):
|
||||
if not o.ambient.contains(sgeometry.Point(x,y)):
|
||||
newsample=(x,y,1)
|
||||
else:
|
||||
if o.use_opencamlib and o.use_exact:
|
||||
|
|
@ -1335,16 +1334,23 @@ def silhoueteOffset(context,offset):
|
|||
bpy.context.scene.cursor_location=(0,0,0)
|
||||
ob=bpy.context.active_object
|
||||
if ob.type=='CURVE':
|
||||
plist=curveToPolys(ob)
|
||||
silhs=curveToShapely(ob)
|
||||
else:
|
||||
plist=getObjectSilhouete('OBJECTS',[ob])
|
||||
p=Polygon.Polygon()
|
||||
for p1 in plist:
|
||||
p+=p1
|
||||
p=outlinePoly(p,abs(offset),64,True,abs(offset)*0.002,offset>0)
|
||||
silhs=getObjectSilhouete('OBJECTS',[ob])
|
||||
#for p1 in plist:
|
||||
# p+=p1
|
||||
print(silhs)
|
||||
polys = []
|
||||
mp = sgeometry.MultiPolygon([silhs[0]],silhs[1:])
|
||||
for p in silhs:
|
||||
polys.append(p.buffer(offset, resolution = 64))
|
||||
#mp = mp.buffer(offset,resolution = 64)
|
||||
#p=outlinePoly(p,abs(offset),64,True,abs(offset)*0.002,offset>0)
|
||||
#print(p[0])
|
||||
#p.shift(ob.location.x,ob.location.y)
|
||||
polyToMesh('offset curve',p,ob.location.z)
|
||||
#for p in polys:
|
||||
for s in polys:
|
||||
shapelyToCurve('offset curve',s,ob.location.z)
|
||||
|
||||
|
||||
return {'FINISHED'}
|
||||
|
|
@ -1674,7 +1680,7 @@ def getOperationSilhouete(operation):
|
|||
i = samples > numpy.min(operation.zbuffer_image)#this fixes another numeric imprecision.
|
||||
|
||||
chunks= imageToChunks(operation,i)
|
||||
operation.silhouete=chunksToPolys(chunks)
|
||||
operation.silhouete=chunksToShapely(chunks)
|
||||
#print(operation.silhouete)
|
||||
#this conversion happens because we need the silh to be oriented, for milling directions.
|
||||
else:
|
||||
|
|
@ -1691,7 +1697,7 @@ def getObjectSilhouete(stype, objects=None):
|
|||
for ob in objects:
|
||||
chunks=curveToChunks(ob)
|
||||
allchunks.extend(chunks)
|
||||
silhouete=chunksToPolys(allchunks)
|
||||
silhouete=chunksToShapely(allchunks)
|
||||
|
||||
elif stype=='OBJECTS':
|
||||
totfaces=0
|
||||
|
|
@ -1741,7 +1747,7 @@ def getObjectSilhouete(stype, objects=None):
|
|||
print(time.time()-t)
|
||||
|
||||
t=time.time()
|
||||
silhouete = [polygon_utils_cam.Shapely2Polygon(p)]
|
||||
silhouete = [p]#[polygon_utils_cam.Shapely2Polygon(p)]
|
||||
'''
|
||||
e=0.00001#one hunderth of a millimeter, should be ok.
|
||||
origtol=Polygon.getTolerance()
|
||||
|
|
@ -1793,41 +1799,58 @@ def getAmbient(o):
|
|||
r=o.ambient_radius - m
|
||||
o.ambient = getObjectOutline( r , o , True)# in this method we need ambient from silhouete
|
||||
else:
|
||||
o.ambient=Polygon.Polygon(((o.min.x + m ,o.min.y + m ) , (o.min.x + m ,o.max.y - m ),(o.max.x - m ,o.max.y - m ),(o.max.x - m , o.min.y + m )))
|
||||
#o.ambient=Polygon.Polygon(((o.min.x + m ,o.min.y + m ) , (o.min.x + m ,o.max.y - m ),(o.max.x - m ,o.max.y - m ),(o.max.x - m , o.min.y + m )))
|
||||
#SHAPELY stuff!
|
||||
o.ambient=spolygon.Polygon(((o.min.x + m ,o.min.y + m ) , (o.min.x + m ,o.max.y - m ),(o.max.x - m ,o.max.y - m ),(o.max.x - m , o.min.y + m )))
|
||||
|
||||
if o.use_limit_curve:
|
||||
if o.limit_curve!='':
|
||||
limit_curve=bpy.data.objects[o.limit_curve]
|
||||
polys=curveToPolys(limit_curve)
|
||||
o.limit_poly=Polygon.Polygon()
|
||||
for p in polys:
|
||||
o.limit_poly+=p
|
||||
#polys=curveToPolys(limit_curve)
|
||||
polys = curveToShapely(limit_curve)
|
||||
o.limit_poly=shapely.ops.unary_union(polys)
|
||||
#for p in polys:
|
||||
# o.limit_poly+=p
|
||||
if o.ambient_cutter_restrict:
|
||||
o.limit_poly = outlinePoly(o.limit_poly,o.cutter_diameter/2,o.circle_detail,o.optimize,o.optimize_threshold,offset = False)
|
||||
o.ambient = o.ambient & o.limit_poly
|
||||
#o.limit_poly = outlinePoly(o.limit_poly,o.cutter_diameter/2,o.circle_detail,o.optimize,o.optimize_threshold,offset = False)
|
||||
o.limit_poly = o.limit_poly.buffer(o.cutter_diameter/2,resolution = o.circle_detail)
|
||||
o.ambient = o.ambient.intersection(o.limit_poly)
|
||||
o.update_ambient_tag=False
|
||||
|
||||
def getObjectOutline(radius,o,Offset):#FIXME: make this one operation independent
|
||||
#circle detail, optimize, optimize thresold.
|
||||
|
||||
polygons=getOperationSilhouete(o)
|
||||
outline=Polygon.Polygon()
|
||||
|
||||
i=0
|
||||
#print('offseting polygons')
|
||||
|
||||
if Offset:
|
||||
offset=1
|
||||
else:
|
||||
offset=-1
|
||||
|
||||
outlines=[]
|
||||
for p in polygons:#sort by size before this???
|
||||
|
||||
|
||||
i=0
|
||||
#print(polygons, polygons.type)
|
||||
for p1 in polygons:#sort by size before this???
|
||||
print(p1.type,len(polygons))
|
||||
i+=1
|
||||
if radius>0:
|
||||
p=outlinePoly(p,radius,o.circle_detail,o.optimize,o.optimize_threshold*0.000001,Offset)
|
||||
|
||||
if o.dont_merge:
|
||||
for ci in range(0,len(p)):
|
||||
outline.addContour(p[ci],p.isHole(ci))
|
||||
else:
|
||||
#print(p)
|
||||
outline=outline+p
|
||||
#p=outlinePoly(p,radius,o.circle_detail,o.optimize,o.optimize_threshold*0.000001,Offset)
|
||||
p1 = p1.buffer(radius*offset,resolution = o.circle_detail)
|
||||
outlines.append(p1)
|
||||
|
||||
print(outlines)
|
||||
if o.dont_merge:
|
||||
outline=sgeometry.MultiPolygon(outlines)
|
||||
#for ci in range(0,len(p)):
|
||||
# outline.addContour(p[ci],p.isHole(ci))
|
||||
else:
|
||||
#print(p)
|
||||
outline=shapely.ops.unary_union(outlines)
|
||||
#outline = sgeometry.MultiPolygon([outline])
|
||||
shapelyToCurve('oboutline',outline,0)
|
||||
return outline
|
||||
|
||||
def addOrientationObject(o):
|
||||
|
|
@ -2039,6 +2062,7 @@ def addAutoBridges(o):
|
|||
|
||||
if ob.type=='CURVE':
|
||||
sply = curveToShapely(ob)
|
||||
|
||||
mw=ob.matrix_world
|
||||
for c in ob.data.splines:
|
||||
blength = o.cutter_diameter*1
|
||||
|
|
@ -2289,7 +2313,7 @@ def getPath3axis(context,operation):
|
|||
#print(ch.points)
|
||||
|
||||
if len(ch.points)>2:
|
||||
ch.poly=chunkToPoly(ch)
|
||||
ch.poly=chunkToShapely(ch)
|
||||
#p.addContour(ch.poly)
|
||||
else:
|
||||
chunksFromCurve=[]
|
||||
|
|
@ -2300,14 +2324,16 @@ def getPath3axis(context,operation):
|
|||
offset=True
|
||||
if o.cut_type=='INSIDE':
|
||||
offset=False
|
||||
|
||||
p=getObjectOutline(o.cutter_diameter/2,o,offset)
|
||||
if o.outlines_count>1:
|
||||
for i in range(1,o.outlines_count):
|
||||
chunksFromCurve.extend(polyToChunks(p,-1))
|
||||
p=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offset)
|
||||
chunksFromCurve.extend(shapelyToChunks(p,-1))
|
||||
p = p.buffer(distance = o.dist_between_paths * offset, resolution = o.circle_detail)
|
||||
#p=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offset)
|
||||
|
||||
|
||||
chunksFromCurve.extend(polyToChunks(p,-1))
|
||||
chunksFromCurve.extend(shapelyToChunks(p,-1))
|
||||
if o.outlines_count>1 and o.movement_insideout=='OUTSIDEIN':
|
||||
chunksFromCurve.reverse()
|
||||
#parentChildPoly(chunksFromCurve,chunksFromCurve,o)
|
||||
|
|
@ -2492,41 +2518,43 @@ def getPath3axis(context,operation):
|
|||
|
||||
if o.strategy=='POCKET':
|
||||
p=getObjectOutline(o.cutter_diameter/2,o,False)
|
||||
all=Polygon.Polygon(p)
|
||||
#all=Polygon.Polygon(p)
|
||||
approxn=(min(o.max.x-o.min.x,o.max.y-o.min.y)/o.dist_between_paths)/2
|
||||
i=0
|
||||
chunks=[]
|
||||
chunksFromCurve=[]
|
||||
lastchunks=[]
|
||||
centers=None
|
||||
while len(p)>0:
|
||||
nchunks=polyToChunks(p,o.min.z)
|
||||
#shapelyToCurve('testik',p,0)
|
||||
while not p.is_empty:
|
||||
nchunks=shapelyToChunks(p,o.min.z)
|
||||
nchunks=limitChunks(nchunks,o)
|
||||
chunksFromCurve.extend(nchunks)
|
||||
parentChildDist(lastchunks,nchunks,o)
|
||||
lastchunks=nchunks
|
||||
|
||||
pnew=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,False)
|
||||
pnew=p.buffer(-o.dist_between_paths,o.circle_detail)
|
||||
#pnew=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,False)
|
||||
|
||||
if o.dist_between_paths>o.cutter_diameter/2.0:#this mess under this IF condition is here ONLY because of the ability to have stepover> than cutter radius. Other CAM softwares don't allow this at all, maybe because of this mathematical problem and performance cost, but into soft materials, this is good to have.
|
||||
o.warnings=o.warnings+'Distance between paths larger\n than cutter radius can result in uncut areas!\n '
|
||||
|
||||
contours_before=len(p)
|
||||
contours_before=len(p.boundary)
|
||||
|
||||
if centers==None:
|
||||
centers=[]
|
||||
for ci in range(0,len(p)):
|
||||
centers.append(p.center(ci))
|
||||
contours_after=len(pnew)
|
||||
for p in range(0,len(p)):
|
||||
centers.append(p.centroid())
|
||||
contours_after=len(pnew.boundary)
|
||||
newcenters=[]
|
||||
|
||||
do_test=False
|
||||
for ci in range(0,len(pnew)):
|
||||
newcenters.append(pnew.center(ci))
|
||||
|
||||
newcenters.append(pnew.centroid())
|
||||
dodelat
|
||||
if len(p)>ci:#comparing polygons to detect larger changes in shape
|
||||
#print(ci,len(p))
|
||||
bb1=p.boundingBox(ci)
|
||||
bb1=p.bounds(ci)
|
||||
bb2=pnew.boundingBox(ci)
|
||||
d1=dist2d(newcenters[ci],centers[ci])
|
||||
d2=0
|
||||
|
|
@ -2619,10 +2647,10 @@ def getPath3axis(context,operation):
|
|||
p=ch.points[0]#TODO:intercept closest next point when it should stay low
|
||||
#first thing to do is to check if helix enter can really enter.
|
||||
checkc=Circle(helix_radius+o.cutter_diameter/2,o.circle_detail)
|
||||
checkc.shift(p[0],p[1])
|
||||
checkc = affinity.translate(checkc,p[0],p[1])
|
||||
covers=False
|
||||
for poly in o.silhouete:
|
||||
if poly.covers(checkc):
|
||||
if poly.contains(checkc):
|
||||
covers=True
|
||||
break;
|
||||
|
||||
|
|
@ -2683,10 +2711,11 @@ def getPath3axis(context,operation):
|
|||
rothelix.append(p)
|
||||
c.append((p[0],p[1]))
|
||||
|
||||
c=Polygon.Polygon(c)
|
||||
c=sgeometry.Polygon(c)
|
||||
#print('çoutline')
|
||||
#print(c)
|
||||
coutline = outlinePoly(c,o.cutter_diameter/2,o.circle_detail,o.optimize,o.optimize_threshold,offset = True)
|
||||
coutline = c.buffer(o.cutter_diameter/2,o.circle_detail)
|
||||
#coutline = outlinePoly(c,o.cutter_diameter/2,o.circle_detail,o.optimize,o.optimize_threshold,offset = True)
|
||||
#print(h)
|
||||
#print('çoutline')
|
||||
#print(coutline)
|
||||
|
|
@ -2695,7 +2724,7 @@ def getPath3axis(context,operation):
|
|||
|
||||
covers=False
|
||||
for poly in o.silhouete:
|
||||
if poly.covers(coutline):
|
||||
if poly.contains(coutline):
|
||||
covers=True
|
||||
break;
|
||||
|
||||
|
|
@ -2817,7 +2846,7 @@ def getPath3axis(context,operation):
|
|||
#######################
|
||||
nslices=ceil(abs(o.minz/o.slice_detail))
|
||||
lastislice=numpy.array([])
|
||||
lastslice=Polygon.Polygon()#polyversion
|
||||
lastslice=spolygon.Polygon()#polyversion
|
||||
layerstepinc=0
|
||||
|
||||
slicesfilled=0
|
||||
|
|
@ -2832,10 +2861,10 @@ def getPath3axis(context,operation):
|
|||
#print(z)
|
||||
#sliceimage=o.offset_image>z
|
||||
islice=o.offset_image>z
|
||||
slicepolys=imageToPoly(o,islice,with_border=True)
|
||||
slicepolys=imageToShapely(o,islice,with_border=True)
|
||||
#for pviz in slicepolys:
|
||||
# polyToMesh('slice',pviz,z)
|
||||
poly=Polygon.Polygon()#polygversion
|
||||
poly=spolygon.Polygon()#polygversion
|
||||
lastchunks=[]
|
||||
#imagechunks=imageToChunks(o,islice)
|
||||
#for ch in imagechunks:
|
||||
|
|
@ -2847,10 +2876,10 @@ def getPath3axis(context,operation):
|
|||
#print('found polys',layerstepinc,len(slicepolys))
|
||||
for p in slicepolys:
|
||||
#print('polypoints',p.nPoints(0))
|
||||
poly+=p#polygversion TODO: why is this added?
|
||||
poly=poly.union(p)#polygversion TODO: why is this added?
|
||||
#print()
|
||||
#polyToMesh(p,z)
|
||||
nchunks=polyToChunks(p,z)
|
||||
nchunks=shapelyToChunks(p,z)
|
||||
nchunks=limitChunks(nchunks,o, force=True)
|
||||
#print('chunksnum',len(nchunks))
|
||||
#if len(nchunks)>0:
|
||||
|
|
@ -2874,25 +2903,27 @@ def getPath3axis(context,operation):
|
|||
layers=[[layerstart,layerend]]
|
||||
#####################################
|
||||
#fill top slice for normal and first for inverse, fill between polys
|
||||
if len(lastslice)>0 or (o.inverse and len(poly)>0 and slicesfilled==1):
|
||||
offs=False
|
||||
if len(lastslice)>0:#between polys
|
||||
if not lastslice.is_empty or (o.inverse and not poly.is_empty and slicesfilled==1):
|
||||
#offs=False
|
||||
if not lastslice.is_empty:#between polys
|
||||
if o.inverse:
|
||||
restpoly=poly-lastslice
|
||||
restpoly=poly.difference(lastslice)
|
||||
else:
|
||||
restpoly=lastslice-poly#Polygon.Polygon(lastslice)
|
||||
restpoly=lastslice.difference(poly)#Polygon.Polygon(lastslice)
|
||||
#print('filling between')
|
||||
if (not o.inverse and len(poly)==0 and slicesfilled>0) or (o.inverse and len(poly)>0 and slicesfilled==1):#first slice fill
|
||||
if (not o.inverse and poly.is_empty and slicesfilled>0) or (o.inverse and not poly.is_empty and slicesfilled==1):#first slice fill
|
||||
restpoly=lastslice
|
||||
#print('filling first')
|
||||
|
||||
#print(len(restpoly))
|
||||
#polyToMesh('fillrest',restpoly,z)
|
||||
restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs)
|
||||
|
||||
restpoly=restpoly.buffer(-o.dist_between_paths, resolution = o.circle_detail)
|
||||
#outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs)
|
||||
fillz = z
|
||||
i=0
|
||||
while len(restpoly)>0:
|
||||
nchunks=polyToChunks(restpoly,fillz)
|
||||
while not restpoly.is_empty:
|
||||
nchunks=shapelyToChunks(restpoly,fillz)
|
||||
#project paths TODO: path projection during waterline is not working
|
||||
if o.waterline_project:
|
||||
nchunks=chunksRefine(nchunks,o)
|
||||
|
|
@ -2904,38 +2935,41 @@ def getPath3axis(context,operation):
|
|||
parentChildDist(lastchunks,nchunks,o)
|
||||
lastchunks=nchunks
|
||||
#slicechunks.extend(polyToChunks(restpoly,z))
|
||||
restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs)
|
||||
restpoly=restpoly.buffer(-o.dist_between_paths, resolution = o.circle_detail)
|
||||
#restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs)
|
||||
i+=1
|
||||
#print(i)
|
||||
i=0
|
||||
#'''
|
||||
#####################################
|
||||
# fill layers and last slice, last slice with inverse is not working yet - inverse millings end now always on 0 so filling ambient does have no sense.
|
||||
if (slicesfilled>0 and layerstepinc==layerstep) or (not o.inverse and len(poly)>0 and slicesfilled==1) or (o.inverse and len(poly)==0 and slicesfilled>0):
|
||||
if (slicesfilled>0 and layerstepinc==layerstep) or (not o.inverse and not poly.is_empty and slicesfilled==1) or (o.inverse and poly.is_empty and slicesfilled>0):
|
||||
fillz=z
|
||||
layerstepinc=0
|
||||
|
||||
#ilim=1000#TODO:this should be replaced... no limit, just check if the shape grows over limits.
|
||||
|
||||
offs=False
|
||||
#offs=False
|
||||
boundrect=o.ambient#Polygon.Polygon(((o.min.x,o.min.y),(o.min.x,o.max.y),(o.max.x,o.max.y),(o.max.x,o.min.y)))
|
||||
|
||||
restpoly=boundrect-poly
|
||||
if (o.inverse and len(poly)==0 and slicesfilled>0):
|
||||
restpoly=boundrect-lastslice
|
||||
restpoly=boundrect.difference(poly)
|
||||
if (o.inverse and poly.is_empty and slicesfilled>0):
|
||||
restpoly=boundrect.difference(lastslice)
|
||||
|
||||
restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs)
|
||||
restpoly=restpoly.buffer(-o.dist_between_paths, resolution = o.circle_detail)
|
||||
#restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs)
|
||||
i=0
|
||||
while len(restpoly)>0:
|
||||
print(i)
|
||||
nchunks=polyToChunks(restpoly,fillz)
|
||||
while not restpoly.is_empty: #'GeometryCollection':#len(restpoly.boundary.coords)>0:
|
||||
#print(i)
|
||||
nchunks=shapelyToChunks(restpoly,fillz)
|
||||
#########################
|
||||
nchunks=limitChunks(nchunks,o, force=True)
|
||||
slicechunks.extend(nchunks)
|
||||
parentChildDist(lastchunks,nchunks,o)
|
||||
lastchunks=nchunks
|
||||
#slicechunks.extend(polyToChunks(restpoly,z))
|
||||
restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs)
|
||||
restpoly=restpoly.buffer(-o.dist_between_paths, resolution = o.circle_detail)
|
||||
#restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs)
|
||||
i+=1
|
||||
|
||||
|
||||
|
|
@ -2953,7 +2987,7 @@ def getPath3axis(context,operation):
|
|||
n=0
|
||||
while i.sum()>0 and n<10000:
|
||||
i=outlineImageBinary(o,o.dist_between_paths,i,False)
|
||||
polys=imageToPoly(o,i)
|
||||
polys=imageToShapely(o,i)
|
||||
for poly in polys:
|
||||
chunks.extend(polyToChunks(poly,z))
|
||||
n+=1
|
||||
|
|
@ -3056,7 +3090,7 @@ def getPath3axis(context,operation):
|
|||
for ob in o.objects:
|
||||
polys=getOperationSilhouete(o)
|
||||
for poly in polys:
|
||||
chunks=polyToChunks(poly,-1)
|
||||
chunks=shapelyToChunks(poly,-1)
|
||||
chunks = chunksRefine(chunks,o)
|
||||
|
||||
'''
|
||||
|
|
@ -3111,7 +3145,7 @@ def getPath3axis(context,operation):
|
|||
filteredPts=[]
|
||||
print('filter points')
|
||||
for p in pts:
|
||||
if not poly.isInside(p[0],p[1]):
|
||||
if not poly.contains(sgeometry.Point(p)):
|
||||
vertr.append((True,-1))
|
||||
else:
|
||||
vertr.append((False,newIdx))
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue