Jeff Doyle (nfz) 2015-12-19 12:37:03 -04:00
commit 7c4882d90c
9 zmienionych plików z 671 dodań i 241 usunięć

5
.gitignore vendored
Wyświetl plik

@ -6,8 +6,13 @@ config/bookmarks.txt
/scripts/startup/
/scripts/templates_osl/
/scripts/templates_py/
/scripts/addons/
/scripts/addons_contrib/
*.spi1d
*.pyc
*.ocio
*.spi3d
*.py
config/recent-files.txt
scripts/addons_contrib/add_mesh_rocks/add_mesh_rocks.xml
scripts/addons_contrib/online_mat_lib/material-library/bundled/cycles/wood/rough_pine.bcm

Wyświetl plik

@ -219,8 +219,9 @@ def updateStrategy(o,context):
updateExact(o,context)
def updateCutout(o,context):
if o.outlines_count>1:
o.use_bridges=False
pass;
#if o.outlines_count>1:
# o.use_bridges=False
def updateExact(o,context):
@ -481,6 +482,9 @@ class camOperation(bpy.types.PropertyGroup):
use_bridges = bpy.props.BoolProperty(name="Use bridges",description="use bridges in cutout", default=False, update = updateBridges)
bridges_width = bpy.props.FloatProperty(name = 'width of bridges', default=0.002, unit='LENGTH', precision=PRECISION, update = updateBridges)
bridges_height = bpy.props.FloatProperty(name = 'height of bridges', description="Height from the bottom of the cutting operation", default=0.0005, unit='LENGTH', precision=PRECISION, update = updateBridges)
bridges_group_name = bpy.props.StringProperty(name='Bridges Group', description='Group of curves used as bridges', update=operationValid)
'''commented this - auto bridges will be generated, but not as a setting of the operation
bridges_placement = bpy.props.EnumProperty(name='Bridge placement',
items=(
('AUTO','Automatic', 'Automatic bridges with a set distance'),
@ -492,6 +496,9 @@ class camOperation(bpy.types.PropertyGroup):
bridges_per_curve = bpy.props.IntProperty(name="minimum bridges per curve", description="", default=4, min=1, max=512, update = updateBridges)
bridges_max_distance = bpy.props.FloatProperty(name = 'Maximum distance between bridges', default=0.08, unit='LENGTH', precision=PRECISION, update = updateBridges)
'''
group_name = bpy.props.StringProperty(name='Group', description='Object group handled by this operation', update=operationValid)
#optimisation panel
#material settings
@ -706,7 +713,7 @@ def get_panels():#convenience function for bot register and unregister functions
ops.CamOperationRemove,
ops.CamOperationMove,
#bridges related
ops.CamBridgeAdd,
ops.CamBridgesAdd,
#5 axis ops
ops.CamOrientationAdd,
#shape packing

Wyświetl plik

@ -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
@ -295,9 +295,8 @@ class camPathChunk:
z=znew
i+=1
self.points = chunk.points
return chunk
def rampZigZag(self,zstart,zend,o):
chunk=camPathChunk([])
@ -428,8 +427,7 @@ class camPathChunk:
ratio=1-(traveled/ramplength)
znew=zstart-stepdown*ratio
chunk.points.append((p2[0],p2[1],max(p2[2],znew)))#max value here is so that it doesn't go below surface in the case of 3d paths
return chunk
self.points=chunk.points
#def appendChunk(sorted,ch,o,pos)
def chunksCoherency(chunks):
@ -542,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
@ -571,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)
@ -612,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=[]
@ -633,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')
@ -736,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
@ -818,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=[]
@ -828,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:

Wyświetl plik

@ -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()

Wyświetl plik

