def getWaterline(s, cutter, zh, sampling): wl = ocl.Waterline() #wl.setThreads(1) # single thread for easier debug wl.setSTL(s) wl.setCutter(cutter) wl.setZ(zh) wl.setSampling(sampling) wl.run() loops = wl.getLoops() return loops
def oclGetWaterline(operation, chunks): layers = oclWaterlineLayerHeights(operation) oclSTL = get_oclSTL(operation) cutter_props = operation.getOpCuttingTool() op_cutter_type = cutter_props.cutter_type op_cutter_diameter = cutter_props.cutter_diameter op_minz = operation.minz if op_cutter_type == "VCARVE": op_cutter_tip_angle = cutter_props.cutter_tip_angle cutter = None cutter_length = 150 #TODO: automatically determine necessary cutter length depending on object size if op_cutter_type == 'END': cutter = ocl.CylCutter( (op_cutter_diameter + operation.skin * 2) * 1000, cutter_length) elif op_cutter_type == 'BALLNOSE': cutter = ocl.BallCutter( (op_cutter_diameter + operation.skin * 2) * 1000, cutter_length) elif op_cutter_type == 'VCARVE': cutter = ocl.ConeCutter( (op_cutter_diameter + operation.skin * 2) * 1000, op_cutter_tip_angle, cutter_length) else: print("Cutter unsupported: {0}\n".format(op_cutter_type)) quit() waterline = ocl.Waterline() waterline.setSTL(oclSTL) waterline.setCutter(cutter) waterline.setSampling(0.1) #TODO: add sampling setting to UI for height in layers: print(str(height) + '\n') waterline.reset() waterline.setZ(height * OCL_SCALE) waterline.run2() wl_loops = waterline.getLoops() for l in wl_loops: chunks.append(camPathChunk(inpoints=[])) for p in l: chunks[-1].points.append( (p.x / OCL_SCALE, p.y / OCL_SCALE, p.z / OCL_SCALE)) chunks[-1].append(chunks[-1].points[0]) chunks[-1].closed = True chunks[-1].poly = sgeometry.Polygon(chunks[-1].points)
def calcWaterline(zh, cutter, s): wl = ocl.Waterline() #wl = ocl.AdaptiveWaterline() wl.setSTL(s) wl.setCutter(cutter) wl.setZ(zh) wl.setSampling(0.02) wl.setThreads(2) t_before = time.time() wl.run() t_after = time.time() calctime = t_after - t_before print(" Waterline done in ", calctime, " s") out = [] out.append(wl.getLoops()) out.append(wl.getXFibers()) out.append(wl.getYFibers()) return out
def waterline_time(zheights, diam, length, s, sampling): t_total = time.time() for zh in zheights: cutter = ocl.BallCutter(diam, length) wl = ocl.Waterline() wl.setSTL(s) wl.setCutter(cutter) wl.setZ(zh) wl.setSampling(sampling) wl.setThreads(1) wl.run() cutter_loops = wl.getLoops() for l in cutter_loops: loops.append(l) timeTotal = time.time() - t_total print " ALL Waterlines done in ", timeTotal, " s" return timeTotal
def waterline(filepath, tool_diameter=3.0, corner_radius=0.0, step_over=1.0, x0=-10.0, x1=10.0, y0=-10.0, y1=10.0, mat_allowance=0.0, clearance=5.0, rapid_safety_space=2.0, start_depth=0.0, step_down=2.0, final_depth=-10.0, units=1.0, tolerance=0.01): mm = True if math.fabs(units) > 0.000000001: # ocl works in mm, so convert all values to mm mm = False tool_diameter *= units corner_radius *= units step_over *= units x0 *= units x1 *= units y0 *= units y1 *= units mat_allowance *= units clearance *= units rapid_safety_space *= units start_depth *= units step_down *= units final_depth *= units tolerance *= units # read the stl file, we know it is an ascii file because HeeksCNC made it s = STLSurfFromFile(filepath) if final_depth > start_depth: raise 'final_depth > start_depth' height = start_depth - final_depth zsteps = int(height / math.fabs(step_down) + 0.999999) zstep_down = height / zsteps incremental_rapid_to = rapid_safety_space - start_depth if incremental_rapid_to < 0: incremental_rapid_to = 0.1 tool_location = ocl.Point(0.0, 0.0, 0.0) for k in range(0, zsteps): z = start_depth - k * zstep_down working_diameter = tool_diameter + mat_allowance room_to_expand = True # while (room_to_expand == True): cutter = cutting_tool(working_diameter, corner_radius, 10) waterline = ocl.Waterline() waterline.setSTL(s) waterline.setSampling(tolerance) waterline.setCutter(cutter) waterline.setZ(z) waterline.run() cutter_loops = waterline.getLoops() for cutter_loop in cutter_loops: if ((cutter_loop[0].z != tool_location.z) or (tool_location.distance(cutter_loop[0]) > (tool_diameter / 2.0))): # Move above the starting point. rapid(z=clearance / units) rapid(x=cutter_loop[0].x, y=cutter_loop[0].y) tool_location.x = cutter_loop[0].x tool_location.y = cutter_loop[0].y tool_location.z = clearance / units # Feed down to the cutting depth rapid(x=cutter_loop[0].x, y=cutter_loop[0].y) tool_location.x = cutter_loop[0].x tool_location.y = cutter_loop[0].y # Cut around the solid at this level. for point in cutter_loop: feed(x=point.x, y=point.y, z=point.z) tool_location = point #if (point.x < (x0-step_over)) or (point.x > (x1+step_over)) or (point.y < (y0-step_over)) or (point.y > (y1+step_over)): # room_to_expand = False # And retract to the clearance height rapid(z=clearance / units) tool_location.z = clearance / units
def _waterline(self, obj, s, bb): import time import ocl def drawLoops(loops): nloop = 0 pp = [] pp.append(Path.Command("(waterline begin)" )) for loop in loops: p = loop[0] pp.append(Path.Command("(loop begin)" )) pp.append(Path.Command('G0', {"Z": obj.SafeHeight.Value, 'F': self.vertRapid})) pp.append(Path.Command('G0', {'X': p.x, "Y": p.y, 'F': self.horizRapid})) pp.append(Path.Command('G1', {"Z": p.z, 'F': self.vertFeed})) for p in loop[1:]: pp.append(Path.Command('G1', {'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed})) # zheight = p.z p = loop[0] pp.append(Path.Command('G1', {'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed})) pp.append(Path.Command("(loop end)" )) print(" loop ", nloop, " with ", len(loop), " points") nloop = nloop + 1 pp.append(Path.Command("(waterline end)" )) return pp depthparams = PathUtils.depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value) t_before = time.time() zheights = [i for i in depthparams] wl = ocl.Waterline() wl.setSTL(s) cutter = ocl.CylCutter(obj.ToolController.Tool.Diameter, 5) wl.setCutter(cutter) # this should be smaller than the smallest details in the STL file wl.setSampling(obj.SampleInterval) # AdaptiveWaterline() also has settings for minimum sampling interval # (see c++ code) all_loops = [] print ("zheights: {}".format(zheights)) for zh in zheights: print("calculating Waterline at z= ", zh) wl.reset() wl.setZ(zh) # height for this waterline wl.run() all_loops.append(wl.getLoops()) t_after = time.time() calctime = t_after - t_before n = 0 output = [] for loops in all_loops: # at each z-height, we may get many loops print(" %d/%d:" % (n, len(all_loops))) output.extend(drawLoops(loops)) n = n + 1 print("(" + str(calctime) + ")") return output
def _waterline(self, obj, s, bb): import ocl from PathScripts.PathUtils import depth_params, fmt import time def drawLoops(loops): nloop = 0 waterlinestring = "" waterlinestring += "(waterline begin)" for loop in loops: p = loop[0] loopstring = "(loop begin)" + "\n" loopstring += "G0 Z" + str(obj.SafeHeight.Value) + "\n" loopstring += "G0 X" + \ str(fmt(p.x)) + " Y" + str(fmt(p.y)) + "\n" loopstring += "G1 Z" + str(fmt(p.z)) + "\n" for p in loop[1:]: loopstring += "G1 X" + \ str(fmt(p.x)) + " Y" + str(fmt(p.y)) + \ " Z" + str(fmt(p.z)) + "\n" zheight = p.z p = loop[0] loopstring += "G1 X" + \ str(fmt(p.x)) + " Y" + str(fmt(p.y)) + \ " Z" + str(fmt(zheight)) + "\n" loopstring += "(loop end)" + "\n" print " loop ", nloop, " with ", len(loop), " points" nloop = nloop + 1 waterlinestring += loopstring waterlinestring += "(waterline end)" + "\n" return waterlinestring depthparams = depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value) # stlfile = "../../stl/gnu_tux_mod.stl" # surface = STLSurfaceSource(stlfile) surface = s t_before = time.time() zheights = depthparams.get_depths() wl = ocl.Waterline() # wl = ocl.AdaptiveWaterline() # this is slower, ca 60 seconds on i7 # CPU wl.setSTL(surface) diam = 0.5 length = 10.0 # any ocl MillingCutter class should work here cutter = ocl.BallCutter(diam, length) wl.setCutter(cutter) # this should be smaller than the smallest details in the STL file wl.setSampling(obj.SampleInterval) # AdaptiveWaterline() also has settings for minimum sampling interval # (see c++ code) all_loops = [] for zh in zheights: print "calculating Waterline at z= ", zh wl.reset() wl.setZ(zh) # height for this waterline wl.run() all_loops.append(wl.getLoops()) t_after = time.time() calctime = t_after - t_before n = 0 output = "" for loops in all_loops: # at each z-height, we may get many loops print " %d/%d:" % (n, len(all_loops)) output += drawLoops(loops) n = n + 1 print "(" + str(calctime) + ")" return output
myscreen.addActor(camvtk.Line(p1=(a.x, a.y, a.z), p2=(c.x, c.y, c.z))) myscreen.addActor(camvtk.Line(p1=(c.x, c.y, c.z), p2=(b.x, b.y, b.z))) myscreen.addActor(camvtk.Line(p1=(a.x, a.y, a.z), p2=(b.x, b.y, b.z))) t = ocl.Triangle(b, c, a) s = ocl.STLSurf() s.addTriangle(t) # a one-triangle STLSurf zheight = 0.15 # the z-coordinate for the waterline diam = 0.6 length = 5 loops = [] #cutter = ocl.CylCutter( 1 , 1 ) cutter = ocl.CylCutter(diam, length) #cutter = ocl.BallCutter( diam , length ) #cutter = ocl.BullCutter( diam , diam/5, length ) wl = ocl.Waterline() #wl.setThreads(1) wl.setSTL(s) wl.setCutter(cutter) wl.setZ(zheight) wl.setSampling(0.1) t_before = time.time() wl.run() t_after = time.time() calctime = t_after - t_before print(" Waterline done in ", calctime, " s") cutter_loops = wl.getLoops() for l in cutter_loops: loops.append(l) #print loops print("All waterlines done. Got", len(loops), " loops in total.")
elif op_cutter_type == 'BALL': cutter = ocl.BallCutter(op_cutter_diameter * 1000, cutter_length) elif op_cutter_type == 'VCARVE': cutter = ocl.ConeCutter(op_cutter_diameter * 1000, 1, cutter_length) else: print "Cutter unsupported: " + op_cutter_type + '\n' quit() wl_height_file = open(tempfile.gettempdir() + '/ocl_wl_heights.txt', 'r') waterline_heights = [] for line in wl_height_file: waterline_heights.append(float(line.split()[0])) wl_height_file.close() wl_index = 0 for height in waterline_heights: print(str(height) + '\n') waterline = ocl.Waterline() waterline.setSTL(stl_surf) waterline.setCutter(cutter) waterline.setZ(height) waterline.setSampling(0.3) waterline.run() wl_loops = waterline.getLoops() wl_file = open( tempfile.gettempdir() + '/oclWaterline' + str(wl_index) + '.txt', 'w') for l in wl_loops: wl_file.write('l\n') for p in l: wl_file.write(str(p.x) + ' ' + str(p.y) + ' ' + str(p.z) + '\n') wl_file.close() wl_index += 1
print " loop ", nloop, " with ", len(lop), " points" nloop = nloop + 1 if __name__ == "__main__": stlfile = "../../stl/gnu_tux_mod.stl" surface = STLSurfaceSource(stlfile) t_before = time.time() zheights = [ 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6 ] #zheights=[float(1.0)] # for faster computation, calculate only one waterline wl = ocl.Waterline() # total time 14 seconds on i7 CPU #wl = ocl.AdaptiveWaterline() # this is slower, ca 60 seconds on i7 CPU wl.setSTL(surface) diam = 0.5 length = 10 cutter = ocl.BallCutter( diam, length) # any ocl MillingCutter class should work here wl.setCutter(cutter) wl.setSampling( 0.0314 ) # this should be smaller than the smallest details in the STL file # AdaptiveWaterline() also has settings for minimum sampling interval (see c++ code) all_loops = [] for zh in zheights: print "calculating Waterline at z= ", zh wl.reset()
def generate(self): self.set_tool(tool=self._tool) stepdown = min(self.stepdown * self.material_factor, 2) * self.tool.diameter boundary = self.get_boundary() if isinstance(self.boundary, (tuple, list)): minx, miny, maxx, maxy = self.boundary self.boundary = Polygon(( (minx, miny), (minx, maxy), (maxx, maxy), (maxy, miny), )) cutter = self.ocl_cutter() minz = self.minZ if self.minZ is not None else self.surface.range[2][0] maxz = self.maxZ if self.maxZ is not None else self.surface.range[2][1] clearz = self.clearZ or maxz if self.adaptive: wl = ocl.AdaptiveWaterline( ) # this is slower, ca 60 seconds on i7 CPU wl.setMinSampling(0.01) else: wl = ocl.Waterline() # total time 14 seconds on i7 CPU surf = self.surface.get_ocl_stl_surf() wl.setSTL(surf) # surface MUST be saved in a variable first wl.setCutter(cutter) wl.setSampling( 0.0314 ) # this should be smaller than the smallest details in the STL file for zh in frange(maxz, minz, stepdown): wl.reset() wl.setZ(zh) # height for this waterline wl.run() for path in wl.getLoops(): fpath = self.filter_path(path, self.tolerance) coords = [(a.x, a.y, a.z) for a in fpath] coords.append(coords[0]) ls = LineString(coords) inter = boundary.intersection(ls) if isinstance(inter, MultiLineString): print "MULTI" for lx in inter: self.cut_linestring(lx, zh, clearz=clearz) #Line(lx.coords).graph(fig=fig) elif isinstance(inter, LineString): print "SINGLE" self.cut_linestring(inter, zh, clearz=clearz) #Line(inter.coords).graph(fig=fig) elif isinstance(inter, GeometryCollection): for foo in inter: print "COLLECTION", foo.__class__ sys.exit(0) else: print "WEIRD", inter.__class__ sys.exit(0)
def waterline(filepath, tool_diameter=3.0, corner_radius=0.0, cutter_length=0.0, x0=-10.0, x1=10.0, y0=-10.0, y1=10.0, mat_allowance=0.0, clearance=5.0, rapid_safety_space=2.0, start_depth=0.0, step_down=2.0, final_depth=-10.0, units=1.0, tolerance=0.01): mm = True if math.fabs(units) > 0.000000001: # ocl works in mm, so convert all values to mm mm = False tool_diameter *= units corner_radius *= units cutter_length *= units x0 *= units x1 *= units y0 *= units y1 *= units mat_allowance *= units clearance *= units rapid_safety_space *= units start_depth *= units step_down *= units final_depth *= units tolerance *= units cut_flag = True first_move = True # read the stl file, we know it is an ascii file because HeeksCNC made it s = STLSurfFromFile(filepath) if final_depth > start_depth: raise Exception('final_depth > start_depth') height = start_depth - final_depth zsteps = int(height / math.fabs(step_down) + 0.999999) zstep_down = height / zsteps incremental_rapid_to = rapid_safety_space - start_depth if incremental_rapid_to < 0: incremental_rapid_to = 0.1 tool_location = ocl.Point(0.0, 0.0, 0.0) for k in range(0, zsteps): z = start_depth - k * zstep_down working_diameter = tool_diameter + mat_allowance room_to_expand = True # while (room_to_expand == True): cutter = cutting_tool(working_diameter, corner_radius, cutter_length) waterline = ocl.Waterline() #waterline = ocl.AdaptiveWaterline() waterline.setSTL(s) waterline.setSampling(tolerance) waterline.setCutter(cutter) waterline.setZ(z) waterline.run() cutter_loops = waterline.getLoops() for cutter_loop in cutter_loops: if ((cutter_loop[0].z != tool_location.z) or (tool_location.distance(cutter_loop[0]) > (tool_diameter / 2.0))): # Move above the starting point. rapid(z=clearance / units) if (x0 <= cutter_loop[0].x / units <= x1) and ( y0 <= cutter_loop[0].y / units <= y1): #boundary check rapid(x=cutter_loop[0].x / units, y=cutter_loop[0].y / units) tool_location.x = cutter_loop[0].x / units tool_location.y = cutter_loop[0].y / units tool_location.z = clearance / units # Feed down to the cutting depth if (x0 <= tool_location.x / units <= x1) and ( y0 <= tool_location.y / units <= y1): #boundary check feed(tool_location.x, tool_location.y, z / units) # Cut around the solid at this level. for point in cutter_loop: if (x0 <= point.x <= x1) and (y0 <= point.y <= y1): #boundary check if cut_flag == False: rapid(x=point.x / units, y=point.y / units) cut_flag = True else: if first_move == True: rapid(x=point.x / units, y=point.y / units) #rapid over to xy then feed down feed(z=point.z / units) first_move = False else: feed(x=point.x / units, y=point.y / units, z=point.z / units) tool_location = point else: cut_flag = False # And retract to the clearance height rapid(z=clearance / units)
def _waterline(self, obj, s, bb): import time import ocl def drawLoops(loops): nloop = 0 pp = [] pp.append(Path.Command("(waterline begin)")) for loop in loops: p = loop[0] pp.append(Path.Command("(loop begin)")) pp.append( Path.Command('G0', { "Z": obj.SafeHeight.Value, 'F': self.vertRapid })) pp.append( Path.Command('G0', { 'X': p.x, "Y": p.y, 'F': self.horizRapid })) pp.append(Path.Command('G1', {"Z": p.z, 'F': self.vertFeed})) prev = ocl.Point(float("inf"), float("inf"), float("inf")) next = ocl.Point(float("inf"), float("inf"), float("inf")) optimize = obj.Optimize for i in range(1, len(loop)): p = loop[i] if i < len(loop) - 1: next.x = loop[i + 1].x next.y = loop[i + 1].y next.z = loop[i + 1].z else: optimize = False if not optimize or not self.isPointOnLine( FreeCAD.Vector(prev.x, prev.y, prev.z), FreeCAD.Vector(next.x, next.y, next.z), FreeCAD.Vector(p.x, p.y, p.z)): pp.append( Path.Command('G1', { 'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed })) prev.x = p.x prev.y = p.y prev.z = p.z # zheight = p.z p = loop[0] pp.append( Path.Command('G1', { 'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed })) pp.append(Path.Command("(loop end)")) print(" loop ", nloop, " with ", len(loop), " points") nloop = nloop + 1 pp.append(Path.Command("(waterline end)")) return pp depthparams = PathUtils.depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value) t_before = time.time() zheights = [i for i in depthparams] wl = ocl.Waterline() wl.setSTL(s) if obj.ToolController.Tool.ToolType == 'BallEndMill': cutter = ocl.BallCutter( obj.ToolController.Tool.Diameter, 5 ) # TODO: 5 represents cutting edge height. Should be replaced with the data from toolcontroller? else: cutter = ocl.CylCutter(obj.ToolController.Tool.Diameter, 5) wl.setCutter(cutter) # this should be smaller than the smallest details in the STL file wl.setSampling(obj.SampleInterval) # AdaptiveWaterline() also has settings for minimum sampling interval # (see c++ code) all_loops = [] print("zheights: {}".format(zheights)) for zh in zheights: print("calculating Waterline at z= ", zh) wl.reset() wl.setZ(zh) # height for this waterline wl.run() all_loops.append(wl.getLoops()) t_after = time.time() calctime = t_after - t_before n = 0 output = [] for loops in all_loops: # at each z-height, we may get many loops print(" %d/%d:" % (n, len(all_loops))) output.extend(drawLoops(loops)) n = n + 1 print("(" + str(calctime) + ")") return output