diff --git a/src/Mod/Path/Gui/AppPathGui.cpp b/src/Mod/Path/Gui/AppPathGui.cpp index 74fe4ce62..3d0545634 100644 --- a/src/Mod/Path/Gui/AppPathGui.cpp +++ b/src/Mod/Path/Gui/AppPathGui.cpp @@ -58,6 +58,7 @@ PyMODINIT_FUNC initPathGui() return; } try { + Base::Interpreter().runString("import PartGui"); Base::Interpreter().runString("import Path"); } catch(const Base::Exception& e) { diff --git a/src/Mod/Path/Gui/Resources/panels/EngraveEdit.ui b/src/Mod/Path/Gui/Resources/panels/EngraveEdit.ui index 9a5423d0c..783ec1193 100644 --- a/src/Mod/Path/Gui/Resources/panels/EngraveEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/EngraveEdit.ui @@ -34,7 +34,7 @@ 0 0 304 - 379 + 349 @@ -123,28 +123,16 @@ Depths + + QFormLayout::AllNonFixedFieldsGrow + - mm - - - Start Depth - - - - - - - mm - - - - Final Depth @@ -205,8 +193,8 @@ 0 0 - 304 - 349 + 231 + 38 diff --git a/src/Mod/Path/PathScripts/DragknifeDressup.py b/src/Mod/Path/PathScripts/DragknifeDressup.py index d83e4653e..03a3b1aeb 100644 --- a/src/Mod/Path/PathScripts/DragknifeDressup.py +++ b/src/Mod/Path/PathScripts/DragknifeDressup.py @@ -25,7 +25,7 @@ import FreeCAD import FreeCADGui import Path -import PathGui +#import PathGui from PySide import QtCore, QtGui import math import DraftVecUtils as D @@ -66,35 +66,67 @@ class ObjectDressup: def __setstate__(self, state): return None - def getIncidentAngle(self, queue): - global currLocation - '''returns in the incident angle in radians between the current and previous moves''' + def shortcut(self, queue): + '''Determines whether its shorter to twist CW or CCW to align with the next move''' # get the vector of the last move + + global arccommands + if queue[1].Name in arccommands: - print queue - print currLocation - arcLoc = FreeCAD.Base.Vector(queue[2].X + queue[1].I, queue[2].Y + queue[1].J, currLocation['Z']) - radvector = queue[1].Placement.Base.sub(arcLoc) # vector of chord from center to point + arcLoc = FreeCAD.Vector(queue[2].x + queue[1].I, queue[2].y + queue[1].J, currLocation['Z']) + radvector = arcLoc.sub(queue[1].Placement.Base) #.sub(arcLoc) # vector of chord from center to point # vector of line perp to chord. - v1 = radvector.cross(FreeCAD.Base.Vector(0, 0, 1)) + v1 = radvector.cross(FreeCAD.Vector(0, 0, 1)) else: v1 = queue[1].Placement.Base.sub(queue[2].Placement.Base) # get the vector of the current move if queue[0].Name in arccommands: - arcLoc = FreeCAD.Base.Vector((queue[1].x + queue[0].I), (queue[1].y + queue[0].J), currLocation['Z']) + arcLoc = FreeCAD.Vector( (queue[1].x + queue[0].I), (queue[1].y + queue[0].J), currLocation['Z']) radvector = queue[1].Placement.Base.sub(arcLoc) # calculate arcangle - - v2 = radvector.cross(FreeCAD.Base.Vector(0, 0, 1)) - - # if switching between G2 and G3, reverse orientation - if queue[1].Name in arccommands: - if queue[0].Name != queue[1].Name: - v2 = D.rotate2D(v2, math.radians(180)) + v2 = radvector.cross(FreeCAD.Vector(0, 0, 1)) else: v2 = queue[0].Placement.Base.sub(queue[1].Placement.Base) - incident_angle = D.angle(v1, v2, FreeCAD.Base.Vector(0, 0, -1)) + if (v2.x * v1.y) - (v2.y * v1.x) >= 0: + return "CW" + else: + return "CCW" + + def segmentAngleXY(self, prevCommand, currCommand, endpos=False, currentZ=0): + '''returns in the starting angle in radians for a Path command. + requires the previous command in order to calculate arcs correctly + if endpos = True, return the angle at the end of the segment.''' + + global arccommands + if currCommand.Name in arccommands: + arcLoc = FreeCAD.Vector( (prevCommand.x + currCommand.I), (prevCommand.y + currCommand.J), currentZ) + if endpos is True: + radvector = arcLoc.sub(currCommand.Placement.Base) #Calculate vector at start of arc + else: + radvector = arcLoc.sub(prevCommand.Placement.Base) #Calculate vector at end of arc + + v1 = radvector.cross(FreeCAD.Vector(0, 0, 1)) + if currCommand.Name in ["G2", "G02"]: + v1 = D.rotate2D(v1, math.radians(180)) + else: + v1 = currCommand.Placement.Base.sub(prevCommand.Placement.Base) #Straight segments are easy + + myAngle = D.angle(v1, FreeCAD.Base.Vector(1, 0, 0), FreeCAD.Base.Vector(0, 0, -1)) + return myAngle + + def getIncidentAngle(self, queue): + # '''returns in the incident angle in radians between the current and previous moves''' + + angleatend = float(math.degrees(self.segmentAngleXY(queue[2], queue[1], True))) + if angleatend < 0: + angleatend = 360 + angleatend + angleatstart = float(math.degrees(self.segmentAngleXY(queue[1], queue[0]))) + if angleatstart < 0: + angleatstart = 360 + angleatstart + + incident_angle = angleatend-angleatstart + return incident_angle def arcExtension(self, obj, queue): @@ -184,8 +216,6 @@ class ObjectDressup: # calculate IJ offsets of twist arc from current position. offsetvector = C.sub(lastXY) - # I = offsetvector.x - # J = offsetvector.y # add G2/G3 move arcmove = Path.Command( @@ -201,12 +231,8 @@ class ObjectDressup: # The old arc move won't work so calculate a replacement command offsetv = arccenter.sub(endpointvector) - # I = offsetv.x - # J = offsetv.y - replace = Path.Command( queue[0].Name, {"X": queue[0].X, "Y": queue[0].Y, "I": offsetv.x, "J": offsetv.y}) - return (results, replace) def lineExtension(self, obj, queue): @@ -353,10 +379,11 @@ class ObjectDressup: if changedXYFlag and (len(queue) == 3): # check if the inciden angle incident exceeds the filter - incident_angle = math.degrees(self.getIncidentAngle(queue)) + incident_angle = self.getIncidentAngle(queue) if abs(incident_angle) >= obj.filterangle: - if incident_angle >= 0: + if self.shortcut(queue) == "CW": + #if incident_angle >= 0: twistCW = True else: twistCW = False @@ -434,6 +461,11 @@ class ViewProviderDressup: def __setstate__(self, state): return None + def onDelete(self, arg1=None, arg2=None): + FreeCADGui.ActiveDocument.getObject(arg1.Object.Base.Name).Visibility = True + P.addToProject(arg1.Object.Base) + return True + class CommandDragknifeDressup: diff --git a/src/Mod/Path/PathScripts/PathDressup.py b/src/Mod/Path/PathScripts/PathDressup.py index cf2d604f6..f4ff2cb2a 100644 --- a/src/Mod/Path/PathScripts/PathDressup.py +++ b/src/Mod/Path/PathScripts/PathDressup.py @@ -24,7 +24,7 @@ import FreeCAD import FreeCADGui import Path -import PathGui +import PathScripts.PathUtils as P from PySide import QtCore, QtGui """Path Dressup object and FreeCAD command""" @@ -99,6 +99,11 @@ class ViewProviderDressup: def __setstate__(self, state): return None + def onDelete(self, arg1=None, arg2=None): + '''this makes sure that the base operation is added back to the project and visible''' + FreeCADGui.ActiveDocument.getObject(arg1.Object.Base.Name).Visibility = True + P.addToProject(arg1.Object.Base) + return True class CommandPathDressup: diff --git a/src/Mod/Path/PathScripts/PathEngrave.py b/src/Mod/Path/PathScripts/PathEngrave.py index 46ee968ba..70139b040 100644 --- a/src/Mod/Path/PathScripts/PathEngrave.py +++ b/src/Mod/Path/PathScripts/PathEngrave.py @@ -65,7 +65,6 @@ class ObjectPathEngrave: # Depth Properties obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", "The height needed to clear clamps and obstructions") obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", "Rapid Safety Height between locations.") - obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", "Starting Depth of Tool- first cut depth in Z") obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", "Final Depth of Tool- lowest value in Z") obj.addProperty("App::PropertyInteger", "StartVertex", "Path", "The vertex index to start the path from") @@ -161,7 +160,7 @@ class ObjectPathEngrave: # we set the first move to our first point last = edge.Vertexes[0].Point output += "G0" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.SafeHeight.Value) # Rapid sto starting position - output += "G1" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(last.z) + "F " + PathUtils.fmt(self.vertFeed) + "\n" # Vertical feed to depth + output += "G1" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.FinalDepth.Value) + "F " + PathUtils.fmt(self.vertFeed) + "\n" # Vertical feed to depth if isinstance(edge.Curve, Part.Circle): point = edge.Vertexes[-1].Point if point == last: # edges can come flipped @@ -174,7 +173,7 @@ class ObjectPathEngrave: output += "G2" else: output += "G3" - output += " X" + PathUtils.fmt(point.x) + " Y" + PathUtils.fmt(point.y) + " Z" + PathUtils.fmt(point.z) + output += " X" + PathUtils.fmt(point.x) + " Y" + PathUtils.fmt(point.y) + " Z" + PathUtils.fmt(obj.FinalDepth.Value) output += " I" + PathUtils.fmt(relcenter.x) + " J" + PathUtils.fmt(relcenter.y) + " K" + PathUtils.fmt(relcenter.z) output += " F " + PathUtils.fmt(self.horizFeed) output += "\n" @@ -183,7 +182,7 @@ class ObjectPathEngrave: point = edge.Vertexes[-1].Point if point == last: # edges can come flipped point = edge.Vertexes[0].Point - output += "G1 X" + PathUtils.fmt(point.x) + " Y" + PathUtils.fmt(point.y) + " Z" + PathUtils.fmt(point.z) + output += "G1 X" + PathUtils.fmt(point.x) + " Y" + PathUtils.fmt(point.y) + " Z" + PathUtils.fmt(obj.FinalDepth.Value) output += " F " + PathUtils.fmt(self.horizFeed) output += "\n" last = point @@ -195,15 +194,13 @@ class ObjectPathEngrave: if len(baselist) == 0: # When adding the first base object, guess at heights try: bb = ss.Shape.BoundBox # parent boundbox - obj.StartDepth = bb.ZMax obj.ClearanceHeight = bb.ZMax + 5.0 obj.SafeHeight = bb.ZMax + 3.0 obj.FinalDepth = bb.ZMax - 1 except: - obj.StartDepth = 5.0 - obj.FinalDepth = 4.0 obj.ClearanceHeight = 10.0 obj.SafeHeight = 8.0 + obj.FinalDepth = 4.0 item = (ss, "") if item in baselist: @@ -262,7 +259,6 @@ class CommandPathEngrave: FreeCADGui.doCommand('PathScripts.PathEngrave.ObjectPathEngrave(obj)') FreeCADGui.doCommand('obj.ClearanceHeight = 10') - FreeCADGui.doCommand('obj.StartDepth= 0') FreeCADGui.doCommand('obj.FinalDepth= -0.1') FreeCADGui.doCommand('obj.SafeHeight= 5.0') FreeCADGui.doCommand('obj.Active = True') @@ -292,8 +288,6 @@ class TaskPanel: def getFields(self): if self.obj: - if hasattr(self.obj, "StartDepth"): - self.obj.StartDepth = self.form.startDepth.text() if hasattr(self.obj, "FinalDepth"): self.obj.FinalDepth = self.form.finalDepth.text() if hasattr(self.obj, "SafeHeight"): @@ -304,7 +298,6 @@ class TaskPanel: self.obj.Proxy.execute(self.obj) def setFields(self): - self.form.startDepth.setText(str(self.obj.StartDepth.Value)) self.form.finalDepth.setText(str(self.obj.FinalDepth.Value)) self.form.safeHeight.setText(str(self.obj.SafeHeight.Value)) self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value)) @@ -367,7 +360,6 @@ class TaskPanel: def setupUi(self): # Connect Signals and Slots - self.form.startDepth.editingFinished.connect(self.getFields) self.form.finalDepth.editingFinished.connect(self.getFields) self.form.safeHeight.editingFinished.connect(self.getFields) self.form.clearanceHeight.editingFinished.connect(self.getFields) diff --git a/src/Mod/Path/PathScripts/PathPocket.py b/src/Mod/Path/PathScripts/PathPocket.py index 15cff974d..5c1f9bd9f 100644 --- a/src/Mod/Path/PathScripts/PathPocket.py +++ b/src/Mod/Path/PathScripts/PathPocket.py @@ -487,7 +487,7 @@ class CommandPathPocket: return {'Pixmap': 'Path-Pocket', 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathPocket", "Pocket"), 'Accel': "P, O", - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathPocket", "Creates a Path Pocket object from a loop of edges or a face")} + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathPocket", "Creates a Path Pocket object from a face or faces")} def IsActive(self): return FreeCAD.ActiveDocument is not None diff --git a/src/Mod/Path/PathScripts/PathProfile.py b/src/Mod/Path/PathScripts/PathProfile.py index 3a6c9407b..559e77aba 100644 --- a/src/Mod/Path/PathScripts/PathProfile.py +++ b/src/Mod/Path/PathScripts/PathProfile.py @@ -303,7 +303,7 @@ print "y - " + str(point.y) # we only consider the outer wire if this is a Face # Horizontal and vertical faces are handled differently shape = getattr(b[0].Shape, sub) - if numpy.isclose(shape.normalAt(0, 0).z, 1): # horizontal face + if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face hfaces.append(shape) elif numpy.isclose(shape.normalAt(0, 0).z, 0): # vertical face