@ -664,10 +664,10 @@ class CamOrientationAdd(bpy.types.Operator):
return {'FINISHED'}
class CamBridgeAdd(bpy.types.Operator):
class CamBridgesAdd(bpy.types.Operator):
'''Add orientation to cam operation, for multiaxis operations'''
bl_idname = "scene.cam_bridge_add"
bl_label = "Add bridge"
bl_idname = "scene.cam_bridges_add"
bl_label = "Add bridges"
bl_options = {'REGISTER', 'UNDO'}
@ -680,7 +680,7 @@ class CamBridgeAdd(bpy.types.Operator):
s=bpy.context.scene
a=s.cam_active_operation
o=s.cam_operations[a]
utils.addBridge(o)
utils.addAutoBridges(o)
return {'FINISHED'}
@ -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'}

Wyświetl plik

@ -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

Wyświetl plik

@ -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,12 +264,85 @@ def polyToMesh(name,p,z):
return bpy.context.active_object
def shapelyToMesh(name,p,z):
p = Shapely2Polygon(p)
ob = polyToMesh(name,p,z)
return ob
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
verts=[]
edges=[]
vi=0
ci=0
#for c in p.exterior.coords:
print(p.type)
seq = shapelyToCoords(p)
w = 1 # weight
curvedata = bpy.data.curves.new(name=name, type='CURVE')
curvedata.dimensions = '3D'
objectdata = bpy.data.objects.new(name, curvedata)
objectdata.location = (0,0,0) #object origin
bpy.context.scene.objects.link(objectdata)
for c in seq:
polyline = curvedata.splines.new('POLY')
polyline.points.add(len(c)-1)
for num in range(len(c)):
x, y = c[num][0],c[num][1]
polyline.points[num].co = (x, y, z, w)
return objectdata#bpy.context.active_object
'''#outdated?
def orderPoly(polys): #sor poly, do holes e.t.c.
p=Polygon.Polygon()
levels=[[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
@ -302,4 +375,5 @@ def orderPoly(polys): #sor poly, do holes e.t.c.
p.simplify()
li+=1
return p
return p
'''

Wyświetl plik

@ -408,13 +408,16 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, bpy.types.Panel):
layout.prop(ao,'dont_merge')
layout.prop(ao,'use_bridges')
if ao.use_bridges:
layout.prop(ao,'bridges_placement')
#layout.prop(ao,'bridges_placement')
layout.prop(ao,'bridges_width')
layout.prop(ao,'bridges_height')
if ao.bridges_placement == 'AUTO':
layout.prop(ao,'bridges_per_curve')
layout.prop(ao,'bridges_max_distance')
layout.prop_search(ao, "bridges_group_name", bpy.data, "groups")
#layout.prop(ao,'bridges_group_name')
#if ao.bridges_placement == 'AUTO':
# layout.prop(ao,'bridges_per_curve')
# layout.prop(ao,'bridges_max_distance')
layout.operator("scene.cam_bridges_add", text="Autogenerate bridges")
elif ao.strategy=='WATERLINE':
layout.prop(ao,'slice_detail')
layout.prop(ao,'waterline_fill')

Wyświetl plik

