def getEnvelope(partshape, subshape=None, depthparams=None): ''' getEnvelope(partshape, stockheight=None) returns a shape corresponding to the partshape silhouette extruded to height. if stockheight is given, the returned shape is extruded to that height otherwise the returned shape is the height of the original shape boundbox partshape = solid object stockheight = float - Absolute Z height of the top of material before cutting. ''' PathLog.track(partshape, subshape, depthparams) # if partshape.Volume == 0.0: #Not a 3D object # return None zShift = 0 if subshape is not None: if isinstance(subshape, Part.Face): PathLog.debug('processing a face') sec = Part.makeCompound([subshape]) else: area = Path.Area(Fill=2, Coplanar=0).add(subshape) area.setPlane(makeWorkplane(partshape)) PathLog.debug("About to section with params: {}".format( area.getParams())) sec = area.makeSections(heights=[0.0], project=True)[0].getShape() # zShift = partshape.BoundBox.ZMin - subshape.BoundBox.ZMin PathLog.debug('partshapeZmin: {}, subshapeZMin: {}, zShift: {}'.format( partshape.BoundBox.ZMin, subshape.BoundBox.ZMin, zShift)) else: area = Path.Area(Fill=2, Coplanar=0).add(partshape) area.setPlane(makeWorkplane(partshape)) sec = area.makeSections(heights=[0.0], project=True)[0].getShape() # If depthparams are passed, use it to calculate bottom and height of # envelope if depthparams is not None: # eLength = float(stockheight)-partshape.BoundBox.ZMin eLength = depthparams.safe_height - depthparams.final_depth #envelopeshape = sec.extrude(FreeCAD.Vector(0, 0, eLength)) zShift = depthparams.final_depth - sec.BoundBox.ZMin PathLog.debug('boundbox zMIN: {} elength: {} zShift {}'.format( partshape.BoundBox.ZMin, eLength, zShift)) else: eLength = partshape.BoundBox.ZLength - sec.BoundBox.ZMin # Shift the section based on selection and depthparams. newPlace = FreeCAD.Placement(FreeCAD.Vector(0, 0, zShift), sec.Placement.Rotation) sec.Placement = newPlace # Extrude the section to top of Boundbox or desired height envelopeshape = sec.extrude(FreeCAD.Vector(0, 0, eLength)) if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG: removalshape = FreeCAD.ActiveDocument.addObject( "Part::Feature", "Envelope") removalshape.Shape = envelopeshape return envelopeshape
def _extractFaceOffset(self, obj, fcShape, isHole): '''_extractFaceOffset(obj, fcShape, isHole) ... internal function. Original _buildPathArea() version copied from PathAreaOp.py module. This version is modified. Adjustments made based on notes by @sliptonic - https://github.com/sliptonic/FreeCAD/wiki/PathArea-notes.''' PathLog.debug('_extractFaceOffset()') areaParams = {} JOB = PathUtils.findParentJob(obj) tolrnc = JOB.GeometryTolerance.Value if self.useComp is True: offset = self.ofstRadius # + tolrnc else: offset = self.offsetExtra # + tolrnc if isHole is False: offset = 0 - offset areaParams['Offset'] = offset areaParams['Fill'] = 1 areaParams['Coplanar'] = 0 areaParams[ 'SectionCount'] = 1 # -1 = full(all per depthparams??) sections areaParams['Reorient'] = True areaParams['OpenMode'] = 0 areaParams['MaxArcPoints'] = 400 # 400 areaParams['Project'] = True # areaParams['JoinType'] = 1 area = Path.Area() # Create instance of Area() class object area.setPlane(PathUtils.makeWorkplane(fcShape)) # Set working plane area.add(fcShape) # obj.Shape to use for extracting offset area.setParams(**areaParams) # set parameters return area.getShape()
def _buildPathArea(self, obj, baseobject, isHole, start, getsim): '''_buildPathArea(obj, baseobject, isHole, start, getsim) ... internal function.''' # pylint: disable=unused-argument PathLog.track() area = Path.Area() area.setPlane(PathUtils.makeWorkplane(baseobject)) area.add(baseobject) areaParams = self.areaOpAreaParams(obj, isHole) # pylint: disable=assignment-from-no-return if hasattr(obj, 'ExpandProfile') and obj.ExpandProfile != 0: areaParams = self.areaOpAreaParamsExpandProfile(obj, isHole) # pylint: disable=assignment-from-no-return heights = [i for i in self.depthparams] PathLog.debug('depths: {}'.format(heights)) area.setParams(**areaParams) obj.AreaParams = str(area.getParams()) PathLog.debug("Area with params: {}".format(area.getParams())) sections = area.makeSections(mode=0, project=self.areaOpUseProjection(obj), heights=heights) PathLog.debug("sections = %s" % sections) shapelist = [sec.getShape() for sec in sections] PathLog.debug("shapelist = %s" % shapelist) pathParams = self.areaOpPathParams(obj, isHole) # pylint: disable=assignment-from-no-return pathParams['shapes'] = shapelist pathParams['feedrate'] = self.horizFeed pathParams['feedrate_v'] = self.vertFeed pathParams['verbose'] = True pathParams['resume_height'] = obj.SafeHeight.Value pathParams['retraction'] = obj.ClearanceHeight.Value pathParams['return_end'] = True # Note that emitting preambles between moves breaks some dressups and prevents path optimization on some controllers pathParams['preamble'] = False if not self.areaOpRetractTool(obj): pathParams['threshold'] = 2.001 * self.radius if self.endVector is not None: pathParams['start'] = self.endVector elif PathOp.FeatureStartPoint & self.opFeatures(obj) and obj.UseStartPoint: pathParams['start'] = obj.StartPoint obj.PathParams = str({key: value for key, value in pathParams.items() if key != 'shapes'}) PathLog.debug("Path with params: {}".format(obj.PathParams)) (pp, end_vector) = Path.fromShapes(**pathParams) PathLog.debug('pp: {}, end vector: {}'.format(pp, end_vector)) self.endVector = end_vector # pylint: disable=attribute-defined-outside-init simobj = None if getsim: areaParams['Thicken'] = True areaParams['ToolRadius'] = self.radius - self.radius * .005 area.setParams(**areaParams) sec = area.makeSections(mode=0, project=False, heights=heights)[-1].getShape() simobj = sec.extrude(FreeCAD.Vector(0, 0, baseobject.BoundBox.ZMax)) return pp, simobj
def _buildPathArea(self, obj, baseobject, start=None, getsim=False): PathLog.track() profile = Path.Area() profile.setPlane(makeWorkplane(baseobject)) profile.add(baseobject) profileparams = {'Fill': 0, 'Coplanar': 2} if obj.UseComp is False: profileparams['Offset'] = 0.0 else: profileparams['Offset'] = self.radius + obj.OffsetExtra.Value heights = [i for i in self.depthparams] PathLog.debug('depths: {}'.format(heights)) profile.setParams(**profileparams) #obj.AreaParams = str(profile.getParams()) PathLog.debug("Contour with params: {}".format(profile.getParams())) sections = profile.makeSections(mode=0, project=True, heights=heights) shapelist = [sec.getShape() for sec in sections] params = { 'shapes': shapelist, 'feedrate': self.horizFeed, 'feedrate_v': self.vertFeed, 'verbose': True, 'resume_height': obj.StepDown.Value, 'retraction': obj.ClearanceHeight.Value, 'return_end': True } if obj.Direction == 'CCW': params['orientation'] = 1 else: params['orientation'] = 0 if self.endVector is not None: params['start'] = self.endVector elif start is not None: params['start'] = start (pp, end_vector) = Path.fromShapes(**params) PathLog.debug("Generating Path with params: {}".format(params)) PathLog.debug('pp: {}, end vector: {}'.format(pp, end_vector)) self.endVector = end_vector simobj = None if getsim: profileparams[ 'Thicken'] = True #{'Fill':0, 'Coplanar':0, 'Project':True, 'SectionMode':2, 'Thicken':True} profileparams['ToolRadius'] = self.radius - self.radius * .005 profile.setParams(**profileparams) sec = profile.makeSections(mode=0, project=False, heights=heights)[-1].getShape() simobj = sec.extrude(FreeCAD.Vector(0, 0, baseobject.BoundBox.ZMax)) return pp, simobj
def _buildPathArea(self, obj, baseobject, start=None): PathLog.track() profile = Path.Area() profile.setPlane(makeWorkplane(baseobject)) profile.add(baseobject) profileparams = {'Fill': 0, 'Coplanar': 0} if obj.UseComp is False: profileparams['Offset'] = 0.0 else: profileparams['Offset'] = self.radius + obj.OffsetExtra.Value depthparams = depth_params(clearance_height=obj.ClearanceHeight.Value, rapid_safety_space=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=0.0, final_depth=obj.FinalDepth.Value, user_depths=None) PathLog.debug('depths: {}'.format(depthparams.get_depths())) profile.setParams(**profileparams) PathLog.debug("Contour with params: {}".format(profile.getParams())) sections = profile.makeSections(mode=0, project=True, heights=depthparams.get_depths()) shapelist = [sec.getShape() for sec in sections] params = { 'shapes': shapelist, 'feedrate': self.horizFeed, 'feedrate_v': self.vertFeed, 'verbose': True, 'resume_height': obj.StepDown.Value, 'retraction': obj.ClearanceHeight.Value, 'return_end': True } if obj.Direction == 'CCW': params['orientation'] = 1 else: params['orientation'] = 0 if self.endVector is not None: params['start'] = self.endVector elif start is not None: params['start'] = start (pp, end_vector) = Path.fromShapes(**params) PathLog.debug("Generating Path with params: {}".format(params)) PathLog.debug('pp: {}, end vector: {}'.format(pp, end_vector)) self.endVector = end_vector return pp
def _buildPathArea(self, obj, baseobject): """build the face path using PathArea""" PathLog.track() boundary = Path.Area() boundary.setPlane(makeWorkplane(baseobject)) boundary.add(baseobject) stepover = (self.radius * 2) * (float(obj.StepOver)/100) pocketparams = {'Fill': 0, 'Coplanar': 0, 'PocketMode': 1, 'SectionCount': -1, 'Angle': obj.ZigZagAngle, 'FromCenter': (obj.StartAt == "Center"), 'PocketStepover': stepover, 'PocketExtraOffset': 0 - obj.PassExtension.Value} Pattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle'] pocketparams['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1 offsetval = self.radius pocketparams['ToolRadius'] = offsetval heights = [i for i in self.depthparams] boundary.setParams(**pocketparams) obj.AreaParams = str(boundary.getParams()) sections = boundary.makeSections(mode=0, project=False, heights=heights) params = {'feedrate': self.horizFeed, 'feedrate_v': self.vertFeed, 'verbose': True, 'resume_height': obj.StepDown, 'retraction': obj.ClearanceHeight.Value} pp = [] if obj.UseStartPoint and obj.StartPoint is not None: params['start'] = obj.StartPoint # store the params for debugging. Don't need the shape. obj.PathParams = str(params) PathLog.debug("Generating Path with params: {}".format(params)) for sec in sections: shape = sec.getShape() respath = Path.fromShapes(shape, **params) # Insert any entry code to the layer # append the layer path pp.extend(respath.Commands) respath.Commands = pp return respath
def _buildPathArea(self, obj, baseobject): """build the face path using PathArea""" PathLog.track() boundary = Path.Area() boundary.setPlane(makeWorkplane(baseobject)) boundary.add(baseobject) stepover = (self.radius * 2) * (float(obj.StepOver) / 100) pocketparams = { 'Fill': 0, 'Coplanar': 0, 'PocketMode': 1, 'SectionCount': -1, 'Angle': obj.ZigZagAngle, 'FromCenter': (obj.StartAt == "Center"), 'PocketStepover': stepover, 'PocketExtraOffset': 0 - obj.PassExtension.Value } Pattern = [ 'ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle' ] pocketparams['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1 offsetval = self.radius pocketparams['ToolRadius'] = offsetval heights = [i for i in self.depthparams] boundary.setParams(**pocketparams) #obj.AreaParams = str(boundary.getParams()) #PathLog.track('areaparams: {}'.format(obj.AreaParams)) PathLog.track('height: {}'.format(heights)) sections = boundary.makeSections(mode=0, project=False, heights=heights) shapelist = [sec.getShape() for sec in sections] params = { 'shapes': shapelist, 'feedrate': self.horizFeed, 'feedrate_v': self.vertFeed, 'verbose': True, 'resume_height': obj.StepDown, 'retraction': obj.ClearanceHeight.Value } PathLog.debug("Generating Path with params: {}".format(params)) pp = Path.fromShapes(**params) return pp
def _buildPathArea(self, obj, baseobject, isHole, start, getsim): '''_buildPathArea(obj, baseobject, isHole, start, getsim) ... internal function.''' PathLog.track() area = Path.Area() area.setPlane(PathUtils.makeWorkplane(baseobject)) area.add(baseobject) areaParams = self.areaOpAreaParams(obj, isHole) heights = [i for i in self.depthparams] PathLog.debug('depths: {}'.format(heights)) area.setParams(**areaParams) obj.AreaParams = str(area.getParams()) PathLog.debug("Area with params: {}".format(area.getParams())) sections = area.makeSections(mode=0, project=self.areaOpUseProjection(obj), heights=heights) PathLog.debug("sections = %s" % sections) shapelist = [sec.getShape() for sec in sections] PathLog.debug("shapelist = %s" % shapelist) pathParams = self.areaOpPathParams(obj, isHole) pathParams['shapes'] = shapelist pathParams['feedrate'] = self.horizFeed pathParams['feedrate_v'] = self.vertFeed pathParams['verbose'] = True pathParams['resume_height'] = obj.StepDown.Value pathParams['retraction'] = obj.ClearanceHeight.Value pathParams['return_end'] = True if self.endVector is not None: pathParams['start'] = self.endVector elif PathOp.FeatureStartPoint & self.opFeatures(obj) and obj.UseStartPoint: pathParams['start'] = obj.StartPoint obj.PathParams = str({key: value for key, value in pathParams.items() if key != 'shapes'}) PathLog.debug("Path with params: {}".format(obj.PathParams)) (pp, end_vector) = Path.fromShapes(**pathParams) PathLog.debug('pp: {}, end vector: {}'.format(pp, end_vector)) self.endVector = end_vector simobj = None if getsim: areaParams['Thicken'] = True areaParams['ToolRadius'] = self.radius - self.radius * .005 area.setParams(**areaParams) sec = area.makeSections(mode=0, project=False, heights=heights)[-1].getShape() simobj = sec.extrude(FreeCAD.Vector(0, 0, baseobject.BoundBox.ZMax)) return pp, simobj
def get_part_outline(self): ''' Get Part Outline ''' sections = Path.Area().add(self.model[0].Shape).makeSections( mode=0, heights=[0.0], project=True, plane=self.stock_silhoutte) part_silhoutte = sections[0].setParams(Offset=0.0).getShape() part_bound_face = sections[0].setParams(Offset=0.1).getShape() path_area = self.stock_silhoutte.cut(part_silhoutte) part_edges = [] part_segments = [] for edge in path_area.Edges: edge_in = True for vertex in edge.Vertexes: if not part_bound_face.isInside(vertex.Point, 0.1, True): edge_in = False if edge_in: # if self.part_edges.__contains__(edge) == False: part_edges.append(edge) vert = edge.Vertexes pt1 = Point(vert[0].X, vert[0].Y, vert[0].Z) pt2 = Point(vert[-1].X, vert[-1].Y, vert[-1].Z) seg = Segment(pt1, pt2) if isinstance(edge.Curve, Part.Circle): # rad = edge.Curve.Radius # angle = 2 * math.asin((seg.get_length()/2) / rad) line1 = Part.makeLine(edge.Curve.Location, edge.Vertexes[0].Point) line2 = Part.makeLine(edge.Curve.Location, edge.Vertexes[-1].Point) part_edges.append(line1) part_edges.append(line2) angle = edge.LastParameter - edge.FirstParameter direction = edge.Curve.Axis.y # print('bulge angle', direction, angle * direction) # TODO: set the correct sign for the bulge +- seg.set_bulge(angle * direction) part_segments.append(seg) # path_profile = Part.makeCompound(part_edges) # Part.show(path_profile, 'Final_pass') return part_segments
def getOffsetArea( fcShape, offset, removeHoles=False, # Default: XY plane plane=Part.makeCircle(10), tolerance=1e-4, ): """Make an offset area of a shape, projected onto a plane. Positive offsets expand the area, negative offsets shrink it. Inspired by _buildPathArea() from PathAreaOp.py module. Adjustments made based on notes by @sliptonic at this webpage: https://github.com/sliptonic/FreeCAD/wiki/PathArea-notes.""" PathLog.debug("getOffsetArea()") areaParams = {} areaParams["Offset"] = offset areaParams["Fill"] = 1 # 1 areaParams["Outline"] = removeHoles areaParams["Coplanar"] = 0 areaParams["SectionCount"] = 1 # -1 = full(all per depthparams??) sections areaParams["Reorient"] = True areaParams["OpenMode"] = 0 areaParams["MaxArcPoints"] = 400 # 400 areaParams["Project"] = True areaParams["FitArcs"] = False # Can be buggy & expensive areaParams["Deflection"] = tolerance areaParams["Accuracy"] = tolerance areaParams["Tolerance"] = 1e-5 # Equal point tolerance areaParams["Simplify"] = True areaParams["CleanDistance"] = tolerance / 5 area = Path.Area() # Create instance of Area() class object # Set working plane normal to Z=1 area.setPlane(makeWorkplane(plane)) area.add(fcShape) area.setParams(**areaParams) # set parameters offsetShape = area.getShape() if not offsetShape.Faces: return False return offsetShape
def getEnvelope(partshape, stockheight=None): ''' getEnvelop(partshape, stockheight=None) returns a shape corresponding to the partshape silhouette extruded to height. if stockheight is given, the returned shape is extruded to that height otherwise the returned shape is the height of the original shape boundbox partshape = solid object stockheight = float ''' PathLog.track(partshape, stockheight) area = Path.Area(Fill=1, Coplanar=0).add(partshape) # loc = FreeCAD.Vector(partshape.BoundBox.Center.x, # partshape.BoundBox.Center.y, # partshape.BoundBox.ZMin) area.setPlane(makeWorkplane(partshape)) sec = area.makeSections(heights=[1.0], project=True)[0].getShape() if stockheight is not None: return sec.extrude(FreeCAD.Vector(0, 0, stockheight)) else: return sec.extrude(FreeCAD.Vector(0, 0, partshape.BoundBox.ZLength))
def _buildPathArea(self, obj, envelopeshape, getsim=False): PathLog.track() pocket = Path.Area() pocket.setPlane(Part.makeCircle(10)) pocket.add(envelopeshape) stepover = (self.radius * 2) * (float(obj.StepOver) / 100) pocketparams = { 'Fill': 0, 'Coplanar': 0, 'PocketMode': 1, 'SectionCount': -1, 'Angle': obj.ZigZagAngle, 'FromCenter': (obj.StartAt == "Center"), 'PocketStepover': stepover, 'PocketExtraOffset': obj.MaterialAllowance.Value } offsetval = self.radius pocketparams['ToolRadius'] = offsetval Pattern = [ 'ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle' ] pocketparams['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1 pocket.setParams(**pocketparams) obj.AreaParams = str(pocket.getParams()) PathLog.debug("Pocketing with params: {}".format(pocket.getParams())) heights = [i for i in self.depthparams] PathLog.debug('pocket section heights: {}'.format(heights)) sections = pocket.makeSections(mode=0, project=False, heights=heights) shapelist = [sec.getShape() for sec in sections] params = { 'shapes': shapelist, 'feedrate': self.horizFeed, 'feedrate_v': self.vertFeed, 'verbose': True, 'resume_height': obj.StepDown.Value, 'retraction': obj.ClearanceHeight.Value } pp = Path.fromShapes(**params) PathLog.debug("Generating Path with params: {}".format(params)) PathLog.debug(pp) simobj = None if getsim: pocketparams['Thicken'] = True pocketparams['ToolRadius'] = self.radius - self.radius * .005 pocketparams['Stepdown'] = -1 pocket.setParams(**pocketparams) #pocket.makeSections(mode=0, project=False, heights=heights) simobj = pocket.getShape().extrude( FreeCAD.Vector(0, 0, obj.StepDown.Value)) #removalshape = FreeCAD.ActiveDocument.addObject("Part::Feature", "simshape") return pp, simobj
def _buildPathArea(self, obj, envelopeshape, getsim=False): PathLog.track() pocket = Path.Area() pocket.setPlane(Part.makeCircle(10)) pocket.add(envelopeshape) stepover = (self.radius * 2) * (float(obj.StepOver)/100) pocketparams = {'Fill': 0, 'Coplanar': 0, 'PocketMode': 1, 'SectionCount': -1, 'Angle': obj.ZigZagAngle, 'FromCenter': (obj.StartAt == "Center"), 'PocketStepover': stepover, 'PocketExtraOffset': obj.MaterialAllowance.Value} offsetval = self.radius pocketparams['ToolRadius'] = offsetval Pattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle'] pocketparams['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1 pocket.setParams(**pocketparams) obj.AreaParams = str(pocket.getParams()) PathLog.debug("Pocketing with params: {}".format(pocket.getParams())) heights = [i for i in self.depthparams] PathLog.debug('pocket section heights: {}'.format(heights)) sections = pocket.makeSections(mode=0, project=False, heights=heights) shapelist = [sec.getShape() for sec in sections] params = {'shapes': shapelist, 'feedrate': self.horizFeed, 'feedrate_v': self.vertFeed, 'verbose': True, 'resume_height': obj.StepDown.Value, 'retraction': obj.ClearanceHeight.Value} if obj.UseStartPoint and obj.StartPoint is not None: params['start'] = obj.StartPoint # if MinTravel is turned on, set path sorting to 3DSort # 3DSort shouldn't be used without a valid start point. Can cause # tool crash without it. if obj.MinTravel: params['sort_mode'] = 2 obj.PathParams = str({key: value for key, value in params.items() if key != 'shapes'}) pp = Path.fromShapes(**params) PathLog.debug("Generating Path with params: {}".format(params)) PathLog.debug(pp) simobj = None if getsim: pocketparams['Thicken'] = True pocketparams['ToolRadius'] = self.radius - self.radius * .005 pocketparams['Stepdown'] = -1 pocket.setParams(**pocketparams) simobj = pocket.getShape().extrude(FreeCAD.Vector(0, 0, obj.StepDown.Value)) return pp, simobj
def get_part_outline(self): ''' Get Part Outline ''' # TODO: Revisit the edge extraction and find a more elegant method model = self.model[0].Shape # get a section through the part origin on the XZ Plane sections = Path.Area().add(model).makeSections( mode=0, heights=[0.0], project=True, plane=self.stock_silhoutte) part_silhoutte = sections[0].setParams(Offset=0.0).getShape() # get an offset section larger than the part section part_bound_face = sections[0].setParams(Offset=0.1).getShape() # ensure the cutplane is larger than the part or segments will be missed modelBB = model.BoundBox plane_length = modelBB.ZLength * 1.5 plane_width = (modelBB.XLength / 2) * 1.5 z_ref = modelBB.ZMax + (plane_length - modelBB.ZLength) / 2 # create a plane larger than the part cut_plane = Part.makePlane(plane_length, plane_width, FreeCAD.Vector(-plane_width, 0, z_ref), FreeCAD.Vector(0, -1, 0)) # Cut the part section from the cut plane path_area = cut_plane.cut(part_silhoutte) part_edges = [] part_segments = [] # interate through the edges and check if each is inside the bound_face for edge in path_area.Edges: edge_in = True for vertex in edge.Vertexes: if not part_bound_face.isInside(vertex.Point, 0.1, True): edge_in = False if edge_in: part_edges.append(edge) vert = edge.Vertexes pt1 = Point(vert[0].X, vert[0].Y, vert[0].Z) pt2 = Point(vert[-1].X, vert[-1].Y, vert[-1].Z) seg = Segment(pt1, pt2) if isinstance(edge.Curve, Part.Circle): line1 = Part.makeLine(edge.Curve.Location, edge.Vertexes[0].Point) line2 = Part.makeLine(edge.Curve.Location, edge.Vertexes[-1].Point) part_edges.append(line1) part_edges.append(line2) angle = edge.LastParameter - edge.FirstParameter direction = edge.Curve.Axis.y # print('bulge angle', direction, angle * direction) # TODO: set the correct sign for the bulge +- seg.set_bulge(angle * direction) part_segments.append(seg) # path_profile = Part.makeCompound(part_edges) # Part.show(path_profile, 'Final_pass') return part_segments
def _buildPathArea(self, obj, baseobject, isHole, start, getsim): """_buildPathArea(obj, baseobject, isHole, start, getsim) ... internal function.""" PathLog.track() area = Path.Area() area.setPlane(PathUtils.makeWorkplane(baseobject)) area.add(baseobject) areaParams = self.areaOpAreaParams(obj, isHole) heights = [i for i in self.depthparams] PathLog.debug("depths: {}".format(heights)) area.setParams(**areaParams) obj.AreaParams = str(area.getParams()) PathLog.debug("Area with params: {}".format(area.getParams())) sections = area.makeSections(mode=0, project=self.areaOpUseProjection(obj), heights=heights) PathLog.debug("sections = %s" % sections) shapelist = [sec.getShape() for sec in sections] PathLog.debug("shapelist = %s" % shapelist) pathParams = self.areaOpPathParams(obj, isHole) pathParams["shapes"] = shapelist pathParams["feedrate"] = self.horizFeed pathParams["feedrate_v"] = self.vertFeed pathParams["verbose"] = True pathParams["resume_height"] = obj.SafeHeight.Value pathParams["retraction"] = obj.ClearanceHeight.Value pathParams["return_end"] = True # Note that emitting preambles between moves breaks some dressups and prevents path optimization on some controllers pathParams["preamble"] = False if not self.areaOpRetractTool(obj): pathParams["threshold"] = 2.001 * self.radius if self.endVector is not None: pathParams["start"] = self.endVector elif PathOp.FeatureStartPoint & self.opFeatures( obj) and obj.UseStartPoint: pathParams["start"] = obj.StartPoint obj.PathParams = str({ key: value for key, value in pathParams.items() if key != "shapes" }) PathLog.debug("Path with params: {}".format(obj.PathParams)) (pp, end_vector) = Path.fromShapes(**pathParams) PathLog.debug("pp: {}, end vector: {}".format(pp, end_vector)) self.endVector = end_vector simobj = None if getsim: areaParams["Thicken"] = True areaParams["ToolRadius"] = self.radius - self.radius * 0.005 area.setParams(**areaParams) sec = area.makeSections(mode=0, project=False, heights=heights)[-1].getShape() simobj = sec.extrude(FreeCAD.Vector(0, 0, baseobject.BoundBox.ZMax)) return pp, simobj
def _buildPathArea(self, obj, baseobject, start=None, getsim=False): PathLog.track() profile = Path.Area() profile.setPlane(Part.makeCircle(10)) profile.add(baseobject) profileparams = { 'Fill': 0, 'Coplanar': 0, 'Offset': 0.0, 'SectionCount': -1 } if obj.UseComp: if obj.Side == 'Right': profileparams[ 'Offset'] = 0 - self.radius + obj.OffsetExtra.Value else: profileparams['Offset'] = self.radius + obj.OffsetExtra.Value profile.setParams(**profileparams) obj.AreaParams = str(profile.getParams()) PathLog.debug("About to profile with params: {}".format( profile.getParams())) heights = [i for i in self.depthparams] sections = profile.makeSections(mode=0, project=True, heights=heights) shapelist = [sec.getShape() for sec in sections] params = { 'shapes': shapelist, 'feedrate': self.horizFeed, 'feedrate_v': self.vertFeed, 'verbose': False, 'resume_height': obj.StepDown.Value, 'retraction': obj.ClearanceHeight.Value } if obj.Direction == 'CCW': params['orientation'] = 0 else: params['orientation'] = 1 if obj.UseStartPoint is True and obj.StartPoint is not None: params['start'] = obj.StartPoint pp = Path.fromShapes(**params) PathLog.debug("Generating Path with params: {}".format(params)) # store the params for debugging. Don't need the shape. obj.PathParams = str( {key: value for key, value in params.items() if key != 'shapes'}) simobj = None if getsim: profileparams['Thicken'] = True profileparams['ToolRadius'] = self.radius - self.radius * .005 profile.setParams(**profileparams) sec = profile.makeSections(mode=0, project=False, heights=heights)[-1].getShape() simobj = sec.extrude(FreeCAD.Vector(0, 0, baseobject.BoundBox.ZMax)) return pp, simobj
def _buildPathArea(self, obj, baseobject, start=None, getsim=False): PathLog.track() profile = Path.Area() profile.setPlane(makeWorkplane(baseobject)) profile.add(baseobject) profileparams = {'Fill': 0, 'Coplanar': 2} if obj.UseComp is False: profileparams['Offset'] = 0.0 else: profileparams['Offset'] = self.radius + obj.OffsetExtra.Value jointype = ['Round', 'Square', 'Miter'] profileparams['JoinType'] = jointype.index(obj.JoinType) if obj.JoinType == 'Miter': profileparams['MiterLimit'] = obj.MiterLimit heights = [i for i in self.depthparams] PathLog.debug('depths: {}'.format(heights)) profile.setParams(**profileparams) obj.AreaParams = str(profile.getParams()) PathLog.debug("Contour with params: {}".format(profile.getParams())) sections = profile.makeSections(mode=0, project=True, heights=heights) shapelist = [sec.getShape() for sec in sections] params = { 'shapes': shapelist, 'feedrate': self.horizFeed, 'feedrate_v': self.vertFeed, 'verbose': True, 'resume_height': obj.StepDown.Value, 'retraction': obj.ClearanceHeight.Value, 'return_end': True } if obj.Direction == 'CCW': params['orientation'] = 0 else: params['orientation'] = 1 if self.endVector is not None: params['start'] = self.endVector elif obj.UseStartPoint: params['start'] = obj.StartPoint obj.PathParams = str( {key: value for key, value in params.items() if key != 'shapes'}) (pp, end_vector) = Path.fromShapes(**params) PathLog.debug('pp: {}, end vector: {}'.format(pp, end_vector)) self.endVector = end_vector simobj = None if getsim: profileparams['Thicken'] = True profileparams['ToolRadius'] = self.radius - self.radius * .005 profile.setParams(**profileparams) sec = profile.makeSections(mode=0, project=False, heights=heights)[-1].getShape() simobj = sec.extrude(FreeCAD.Vector(0, 0, baseobject.BoundBox.ZMax)) return pp, simobj
def _buildPathArea(self, obj, baseobject, isHole=False, start=None, getsim=False): PathLog.track() profile = Path.Area() profile.setPlane(Part.makeCircle(10)) profile.add(baseobject) profileparams = {'Fill': 0, 'Coplanar': 2, 'Offset': 0.0, 'SectionCount': -1} offsetval = 0 if obj.UseComp: offsetval = self.radius+obj.OffsetExtra.Value if obj.Side == 'Inside': offsetval = 0 - offsetval if isHole: offsetval = 0 - offsetval profileparams['Offset'] = offsetval jointype = ['Round', 'Square', 'Miter'] profileparams['JoinType'] = jointype.index(obj.JoinType) if obj.JoinType == 'Miter': profileparams['MiterLimit'] = obj.MiterLimit profile.setParams(**profileparams) obj.AreaParams = str(profile.getParams()) # PathLog.debug("About to profile with params: {}".format(profileparams)) PathLog.debug("About to profile with params: {}".format(profile.getParams())) heights = [i for i in self.depthparams] sections = profile.makeSections(mode=0, project=True, heights=heights) shapelist = [sec.getShape() for sec in sections] params = {'shapes': shapelist, 'feedrate': self.horizFeed, 'feedrate_v': self.vertFeed, 'verbose': True, 'resume_height': obj.StepDown.Value, 'retraction': obj.ClearanceHeight.Value} # Reverse the direction for holes if isHole: direction = "CW" if obj.Direction == "CCW" else "CCW" else: direction = obj.Direction if direction == 'CCW': params['orientation'] = 0 else: params['orientation'] = 1 if obj.UseStartPoint is True and obj.StartPoint is not None: params['start'] = obj.StartPoint pp = Path.fromShapes(**params) obj.PathParams = str({key: value for key, value in params.items() if key != 'shapes'}) PathLog.debug("Generating Path with params: {}".format(params)) PathLog.debug(pp) simobj = None if getsim: profileparams['Thicken'] = True profileparams['ToolRadius'] = self.radius - self.radius * .005 profile.setParams(**profileparams) sec = profile.makeSections(mode=0, project=False, heights=heights)[-1].getShape() simobj = sec.extrude(FreeCAD.Vector(0, 0, baseobject.BoundBox.ZMax)) return pp, simobj