Bug fixes:

fixes reparenting bug when dressup is deleted
Engrave wasn't using final depth value
Dragknife Dressup not correctly calculating spin direction or curve intersection
Per Yorik, fix crash if PartGui hasn't been loaded
Allow selection of bottom face for profiling
Bug # 0002615
This commit is contained in:
sliptonic 2016-08-02 14:38:42 -05:00 committed by Yorik van Havre
parent 1c89c566c9
commit 0ea9cc8c43
7 changed files with 77 additions and 59 deletions

View File

@ -58,6 +58,7 @@ PyMODINIT_FUNC initPathGui()
return;
}
try {
Base::Interpreter().runString("import PartGui");
Base::Interpreter().runString("import Path");
}
catch(const Base::Exception& e) {

View File

@ -34,7 +34,7 @@
<x>0</x>
<y>0</y>
<width>304</width>
<height>379</height>
<height>349</height>
</rect>
</property>
<attribute name="icon">
@ -123,28 +123,16 @@
<string>Depths</string>
</attribute>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="Gui::InputField" name="startDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Start Depth</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Gui::InputField" name="finalDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Final Depth</string>
@ -205,8 +193,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>349</height>
<width>231</width>
<height>38</height>
</rect>
</property>
<attribute name="icon">

View File

@ -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:

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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