@ -53,15 +53,15 @@ from cam.polygon_utils_cam import *
from cam import image_utils
from cam.image_utils import *
from . import nc
from cam.opencamlib.opencamlib import oclSample, oclSamplePoints, oclResampleChunks, oclGetWaterline
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
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]
@ -90,21 +90,65 @@ def getBoundsWorldspace(obs):
maxy=max(maxy,worldCoord.y)
maxz=max(maxz,worldCoord.z)
else:
for coord in bb:
#this can work badly with some imported curves, don't know why...
#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z))
worldCoord =mw * Vector((coord[0], coord[1], coord[2]))
minx=min(minx,worldCoord.x)
miny=min(miny,worldCoord.y)
minz=min(minz,worldCoord.z)
maxx=max(maxx,worldCoord.x)
maxy=max(maxy,worldCoord.y)
maxz=max(maxz,worldCoord.z)
#for coord in bb:
for c in ob.data.splines:
for p in c.bezier_points:
coord=p.co
#this can work badly with some imported curves, don't know why...
#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z))
worldCoord =mw * Vector((coord[0], coord[1], coord[2]))
minx=min(minx,worldCoord.x)
miny=min(miny,worldCoord.y)
minz=min(minz,worldCoord.z)
maxx=max(maxx,worldCoord.x)
maxy=max(maxy,worldCoord.y)
maxz=max(maxz,worldCoord.z)
for p in c.points:
coord=p.co
#this can work badly with some imported curves, don't know why...
#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z))
worldCoord =mw * Vector((coord[0], coord[1], coord[2]))
minx=min(minx,worldCoord.x)
miny=min(miny,worldCoord.y)
minz=min(minz,worldCoord.z)
maxx=max(maxx,worldCoord.x)
maxy=max(maxy,worldCoord.y)
maxz=max(maxz,worldCoord.z)
#progress(time.time()-t)
return minx,miny,minz,maxx,maxy,maxz
def getSplineBounds(ob,curve):
#progress('getting bounds of object(s)')
maxx=maxy=maxz=-10000000
minx=miny=minz=10000000
mw=ob.matrix_world
for p in curve.bezier_points:
coord=p.co
#this can work badly with some imported curves, don't know why...
#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z))
worldCoord =mw * Vector((coord[0], coord[1], coord[2]))
minx=min(minx,worldCoord.x)
miny=min(miny,worldCoord.y)
minz=min(minz,worldCoord.z)
maxx=max(maxx,worldCoord.x)
maxy=max(maxy,worldCoord.y)
maxz=max(maxz,worldCoord.z)
for p in curve.points:
coord=p.co
#this can work badly with some imported curves, don't know why...
#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z))
worldCoord =mw * Vector((coord[0], coord[1], coord[2]))
minx=min(minx,worldCoord.x)
miny=min(miny,worldCoord.y)
minz=min(minz,worldCoord.z)
maxx=max(maxx,worldCoord.x)
maxy=max(maxy,worldCoord.y)
maxz=max(maxz,worldCoord.z)
#progress(time.time()-t)
return minx,miny,minz,maxx,maxy,maxz
def getOperationSources(o):
if o.geometry_source=='OBJECT':
#bpy.ops.object.select_all(action='DESELECT')
@ -254,7 +298,7 @@ def samplePathLow(o,ch1,ch2,dosample):
#print(len(bpath))
pixsize=o.pixsize
if dosample:
if not (o.use_opencamlib and o.use_exact):
if not (o.use_opencamlib and o.use_exact):
if o.use_exact:
cutterdepth=o.cutter_shape.dimensions.z/2
for p in bpath.points:
@ -279,10 +323,10 @@ def sampleChunks(o,pathSamples,layers):
getAmbient(o)
if o.use_exact:#prepare collision world
if o.use_opencamlib:
oclSample(o, pathSamples)
cutterdepth=0
else:
if o.use_opencamlib:
oclSample(o, pathSamples)
cutterdepth=0
else:
if o.update_bullet_collision_tag:
prepareBulletCollision(o)
@ -349,14 +393,14 @@ 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:
z=s[2]
if minz>z:
z=minz
newsample=(x,y,z)
if o.use_opencamlib and o.use_exact:
z=s[2]
if minz>z:
z=minz
newsample=(x,y,z)
####sampling
elif o.use_exact and not o.use_opencamlib:
@ -817,20 +861,20 @@ def doSimulation(name,operations):
numpysave(i,iname)
i=bpy.data.images.load(iname)
createSimulationObject(name,operations,i)
def extendChunks5axis(chunks,o):
s=bpy.context.scene
m=s.cam_machine
m=s.cam_machine
s=bpy.context.scene
free_movement_height = o.free_movement_height# o.max.z +
if m.use_position_definitions:# dhull
cutterstart=Vector((m.starting_position.x, m.starting_position.y ,max(o.max.z, m.starting_position.z)))#start point for casting
else:
cutterstart=Vector((0,0,max(o.max.z,free_movement_height)))#start point for casting
cutterend=Vector((0,0,o.min.z))
oriname=o.name+' orientation'
ori=s.objects[oriname]
cutterstart=Vector((0,0,max(o.max.z,free_movement_height)))#start point for casting
cutterend=Vector((0,0,o.min.z))
oriname=o.name+' orientation'
ori=s.objects[oriname]
#rotationaxes = rotTo2axes(ori.rotation_euler,'CA')#warning-here it allready is reset to 0!!
print('rot',o.rotationaxes)
a,b=o.rotationaxes#this is all nonsense by now.
@ -846,23 +890,23 @@ def extendChunks5axis(chunks,o):
def chunksToMesh(chunks,o):
'''convert sampled chunks to path, optimization of paths'''
t=time.time()
s=bpy.context.scene
m=s.cam_machine
'''convert sampled chunks to path, optimization of paths'''
t=time.time()
s=bpy.context.scene
m=s.cam_machine
verts=[]
free_movement_height = o.free_movement_height#o.max.z +
if o.machine_axes=='3':
if m.use_position_definitions:
origin=(m.starting_position.x, m.starting_position.y, m.starting_position.z)# dhull
origin=(m.starting_position.x, m.starting_position.y, m.starting_position.z)# dhull
else:
origin=(0,0,free_movement_height)
verts = [origin]
if o.machine_axes!='3':
verts_rotations=[]#(0,0,0)
origin=(0,0,free_movement_height)
verts = [origin]
if o.machine_axes!='3':
verts_rotations=[]#(0,0,0)
if (o.machine_axes == '5' and o.strategy5axis=='INDEXED') or (o.machine_axes=='4' and o.strategy4axis=='INDEXED'):
extendChunks5axis(chunks,o)
@ -1035,27 +1079,27 @@ def exportGcodePath(filename,vertslist,operations):
elif m.post_processor=='GRAVOS':
extension = '.nc'
from .nc import gravos as postprocessor
elif m.post_processor=='WIN-PC' :
extension='.din'
from .nc import winpc as postprocessor
elif m.post_processor=='WIN-PC' :
extension='.din'
from .nc import winpc as postprocessor
elif m.post_processor=='SHOPBOT MTC':
extension='.sbp'
from .nc import shopbot_mtc as postprocessor
elif m.post_processor=='LYNX_OTTER_O':
extension='.nc'
from .nc import lynx_otter_o as postprocessor
if s.unit_settings.system=='METRIC':
unitcorr=1000.0
elif s.unit_settings.system=='IMPERIAL':
unitcorr=1/0.0254;
else:
unitcorr=1;
rotcorr=180.0/pi
if s.unit_settings.system=='METRIC':
unitcorr=1000.0
elif s.unit_settings.system=='IMPERIAL':
unitcorr=1/0.0254;
else:
unitcorr=1;
rotcorr=180.0/pi
def startNewFile():
def startNewFile():
fileindex=''
if split:
fileindex='_'+str(findex)
@ -1064,15 +1108,15 @@ def exportGcodePath(filename,vertslist,operations):
c.file_open(filename)
#unit system correction
###############
if s.unit_settings.system=='METRIC':
c.metric()
elif s.unit_settings.system=='IMPERIAL':
###############
if s.unit_settings.system=='METRIC':
c.metric()
elif s.unit_settings.system=='IMPERIAL':
c.imperial()
#start program
#start program
c.program_begin(0,filename)
c.flush_nc()
c.flush_nc()
c.comment('G-code generated with BlenderCAM and NC library')
#absolute coordinates
c.absolute()
@ -1117,35 +1161,35 @@ def exportGcodePath(filename,vertslist,operations):
c.flush_nc()
if m.spindle_start_time>0:
c.dwell(m.spindle_start_time)
c.flush_nc()
# dhull c.feedrate(unitcorr*o.feedrate)
c.flush_nc()
# dhull c.feedrate(unitcorr*o.feedrate)
#commands=[]
m=bpy.context.scene.cam_machine
millfeedrate=min(o.feedrate,m.feedrate_max)
millfeedrate=unitcorr*max(millfeedrate,m.feedrate_min)
plungefeedrate= millfeedrate*o.plunge_feedrate/100
plungefeedrate= millfeedrate*o.plunge_feedrate/100
freefeedrate=m.feedrate_max*unitcorr
fadjust=False
fadjust=False
if o.do_simulation_feedrate and mesh.shape_keys!= None and mesh.shape_keys.key_blocks.find('feedrates')!=-1:
shapek = mesh.shape_keys.key_blocks['feedrates']
fadjust=True
if m.use_position_definitions:# dhull
last=Vector((m.starting_position.x, m.starting_position.y, m.starting_position.z))
else:
last=Vector((0.0,0.0,free_movement_height))#nonsense values so first step of the operation gets written for sure
lastrot=Euler((0,0,0))
duration=0.0
else:
last=Vector((0.0,0.0,free_movement_height))#nonsense values so first step of the operation gets written for sure
lastrot=Euler((0,0,0))
duration=0.0
f=millfeedrate
fadjustval = 1 # if simulation load data is Not present
downvector= Vector((0,0,-1))
plungelimit=(pi/2-o.plunge_angle)
@ -1293,16 +1337,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'}
@ -1486,7 +1537,7 @@ def sortChunks(chunks,o):
progress('sorting paths')
sys.setrecursionlimit(100000)# the getNext() function of CamPathChunk was running out of recursion limits.
sortedchunks=[]
chunks_to_resample=[]
chunks_to_resample=[]
lastch=None
i=len(chunks)
@ -1530,7 +1581,7 @@ def sortChunks(chunks,o):
print(len(ch.points))
'''
sys.setrecursionlimit(1000)
if o.strategy!='DRILL':
sortedchunks = connectChunksLow(sortedchunks,o)
@ -1632,7 +1683,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:
@ -1649,7 +1700,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
@ -1699,7 +1750,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()
@ -1751,41 +1802,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):
@ -1926,7 +1994,7 @@ def getContainer():
container=s.objects['CAM_OBJECTS']
return container
'''
def getSnappingObject(o):
s=bpy.context.scene
@ -1980,8 +2048,167 @@ def getBridges(p,o):
pos=pos[0],pos[1]
bridges.append(pos)
return bridges
'''
def addAutoBridges(o):
'''attempt to add auto bridges as set of curves'''
getOperationSources(o)
if not o.onlycurves:
o.warnings.append('not curves')
return;
bridgegroupname=o.bridges_group_name
if bridgegroupname == '' or bpy.data.groups.get(bridgegroupname) == None:
bridgegroupname = 'bridges_'+o.name
bpy.data.groups.new(bridgegroupname)
g= bpy.data.groups[bridgegroupname]
for ob in o.objects:
if ob.type=='CURVE':
sply = curveToShapely(ob)
mw=ob.matrix_world
for c in ob.data.splines:
blength = o.cutter_diameter*1
minx,miny,minz,maxx,maxy,maxz = getSplineBounds(ob,c)
bpy.ops.mesh.primitive_plane_add(radius=blength, view_align=False, enter_editmode=False, location=(0, 0, 0))
b=bpy.context.active_object
b.name = 'bridge'
b.show_name=True
b.dimensions.x=o.bridges_width
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
bpy.ops.object.editmode_toggle()
bpy.ops.transform.translate(value=(0, blength/2, 0), constraint_axis=(False, True, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1)
bpy.ops.object.editmode_toggle()
bpy.ops.object.convert(target='CURVE')
b.location = (minx+maxx)/2, miny, 0
b.rotation_euler.z=pi
g.objects.link(b)
bpy.ops.object.duplicate(linked=True)
b=bpy.context.active_object
b.location = (minx+maxx)/2, maxy, 0
b.rotation_euler.z=0
bpy.ops.object.duplicate(linked=True)
b=bpy.context.active_object
b.location = minx, (miny+maxy)/2, 0
b.rotation_euler.z=pi/2
bpy.ops.object.duplicate(linked=True)
b=bpy.context.active_object
b.location = maxx, (miny+maxy)/2, 0
b.rotation_euler.z=-pi/2
def addBridges(ch,o):
'''this adds bridges to chunks, takes the bridge-objects group and uses the curves inside it as bridges.'''
bridgegroupname=o.bridges_group_name
bridgegroup=bpy.data.groups[bridgegroupname]
#get bridgepoly
shapes=[]
for ob in bridgegroup.objects:
if ob.type == 'CURVE':
shapes.extend(curveToShapely(ob))
bridgespoly=sops.unary_union(shapes)
#buffer the poly, so the bridges are not actually milled...
bridgespoly = bridgespoly.buffer(distance = o.cutter_diameter/2.0)
####
bridgeheight=min(0,o.min.z+o.bridges_height)
vi=0
#shapelyToCurve('test',bridgespoly,0)
newpoints=[]
while vi<len(ch.points):
i1=vi
i2=vi
chp1=ch.points[i1]
chp2=ch.points[i1]#Vector(v1)#this is for case of last point and not closed chunk..
if vi+1<len(ch.points):
i2 = vi+1
chp2=ch.points[vi+1]#Vector(ch.points[vi+1])
v1=Vector(chp1)
v2=Vector(chp2)
if v1.z<bridgeheight or v2.z<bridgeheight:
v=v2-v1
#dist+=v.length
p1=sgeometry.Point(chp1)
p2=sgeometry.Point(chp1)
startinside = bridgespoly.contains(p1)
endinside = bridgespoly.contains(p2)
l=sgeometry.LineString([chp1,chp2])
intersections = bridgespoly.boundary.intersection(l)
itempty = intersections.type == 'GeometryCollection'
itpoint = intersections.type == 'Point'
itmpoint = intersections.type == 'MultiPoint'
#print(startinside, endinside,intersections, intersections.type)
#print(l,bridgespoly)
if not startinside:
#print('nothing found')
newpoints.append(chp1)
#elif startinside and endinside and itempty:
# newpoints.append((chp1[0],chp1[1],max(chp1[2],bridgeheight)))
elif startinside:
newpoints.append((chp1[0],chp1[1],max(chp1[2],bridgeheight)))
#elif not startinside:
# newpoints.append(chp1)
cpoints=[]
if itpoint:
cpoints= [Vector((intersections.x,intersections.y,intersections.z))]
elif itmpoint:
cpoints=[]
for p in intersections:
cpoints.append(Vector((p.x,p.y,p.z)))
#####sort collisions here :(
ncpoints=[]
while len(cpoints)>0:
mind=10000000
mini=-1
for i,p in enumerate(cpoints):
if min(mind, (p-v1).length)<mind:
mini=i
mind= (p-v1).length
ncpoints.append(cpoints.pop(mini))
cpoints = ncpoints
#endsorting
if startinside:
isinside=True
else:
isinside=False
for cp in cpoints:
v3= cp
#print(v3)
if v.length==0:
ratio=1
else:
fractvect = v3 - v1
ratio = fractvect.length/v.length
collisionz=v1.z+v.z*ratio
np1 = (v3.x, v3.y, collisionz)
np2 = (v3.x, v3.y, max(collisionz,bridgeheight))
if not isinside:
newpoints.extend((np1, np2))
else:
newpoints.extend((np2, np1))
isinside = not isinside
vi+=1
else:
newpoints.append(chp1)
vi+=1
ch.points=newpoints
'''
def addBridges(ch,o):
#this functions adds Bridges to the finished chunks. AUTOMATIC ONLY NOW!
if o.bridges_placement == 'AUTO':
@ -2063,6 +2290,8 @@ def addBridges(ch,o):
for pi in range(len(insertpoints)-1,-1,-1):
ch.points.insert(insertpoints[pi][0],insertpoints[pi][1])
'''
###########cutout strategy is completely here:
def strategy_cutout( o ):
#ob=bpy.context.active_object
@ -2078,7 +2307,7 @@ def strategy_cutout( o ):
#print(ch.points)
if len(ch.points)>2:
ch.poly=chunkToPoly(ch)
ch.poly=chunkToShapely(ch)
#p.addContour(ch.poly)
else:
chunksFromCurve=[]
@ -2092,11 +2321,12 @@ def strategy_cutout( o ):
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)
@ -2130,6 +2360,7 @@ def strategy_cutout( o ):
layers=[[o.maxz,o.min.z]]
print(layers)
extendorder=[]
if o.first_down:#each shape gets either cut all the way to bottom, or every shape gets cut 1 layer, then all again. has to create copies, because same chunks are worked with on more layers usually
for chunk in chunksFromCurve:
@ -2148,15 +2379,6 @@ def strategy_cutout( o ):
chunks=[]
if o.use_bridges:#add bridges to chunks
#bridges=getBridges(p,o)
bridgeheight=min(0,o.min.z+o.bridges_height)
for chl in extendorder:
chunk=chl[0]
layer=chl[1]
if layer[1]<bridgeheight:
addBridges(chunk,o)
if o.ramp:#add ramps or simply add chunks
for chl in extendorder:
chunk=chl[0]
@ -2165,9 +2387,19 @@ def strategy_cutout( o ):
chunks.append(chunk.rampContour(layer[0],layer[1],o))
else:
chunks.append(chunk.rampZigZag(layer[0],layer[1],o))
else:
if o.use_bridges:#add bridges to chunks
#bridges=getBridges(p,o)
bridgeheight=min(0,o.min.z+o.bridges_height)
for chl in extendorder:
chunks.append(chl[0])
chunk=chl[0]
layer=chl[1]
if layer[1]<bridgeheight:
addBridges(chunk,o)
for chl in extendorder:
chunks.append(chl[0])
chunksToMesh(chunks,o)
@ -2269,8 +2501,6 @@ def strategy_proj_curve( s, o ):
# ch.points=ch.endpoints
chunksToMesh(chunks,o)
#def strategy_pocket( o ):
#this is the main function.
#FIXME: split strategies into separate file!
@ -2292,45 +2522,43 @@ def getPath3axis(context, operation):
elif 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
checkCenters=False
if o.dist_between_paths>o.cutter_diameter/2.0:
checkCenters=True
o.warnings=o.warnings+'Distance between paths larger\n than cutter radius can result in uncut areas!\n '
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 checkCenters:
contours_before=len(p)
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.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
@ -2423,10 +2651,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;
@ -2487,10 +2715,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)
@ -2499,7 +2728,7 @@ def getPath3axis(context, operation):
covers=False
for poly in o.silhouete:
if poly.covers(coutline):
if poly.contains(coutline):
covers=True
break;
@ -2592,16 +2821,16 @@ def getPath3axis(context, operation):
elif o.strategy=='WATERLINE' and o.use_opencamlib:
getAmbient(o)
chunks=[]
oclGetWaterline(o, chunks)
chunks=limitChunks(chunks,o)
getAmbient(o)
chunks=[]
oclGetWaterline(o, chunks)
chunks=limitChunks(chunks,o)
if (o.movement_type=='CLIMB' and o.spindle_rotation_direction=='CW') or (o.movement_type=='CONVENTIONAL' and o.spindle_rotation_direction=='CCW'):
for ch in chunks:
ch.points.reverse()
chunksToMesh(chunks,o)
chunksToMesh(chunks,o)
elif o.strategy=='WATERLINE' and not o.use_opencamlib:
topdown=True
tw=time.time()
@ -2621,7 +2850,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
@ -2636,10 +2865,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:
@ -2651,10 +2880,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:
@ -2678,25 +2907,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)
@ -2708,38 +2939,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
@ -2757,7 +2991,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
@ -2861,7 +3095,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)
'''
@ -2916,7 +3150,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))