PATH: conversion of PathContour to PathArea nearly complete
Path: improve contour to use makeSections
This commit is contained in:
@@ -23,19 +23,19 @@
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD
|
||||
from FreeCAD import Vector
|
||||
#from FreeCAD import Vector
|
||||
import Path
|
||||
import PathScripts.PathLog as PathLog
|
||||
from PathScripts import PathUtils
|
||||
from PathScripts.PathUtils import depth_params
|
||||
from PySide import QtCore
|
||||
import TechDraw
|
||||
#import TechDraw
|
||||
import ArchPanel
|
||||
import Part
|
||||
|
||||
LOG_MODULE = 'PathContour'
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
#PathLog.trackModule('PathContour')
|
||||
PathLog.trackModule('PathContour')
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
@@ -80,14 +80,6 @@ class ObjectContour:
|
||||
# Start Point Properties
|
||||
obj.addProperty("App::PropertyVector", "StartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "The start point of this path"))
|
||||
obj.addProperty("App::PropertyBool", "UseStartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if specifying a Start Point"))
|
||||
obj.addProperty("App::PropertyLength", "ExtendAtStart", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "extra length of tool path before start of part edge"))
|
||||
obj.addProperty("App::PropertyLength", "LeadInLineLen", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "length of straight segment of toolpath that comes in at angle to first part edge"))
|
||||
|
||||
# End Point Properties
|
||||
obj.addProperty("App::PropertyBool", "UseEndPoint", "End Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if specifying an End Point"))
|
||||
obj.addProperty("App::PropertyLength", "ExtendAtEnd", "End Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "extra length of tool path after end of part edge"))
|
||||
obj.addProperty("App::PropertyLength", "LeadOutLineLen", "End Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "length of straight segment of toolpath that comes in at angle to last part edge"))
|
||||
obj.addProperty("App::PropertyVector", "EndPoint", "End Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "The end point of this path"))
|
||||
|
||||
# Contour Properties
|
||||
obj.addProperty("App::PropertyEnumeration", "Direction", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
|
||||
@@ -97,7 +89,6 @@ class ObjectContour:
|
||||
obj.Side = ['Left', 'Right', 'On'] # side of profile that cutter is on in relation to direction of profile
|
||||
obj.setEditorMode('Side', 2) # hide
|
||||
|
||||
obj.addProperty("App::PropertyDistance", "RollRadius", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "Radius at start and end"))
|
||||
obj.addProperty("App::PropertyDistance", "OffsetExtra", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra value to stay away from final Contour- good for roughing toolpath"))
|
||||
|
||||
obj.Proxy = self
|
||||
@@ -132,100 +123,62 @@ class ObjectContour:
|
||||
obj.ClearanceHeight = 10.0
|
||||
obj.SafeHeight = 8.0
|
||||
|
||||
def _buildPathArea(self, obj, edgelist, start = None):
|
||||
def _buildPathArea(self, obj, baseobject, start=None):
|
||||
PathLog.track()
|
||||
|
||||
c = Part.Wire(edgelist)
|
||||
f = Part.makeFace([c], 'Part::FaceMakerSimple')
|
||||
|
||||
profile = Path.Area(Offset=self.radius,SectionCount=1)
|
||||
profile = Path.Area()
|
||||
profile.setPlane(Part.makeCircle(10))
|
||||
profile.add(f)
|
||||
lshapes = [profile.getShape()]
|
||||
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
|
||||
|
||||
profile.setParams(**profileparams)
|
||||
PathLog.debug("About to profile with params: {}".format(profileparams))
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
print (depthparams.get_depths())
|
||||
for l in depthparams.get_depths():
|
||||
c = lshapes[0].copy()
|
||||
c.Placement.Base.z = l
|
||||
lshapes.append(c)
|
||||
sections = profile.makeSections(mode=0, project=True, heights=depthparams.get_depths())
|
||||
shapelist = [sec.getShape() for sec in sections]
|
||||
|
||||
if start is None:
|
||||
pp = Path.fromShapes(lshapes, verbose=False)
|
||||
params = {'shapes': shapelist,
|
||||
'feedrate': self.horizFeed,
|
||||
'feedrate_v': self.vertFeed,
|
||||
'verbose': True,
|
||||
'resume_height': obj.StepDown.Value,
|
||||
'retraction': obj.ClearanceHeight.Value}
|
||||
|
||||
if obj.Direction == 'CCW':
|
||||
params['orientation'] = 1
|
||||
else:
|
||||
pp = Path.fromShapes(lshapes, start, verbose=False)
|
||||
params['orientation'] = 0
|
||||
|
||||
if obj.UseStartPoint is True and obj.StartPoint is not None:
|
||||
params['start'] = obj.StartPoint
|
||||
|
||||
PathLog.debug("Generating Path with params: {}".format(params))
|
||||
pp = Path.fromShapes(**params)
|
||||
PathLog.debug(pp)
|
||||
|
||||
return pp
|
||||
|
||||
|
||||
# def _buildPathLibarea(self, obj, edgelist):
|
||||
# import PathScripts.PathKurveUtils as PathKurveUtils
|
||||
# PathLog.track()
|
||||
# # import math
|
||||
# # import area
|
||||
# output = ""
|
||||
# if obj.Comment != "":
|
||||
# output += '(' + str(obj.Comment)+')\n'
|
||||
|
||||
# if obj.StartPoint and obj.UseStartPoint:
|
||||
# startpoint = obj.StartPoint
|
||||
# else:
|
||||
# startpoint = None
|
||||
|
||||
# if obj.EndPoint and obj.UseEndPoint:
|
||||
# endpoint = obj.EndPoint
|
||||
# else:
|
||||
# endpoint = None
|
||||
|
||||
# PathKurveUtils.output('mem')
|
||||
# PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed)
|
||||
|
||||
# output = ""
|
||||
# output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
|
||||
# curve = PathKurveUtils.makeAreaCurve(edgelist, obj.Direction, startpoint, endpoint)
|
||||
|
||||
# roll_radius = 2.0
|
||||
# extend_at_start = 0.0
|
||||
# extend_at_end = 0.0
|
||||
# lead_in_line_len = 0.0
|
||||
# lead_out_line_len = 0 # obj.FinalDepth.Value, None)
|
||||
|
||||
# PathKurveUtils.profile2(
|
||||
|
||||
# if obj.UseComp is False:
|
||||
# obj.Side = 'On'
|
||||
# else:
|
||||
# if obj.Direction == 'CW':
|
||||
# obj.Side = 'Left'
|
||||
# else:
|
||||
# obj.Side = 'Right'
|
||||
|
||||
# depthparams = depth_params(
|
||||
# obj.ClearanceHeight.Value,
|
||||
# obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0,
|
||||
# obj.FinalDepth.Value, None)
|
||||
|
||||
# PathKurveUtils.profile2(
|
||||
# curve, obj.Side, self.radius, self.vertFeed, self.horizFeed,
|
||||
# self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius,
|
||||
# None, None, depthparams, extend_at_start, extend_at_end,
|
||||
# lead_in_line_len, lead_out_line_len)
|
||||
|
||||
# output += PathKurveUtils.retrieve_gcode()
|
||||
# return output
|
||||
|
||||
def execute(self, obj):
|
||||
PathLog.track()
|
||||
import Part # math #DraftGeomUtils
|
||||
commandlist = []
|
||||
#output = ""
|
||||
import Part
|
||||
|
||||
commandlist = []
|
||||
toolLoad = obj.ToolController
|
||||
|
||||
if toolLoad is None or toolLoad.ToolNumber == 0:
|
||||
@@ -236,23 +189,18 @@ class ObjectContour:
|
||||
self.horizFeed = toolLoad.HorizFeed.Value
|
||||
self.vertRapid = toolLoad.VertRapid.Value
|
||||
self.horizRapid = toolLoad.HorizRapid.Value
|
||||
tool = toolLoad.Proxy.getTool(toolLoad) #PathUtils.getTool(obj, toolLoad.ToolNumber)
|
||||
tool = toolLoad.Proxy.getTool(toolLoad)
|
||||
if not tool or tool.Diameter == 0:
|
||||
FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.")
|
||||
return
|
||||
#self.radius = 0.25
|
||||
else:
|
||||
self.radius = tool.Diameter/2
|
||||
|
||||
#output += "(" + obj.Label + ")"
|
||||
commandlist.append(Path.Command("(" + obj.Label + ")"))
|
||||
|
||||
if not obj.UseComp:
|
||||
#output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"
|
||||
commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"))
|
||||
|
||||
else:
|
||||
#output += "(Uncompensated Tool Path)"
|
||||
commandlist.append(Path.Command("(Uncompensated Tool Path)"))
|
||||
|
||||
parentJob = PathUtils.findParentJob(obj)
|
||||
@@ -269,34 +217,27 @@ class ObjectContour:
|
||||
if isinstance(subobj.Proxy, ArchPanel.PanelCut):
|
||||
shapes = baseobject.Proxy.getOutlines(baseobject, transform=True)
|
||||
for shape in shapes:
|
||||
for wire in shape.Wires:
|
||||
edgelist = wire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
PathLog.debug("Processing panel perimeter. edges found: {}".format(len(edgelist))) # subobj.Proxy.execute(subobj)
|
||||
f = Part.makeFace([shape], 'Part::FaceMakerSimple')
|
||||
thickness = baseobject.Group[0].Source.Thickness
|
||||
contourshape = f.extrude(FreeCAD.Vector(0,0, thickness))
|
||||
try:
|
||||
#output += self._buildPathLibarea(obj, edgelist)
|
||||
commandlist.extend(self._buildPathArea(obj, edgelist).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
commandlist.extend(self._buildPathArea(obj, contourshape).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
else:
|
||||
fixbase = baseobject.Shape.copy()
|
||||
fixbase.fix(0.00001,0.00001,0.00001)
|
||||
contourwire = TechDraw.findShapeOutline(fixbase, 1, Vector(0, 0, 1))
|
||||
|
||||
edgelist = contourwire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
#fixbase = baseobject.Shape.copy()
|
||||
#fixbase.fix(0.00001, 0.00001, 0.00001)
|
||||
env = PathUtils.getEnvelope(baseobject.Shape, obj.StartDepth)
|
||||
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, edgelist).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
commandlist.extend(self._buildPathArea(obj, env).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
|
||||
if obj.Active:
|
||||
path = Path.Path(commandlist)
|
||||
# for c in contourcommands.Commands:
|
||||
# path.addCommands(c)
|
||||
|
||||
obj.Path = path
|
||||
if obj.ViewObject:
|
||||
obj.ViewObject.Visibility = True
|
||||
@@ -348,26 +289,6 @@ class _CommandSetStartPoint:
|
||||
obj.StartPoint.y = point.y
|
||||
|
||||
def Activated(self):
|
||||
|
||||
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
|
||||
|
||||
|
||||
class _CommandSetEndPoint:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Path-EndPoint',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick End Point"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick End Point")}
|
||||
|
||||
def IsActive(self):
|
||||
return FreeCAD.ActiveDocument is not None
|
||||
|
||||
def setpoint(self, point, o):
|
||||
obj = FreeCADGui.Selection.getSelection()[0]
|
||||
obj.EndPoint.x = point.x
|
||||
obj.EndPoint.y = point.y
|
||||
|
||||
def Activated(self):
|
||||
|
||||
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
|
||||
|
||||
|
||||
@@ -450,14 +371,10 @@ class TaskPanel:
|
||||
self.obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value
|
||||
if hasattr(self.obj, "OffsetExtra"):
|
||||
self.obj.OffsetExtra = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value
|
||||
if hasattr(self.obj, "RollRadius"):
|
||||
self.obj.RollRadius = FreeCAD.Units.Quantity(self.form.rollRadius.text()).Value
|
||||
if hasattr(self.obj, "UseComp"):
|
||||
self.obj.UseComp = self.form.useCompensation.isChecked()
|
||||
if hasattr(self.obj, "UseStartPoint"):
|
||||
self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
|
||||
if hasattr(self.obj, "UseEndPoint"):
|
||||
self.obj.UseEndPoint = self.form.useEndPoint.isChecked()
|
||||
if hasattr(self.obj, "Direction"):
|
||||
self.obj.Direction = str(self.form.direction.currentText())
|
||||
if hasattr(self.obj, "ToolController"):
|
||||
@@ -473,10 +390,8 @@ class TaskPanel:
|
||||
self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value, FreeCAD.Units.Length).UserString)
|
||||
self.form.stepDown.setText(FreeCAD.Units.Quantity(self.obj.StepDown.Value, FreeCAD.Units.Length).UserString)
|
||||
self.form.extraOffset.setText(FreeCAD.Units.Quantity(self.obj.OffsetExtra.Value, FreeCAD.Units.Length).UserString)
|
||||
self.form.rollRadius.setText(FreeCAD.Units.Quantity(self.obj.RollRadius.Value, FreeCAD.Units.Length).UserString)
|
||||
self.form.useCompensation.setChecked(self.obj.UseComp)
|
||||
self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
|
||||
self.form.useEndPoint.setChecked(self.obj.UseEndPoint)
|
||||
|
||||
index = self.form.direction.findText(
|
||||
self.obj.Direction, QtCore.Qt.MatchFixedString)
|
||||
@@ -529,9 +444,7 @@ class TaskPanel:
|
||||
self.form.uiToolController.currentIndexChanged.connect(self.getFields)
|
||||
self.form.useCompensation.clicked.connect(self.getFields)
|
||||
self.form.useStartPoint.clicked.connect(self.getFields)
|
||||
self.form.useEndPoint.clicked.connect(self.getFields)
|
||||
self.form.extraOffset.editingFinished.connect(self.getFields)
|
||||
self.form.rollRadius.editingFinished.connect(self.getFields)
|
||||
|
||||
self.setFields()
|
||||
|
||||
@@ -554,6 +467,5 @@ if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Contour', CommandPathContour())
|
||||
FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint())
|
||||
FreeCADGui.addCommand('Set_EndPoint', _CommandSetEndPoint())
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathContour... done\n")
|
||||
|
||||
@@ -33,6 +33,7 @@ import numpy
|
||||
import PathLog
|
||||
#from math import pi
|
||||
from FreeCAD import Vector
|
||||
import Path
|
||||
|
||||
LOG_MODULE = 'PathUtils'
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
@@ -193,6 +194,22 @@ def filterArcs(arcEdge):
|
||||
pass
|
||||
return splitlist
|
||||
|
||||
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
|
||||
'''
|
||||
area = Path.Area(Fill=1, Coplanar=0).add(partshape)
|
||||
area.setPlane(Part.makeCircle(10))
|
||||
sec = area.makeSections(heights=[1.0], project=True)[0].getShape(rebuild=True)
|
||||
if stockheight is not None:
|
||||
return sec.extrude(FreeCAD.Vector(0, 0, stockheight))
|
||||
else:
|
||||
return sec.extrude(FreeCAD.Vector(0, 0, partshape.BoundBox.ZMax))
|
||||
|
||||
def reverseEdge(e):
|
||||
if geomType(e) == "Circle":
|
||||
|
||||
Reference in New Issue
Block a user