diff --git a/.gitignore b/.gitignore
index 05c75fe8..cd1f4de4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,4 +16,4 @@ config/bookmarks.txt
*.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
+scripts/addons_contrib/online_mat_lib/material-library/bundled/cycles/wood/rough_pine.bcm
\ No newline at end of file
diff --git a/scripts/addons/cam/__init__.py b/scripts/addons/cam/__init__.py
index e47c9629..8570745b 100644
--- a/scripts/addons/cam/__init__.py
+++ b/scripts/addons/cam/__init__.py
@@ -31,7 +31,7 @@ from bpy.types import Menu, Operator, UIList, AddonPreferences
#from . import patterns
#from . import chunk_operations
-from cam import ui, ops, utils, simple, polygon_utils_cam#, post_processors
+from cam import ui, ops,utils, simple,polygon_utils_cam#, post_processors
import numpy
import Polygon
from bpy.app.handlers import persistent
@@ -85,7 +85,7 @@ class machineSettings(bpy.types.PropertyGroup):
'''stores all data for machines'''
#name = bpy.props.StringProperty(name="Machine Name", default="Machine")
post_processor = EnumProperty(name='Post processor',
- items=(('ISO','Iso','this should export a standardized gcode'),('MACH3','Mach3','default mach3'),('EMC','EMC - LinuxCNC','default emc'),('GRBL','grbl','grbl on Arduino cnc shield'),('HEIDENHAIN','Heidenhain','heidenhain'),('TNC151','Heidenhain TNC151','Post Processor for the Heidenhain TNC151 machine'),('SIEGKX1','Sieg KX1','Sieg KX1'),('HM50','Hafco HM-50','Hafco HM-50'),('CENTROID','Centroid M40','Centroid M40'),('ANILAM','Anilam Crusader M','Anilam Crusader M'),('GRAVOS','Gravos','Gravos'),('WIN-PC','Win-PC','German CNC'),('SHOPBOT MTC','ShopBot MTC','ShopBot MTC'),('LYNX_OTTER_O','Lynx Otter o','Lynx Otter o')),
+ items=(('ISO','Iso','this should export a standardized gcode'),('MACH3','Mach3','default mach3'),('EMC','EMC - LinuxCNC','default emc'),('HEIDENHAIN','Heidenhain','heidenhain'),('TNC151','Heidenhain TNC151','Post Processor for the Heidenhain TNC151 machine'),('SIEGKX1','Sieg KX1','Sieg KX1'),('HM50','Hafco HM-50','Hafco HM-50'),('CENTROID','Centroid M40','Centroid M40'),('ANILAM','Anilam Crusader M','Anilam Crusader M'),('GRAVOS','Gravos','Gravos'),('WIN-PC','Win-PC','German CNC'),('SHOPBOT MTC','ShopBot MTC','ShopBot MTC'),('LYNX_OTTER_O','Lynx Otter o','Lynx Otter o')),
description='Post processor',
default='MACH3')
#units = EnumProperty(name='Units', items = (('IMPERIAL', ''))
@@ -447,7 +447,7 @@ class camOperation(bpy.types.PropertyGroup):
plunge_angle = bpy.props.FloatProperty(name="Plunge angle", description="What angle is allready considered to plunge", default=math.pi/6, min=0, max=math.pi*0.5 , precision=0, subtype="ANGLE" , unit="ROTATION" , update = updateRest)
spindle_rpm = FloatProperty(name="Spindle rpm", description="Spindle speed ", min=1000, max=60000, default=12000, update = updateChipload)
#movement parallel_step_back
- movement_type = EnumProperty(name='Movement type',items=(('CONVENTIONAL','Conventional / Up milling', 'cutter rotates against the direction of the feed'),('CLIMB', 'Climb / Down milling', 'cutter rotates with the direction of the feed'),('MEANDER', 'Meander / Zig Zag' , 'cutting is done both with and against the rotation of the spindle') ),description='movement type', default='CLIMB', update = updateRest)
+ movement_type = EnumProperty(name='Movement type',items=(('CONVENTIONAL','Conventional', 'a'),('CLIMB', 'Climb', 'a'),('MEANDER', 'Meander' , 'a') ),description='movement type', default='CLIMB', update = updateRest)
spindle_rotation_direction = EnumProperty(name='Spindle rotation', items=(('CW','Clock wise', 'a'),('CCW', 'Counter clock wise', 'a')),description='Spindle rotation direction',default='CW', update = updateRest)
free_movement_height = bpy.props.FloatProperty(name="Free movement height", default=0.01, min=0.0000, max=32,precision=PRECISION, unit="LENGTH", update = updateRest)
movement_insideout = EnumProperty(name='Direction', items=(('INSIDEOUT','Inside out', 'a'),('OUTSIDEIN', 'Outside in', 'a')),description='approach to the piece',default='INSIDEOUT', update = updateRest)
diff --git a/scripts/addons/cam/nc/grbl.py b/scripts/addons/cam/nc/grbl.py
deleted file mode 100644
index 9a4a6e2f..00000000
--- a/scripts/addons/cam/nc/grbl.py
+++ /dev/null
@@ -1,287 +0,0 @@
-from . import nc
-from . import iso_modal
-import math
-import datetime
-import time
-
-now = datetime.datetime.now()
-
-class Creator(iso_modal.Creator):
- def __init__(self):
- iso_modal.Creator.__init__(self)
- self.absolute_flag = True
- self.prev_g91 = ''
- self.useCrc = False
- self.start_of_line = True
-
- def write_blocknum(self):
- self.start_of_line = True
-
- def SPACE(self):
- if self.start_of_line == True:
- self.start_of_line = False
- return ''
- else:
- return ' '
-
- def PROGRAM_END(self): return ' '
-
-############################################################################
-## Begin Program
-
-
- def program_begin(self, id, comment):
- if (self.useCrc == False):
- self.write( ('(Created with grbl post processor ' + str(now.strftime("%Y/%m/%d %H:%M")) + ')' + '\n') )
- else:
- self.write( ('(Created with grbl Cutter Radius Compensation post processor ' + str(now.strftime("%Y/%m/%d %H:%M")) + ')' + '\n') )
-
-
-
-
-############################################################################
-## Settings
-
- def tool_defn(self, id, name='', radius=None, length=None, gradient=None):
- pass
-
- def tool_change(self, id):
- pass
-
- def comment(self, text):
- self.write_blocknum()
- self.write((self.COMMENT(text) + '\n'))
-
-# This is the coordinate system we're using. G54->G59, G59.1, G59.2, G59.3
-# These are selected by values from 1 to 9 inclusive.
- def workplane(self, id):
- if ((id >= 1) and (id <= 6)):
- self.write_blocknum()
- self.write( (self.WORKPLANE() % (id + self.WORKPLANE_BASE())) + '\t (Select Relative Coordinate System)\n')
- if ((id >= 7) and (id <= 9)):
- self.write_blocknum()
- self.write( ((self.WORKPLANE() % (6 + self.WORKPLANE_BASE())) + ('.%i' % (id - 6))) + '\t (Select Relative Coordinate System)\n')
-
-
-############################################################################
-## Moves
-
-
-############################################################################
-## Probe routines
- def report_probe_results(self, x1=None, y1=None, z1=None, x2=None, y2=None, z2=None, x3=None, y3=None, z3=None, x4=None, y4=None, z4=None, x5=None, y5=None, z5=None, x6=None, y6=None, z6=None, xml_file_name=None ):
- if (xml_file_name != None):
- self.comment('Generate an XML document describing the probed coordinates found');
- self.write_blocknum()
- self.write('(LOGOPEN,')
- self.write(xml_file_name)
- self.write(')\n')
-
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if ((x1 != None) or (y1 != None) or (z1 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if (x1 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + x1 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (y1 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + y1 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (z1 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + z1 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if ((x1 != None) or (y1 != None) or (z1 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if ((x2 != None) or (y2 != None) or (z2 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if (x2 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + x2 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (y2 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + y2 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (z2 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + z2 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if ((x2 != None) or (y2 != None) or (z2 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if ((x3 != None) or (y3 != None) or (z3 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if (x3 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + x3 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (y3 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + y3 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (z3 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + z3 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if ((x3 != None) or (y3 != None) or (z3 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if ((x4 != None) or (y4 != None) or (z4 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if (x4 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + x4 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (y4 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + y4 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (z4 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + z4 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if ((x4 != None) or (y4 != None) or (z4 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if ((x5 != None) or (y5 != None) or (z5 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if (x5 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + x5 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (y5 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + y5 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (z5 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + z5 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if ((x5 != None) or (y5 != None) or (z5 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if ((x6 != None) or (y6 != None) or (z6 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if (x6 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + x6 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (y6 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + y6 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (z6 != None):
- self.write_blocknum()
- self.write('#<_value>=[' + z6 + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if ((x6 != None) or (y6 != None) or (z6 != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if (xml_file_name != None):
- self.write_blocknum()
- self.write('(LOGCLOSE)\n')
-
- def open_log_file(self, xml_file_name=None ):
- self.write_blocknum()
- self.write('(LOGOPEN,')
- self.write(xml_file_name)
- self.write(')\n')
-
- def close_log_file(self):
- self.write_blocknum()
- self.write('(LOGCLOSE)\n')
-
- def log_coordinate(self, x=None, y=None, z=None):
- if ((x != None) or (y != None) or (z != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- if (x != None):
- self.write_blocknum()
- self.write('#<_value>=[' + x + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (y != None):
- self.write_blocknum()
- self.write('#<_value>=[' + y + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if (z != None):
- self.write_blocknum()
- self.write('#<_value>=[' + z + ']\n')
- self.write_blocknum()
- self.write('(LOG,#<_value>)\n')
-
- if ((x != None) or (y != None) or (z != None)):
- self.write_blocknum()
- self.write('(LOG,)\n')
-
- def log_message(self, message=None ):
- self.write_blocknum()
- self.write('(LOG,' + message + ')\n')
-
-nc.creator = Creator()
diff --git a/scripts/addons/cam/ui.py b/scripts/addons/cam/ui.py
index 1e9a6a5e..bc6838d6 100644
--- a/scripts/addons/cam/ui.py
+++ b/scripts/addons/cam/ui.py
@@ -381,7 +381,6 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, bpy.types.Panel):
layout.prop(ao,'strategy')
layout.prop(ao,'rotary_axis_1')
layout.prop(ao,'rotary_axis_2')
-
if ao.strategy=='BLOCK' or ao.strategy=='SPIRAL' or ao.strategy=='CIRCLES' or ao.strategy=='OUTLINEFILL':
layout.prop(ao,'movement_insideout')
@@ -424,6 +423,7 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, bpy.types.Panel):
if ao.waterline_fill:
layout.prop(ao,'dist_between_paths')
layout.prop(ao,'waterline_project')
+ layout.prop(ao,'skin')
layout.prop(ao,'inverse')
elif ao.strategy=='CARVE':
layout.prop(ao,'carve_depth')
@@ -449,7 +449,9 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, bpy.types.Panel):
layout.prop(ao,'dist_along_paths')
if ao.strategy=='PARALLEL' or ao.strategy=='CROSS':
layout.prop(ao,'parallel_angle')
-
+
+
+ layout.prop(ao,'skin')
layout.prop(ao,'inverse')
#elif ao.strategy=='SLICES':
# layout.prop(ao,'slice_detail')
@@ -457,8 +459,6 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, bpy.types.Panel):
#layout.operator("object.cam_pack_objects")
#layout.operator("scene.cam_orientation_add")
#gname=ao.name+'_orientations'
-
- layout.prop(ao,'skin')
#if gname in bpy.data.groups:
# layout.label('orientations')
@@ -576,7 +576,7 @@ class CAM_OPTIMISATION_Panel(CAMButtonsPanel, bpy.types.Panel):
if ao.optimize:
layout.prop(ao,'optimize_threshold')
if ao.geometry_source=='OBJECT' or ao.geometry_source=='GROUP':
- exclude_exact= ao.strategy=='WATERLINE' or ao.strategy=='POCKET' or ao.strategy=='CUTOUT' or ao.strategy=='DRILL' or ao.strategy=='PENCIL'
+ exclude_exact= ao.strategy=='CUTOUT' or ao.strategy=='DRILL' or ao.strategy=='PENCIL'
if not exclude_exact:
layout.prop(ao,'use_exact')
if ao.use_exact:
diff --git a/scripts/addons/cam/utils.py b/scripts/addons/cam/utils.py
index 06e188d0..7b5b72a7 100644
--- a/scripts/addons/cam/utils.py
+++ b/scripts/addons/cam/utils.py
@@ -1060,9 +1060,6 @@ def exportGcodePath(filename,vertslist,operations):
elif m.post_processor=='EMC':
extension = '.ngc'
from .nc import emc2b as postprocessor
- elif m.post_processor=='GRBL':
- extension = '.ngc'
- from .nc import grbl as postprocessor
elif m.post_processor=='HM50':
from .nc import hm50 as postprocessor
elif m.post_processor=='HEIDENHAIN':
@@ -1564,28 +1561,15 @@ def sortChunks(chunks,o):
ch = getClosest(o,pos,chunks)
# break
#pass;
- if ch is not None:#found next chunk, append it to list
- ch.sorted = True
- ch.adaptdist(pos, o)
+ if ch!=None:#found next chunk, append it to list
+ ch.sorted=True
+ ch.adaptdist(pos,o)
print(ch)
chunks.remove(ch)
sortedchunks.append(ch)
- lastch = ch
- pos = lastch.points[-1]
- # experimental fix for infinite loop problem
- #else:
- # can't find chunks close enough and still some chunks left
- # to be sorted. For now just move the remaining chunks over to
- # the sorted list.
- # This fixes an infinite loop condition that occurs sometimes.
- # This is a bandaid fix: need to find the root cause of this problem
- # suspect it has to do with the sorted flag?
- #print("no chunks found closest. Chunks not sorted: ", len(chunks))
- #sortedchunks.extend(chunks)
- #chunks[:] = []
-
- i -= 1
-
+ lastch=ch
+ pos=lastch.points[-1]
+ i-=1
'''
if i<-200:
for ch in chunks:
@@ -2300,239 +2284,236 @@ def addBridges(ch,o):
ch.points[p[0]]=p[1]
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
- print('operation: cutout')
- offset=True
- if o.cut_type=='ONLINE' and o.onlycurves==True:#is separate to allow open curves :)
- print('separate')
- chunksFromCurve=[]
- for ob in o.objects:
- chunksFromCurve.extend(curveToChunks(ob))
- #p=Polygon.Polygon()
- for ch in chunksFromCurve:
- #print(ch.points)
-
- if len(ch.points)>2:
- ch.poly=chunkToShapely(ch)
- #p.addContour(ch.poly)
- else:
- chunksFromCurve=[]
- if o.cut_type=='ONLINE':
- p=getObjectOutline(0,o,True)
-
- else:
- 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(shapelyToChunks(p,-1))
- p = p.buffer(distance = o.dist_between_paths * offset, resolution = o.circle_detail)
-
-
- chunksFromCurve.extend(shapelyToChunks(p,-1))
- if o.outlines_count>1 and o.movement_insideout=='OUTSIDEIN':
- chunksFromCurve.reverse()
-
- #parentChildPoly(chunksFromCurve,chunksFromCurve,o)
- chunksFromCurve=limitChunks(chunksFromCurve,o)
- parentChildPoly(chunksFromCurve,chunksFromCurve,o)
- if o.outlines_count==1:
- chunksFromCurve=sortChunks(chunksFromCurve,o)
-
- #if o.outlines_count>0 and o.cut_type!='ONLINE' and o.movement_insideout=='OUTSIDEIN':#reversing just with more outlines
- # chunksFromCurve.reverse()
-
- if (o.movement_type=='CLIMB' and o.spindle_rotation_direction=='CCW') or (o.movement_type=='CONVENTIONAL' and o.spindle_rotation_direction=='CW'):
- for ch in chunksFromCurve:
- ch.points.reverse()
-
- if o.cut_type=='INSIDE':#there would bee too many conditions above, so for now it gets reversed once again when inside cutting.
- for ch in chunksFromCurve:
- ch.points.reverse()
-
-
- if o.use_layers:
- layers=[]
- n=math.ceil((o.maxz-o.min.z)/o.stepdown)
- layerstart=o.maxz
- for x in range(0,n):
- layerend=max(o.maxz-((x+1)*o.stepdown),o.min.z)
- if int(layerstart*10**8)!=int(layerend*10**8):#it was possible that with precise same end of operation, last layer was done 2x on exactly same level...
- layers.append([layerstart,layerend])
- layerstart=layerend
- else:
- 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:
- for layer in layers:
- extendorder.append([chunk.copy(),layer])
- else:
- for layer in layers:
- for chunk in chunksFromCurve:
- extendorder.append([chunk.copy(),layer])
-
- for chl in extendorder:#Set Z for all chunks
- chunk=chl[0]
- layer=chl[1]
- print(layer[1])
- chunk.setZ(layer[1])
-
- chunks=[]
-
- if o.ramp:#add ramps or simply add chunks
- for chl in extendorder:
- chunk=chl[0]
- layer=chl[1]
- if chunk.closed:
- chunks.append(chunk.rampContour(layer[0],layer[1],o))
- else:
- chunks.append(chunk.rampZigZag(layer[0],layer[1],o))
-
- 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]2:
+ ch.poly=chunkToShapely(ch)
+ #p.addContour(ch.poly)
+ else:
+ chunksFromCurve=[]
+ if o.cut_type=='ONLINE':
+ p=getObjectOutline(0,o,True)
+
+ else:
+ 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(shapelyToChunks(p,-1))
+ p = p.buffer(distance = o.dist_between_paths * offset, resolution = o.circle_detail)
+
+
+ chunksFromCurve.extend(shapelyToChunks(p,-1))
+ if o.outlines_count>1 and o.movement_insideout=='OUTSIDEIN':
+ chunksFromCurve.reverse()
+ #parentChildPoly(chunksFromCurve,chunksFromCurve,o)
+ chunksFromCurve=limitChunks(chunksFromCurve,o)
+ parentChildPoly(chunksFromCurve,chunksFromCurve,o)
+ if o.outlines_count==1:
+ chunksFromCurve=sortChunks(chunksFromCurve,o)
- elif o.strategy=='POCKET':
+ #if o.outlines_count>0 and o.cut_type!='ONLINE' and o.movement_insideout=='OUTSIDEIN':#reversing just with more outlines
+ # chunksFromCurve.reverse()
+
+ if (o.movement_type=='CLIMB' and o.spindle_rotation_direction=='CCW') or (o.movement_type=='CONVENTIONAL' and o.spindle_rotation_direction=='CW'):
+ for ch in chunksFromCurve:
+ ch.points.reverse()
+
+ if o.cut_type=='INSIDE':#there would bee too many conditions above, so for now it gets reversed once again when inside cutting.
+ for ch in chunksFromCurve:
+ ch.points.reverse()
+
+
+ if o.use_layers:
+ layers=[]
+ n=math.ceil((o.maxz-o.min.z)/o.stepdown)
+ layerstart=o.maxz
+ for x in range(0,n):
+ layerend=max(o.maxz-((x+1)*o.stepdown),o.min.z)
+ if int(layerstart*10**8)!=int(layerend*10**8):#it was possible that with precise same end of operation, last layer was done 2x on exactly same level...
+ layers.append([layerstart,layerend])
+ layerstart=layerend
+ else:
+ 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:
+ for layer in layers:
+ extendorder.append([chunk.copy(),layer])
+ else:
+ for layer in layers:
+ for chunk in chunksFromCurve:
+ extendorder.append([chunk.copy(),layer])
+
+ for chl in extendorder:#Set Z for all chunks
+ chunk=chl[0]
+ layer=chl[1]
+ print(layer[1])
+ chunk.setZ(layer[1])
+
+ chunks=[]
+
+ if o.ramp:#add ramps or simply add chunks
+ for chl in extendorder:
+ chunk=chl[0]
+ layer=chl[1]
+ if chunk.closed:
+ chunk.rampContour(layer[0],layer[1],o)
+ else:
+ chunk.rampZigZag(layer[0],layer[1],o)
+
+
+
+ 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]