Path: Contour works on clones and other objects with proxy and shape.
This commit is contained in:
committed by
Yorik van Havre
parent
d27870e7e3
commit
b28ed1de02
@@ -34,7 +34,7 @@ from PathScripts.PathUtils import waiting_effects
|
||||
from PathScripts.PathUtils import makeWorkplane
|
||||
|
||||
LOG_MODULE = 'PathContour'
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, LOG_MODULE)
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
PathLog.trackModule('PathContour')
|
||||
FreeCAD.setLogLevel('Path.Area', 0)
|
||||
|
||||
@@ -42,6 +42,7 @@ if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtGui
|
||||
|
||||
|
||||
# Qt tanslation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
@@ -77,9 +78,6 @@ class ObjectContour:
|
||||
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"))
|
||||
obj.Direction = ['CW', 'CCW'] # this is the direction that the Contour runs
|
||||
obj.addProperty("App::PropertyBool", "UseComp", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if using Cutter Radius Compensation"))
|
||||
# obj.addProperty("App::PropertyEnumeration", "Side", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "Side of edge that tool should cut"))
|
||||
# obj.Side = ['Left', 'Right'] # side of profile that cutter is on in relation to direction of profile
|
||||
# obj.setEditorMode('Side', 2) # hide
|
||||
|
||||
obj.addProperty("App::PropertyDistance", "OffsetExtra", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra value to stay away from final Contour- good for roughing toolpath"))
|
||||
|
||||
@@ -98,11 +96,6 @@ class ObjectContour:
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
pass
|
||||
# if prop == "UseComp":
|
||||
# if not obj.UseComp:
|
||||
# obj.setEditorMode('Side', 2)
|
||||
# else:
|
||||
# obj.setEditorMode('Side', 0)
|
||||
|
||||
def setDepths(proxy, obj):
|
||||
PathLog.track()
|
||||
@@ -133,7 +126,7 @@ class ObjectContour:
|
||||
profile.add(baseobject)
|
||||
|
||||
profileparams = {'Fill': 0,
|
||||
'Coplanar': 0}
|
||||
'Coplanar': 2}
|
||||
|
||||
if obj.UseComp is False:
|
||||
profileparams['Offset'] = 0.0
|
||||
@@ -244,8 +237,10 @@ class ObjectContour:
|
||||
# Let's always start by rapid to clearance...just for safety
|
||||
commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value}))
|
||||
|
||||
isPanel = False
|
||||
if hasattr(baseobject, "Proxy"):
|
||||
if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet
|
||||
isPanel = True
|
||||
baseobject.Proxy.execute(baseobject)
|
||||
shapes = baseobject.Proxy.getOutlines(baseobject, transform=True)
|
||||
for shape in shapes:
|
||||
@@ -255,15 +250,16 @@ class ObjectContour:
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, contourshape, start=obj.StartPoint).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintError(e)
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
else:
|
||||
|
||||
if hasattr(baseobject, "Shape") and not isPanel:
|
||||
bb = baseobject.Shape.BoundBox
|
||||
env = PathUtils.getEnvelope(partshape=baseobject.Shape, subshape=None, stockheight=bb.ZLength + (obj.StartDepth.Value-bb.ZMax))
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, env, start=obj.StartPoint).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintError(e)
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
|
||||
path = Path.Path(commandlist)
|
||||
|
||||
@@ -178,7 +178,7 @@ class ObjectFace:
|
||||
'Angle': obj.ZigZagAngle,
|
||||
'FromCenter': (obj.StartAt == "Center"),
|
||||
'PocketStepover': stepover,
|
||||
'PocketExtraOffset': obj.PassExtension.Value}
|
||||
'PocketExtraOffset': 0 - obj.PassExtension.Value}
|
||||
|
||||
Pattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
|
||||
pocketparams['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1
|
||||
|
||||
@@ -38,9 +38,10 @@ from PySide import QtGui
|
||||
|
||||
LOG_MODULE = 'PathUtils'
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
#PathLog.trackModule('PathUtils')
|
||||
# PathLog.trackModule('PathUtils')
|
||||
FreeCAD.setLogLevel('Path.Area', 0)
|
||||
|
||||
|
||||
def waiting_effects(function):
|
||||
def new_function(*args, **kwargs):
|
||||
if not FreeCAD.GuiUp:
|
||||
@@ -147,6 +148,11 @@ def isDrillable(obj, candidate, tooldiameter=None):
|
||||
PathLog.debug("Has Radius, Circle")
|
||||
if tooldiameter is not None:
|
||||
drillable = edge.Curve.Radius >= tooldiameter/2
|
||||
if not drillable:
|
||||
FreeCAD.Console.PrintMessage(
|
||||
"Found a drillable hole with diameter: {}: "
|
||||
"too small for the current tool with "
|
||||
"diameter: {}".format(edge.Curve.Radius*2, tooldiameter))
|
||||
else:
|
||||
drillable = True
|
||||
PathLog.debug("candidate is drillable: {}".format(drillable))
|
||||
@@ -277,10 +283,11 @@ def getEnvelope(partshape, subshape=None, stockheight=None):
|
||||
else:
|
||||
envelopeshape = sec.extrude(FreeCAD.Vector(0, 0, partshape.BoundBox.ZLength))
|
||||
if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG:
|
||||
removalshape=FreeCAD.ActiveDocument.addObject("Part::Feature","Envelope")
|
||||
removalshape = FreeCAD.ActiveDocument.addObject("Part::Feature", "Envelope")
|
||||
removalshape.Shape = envelopeshape
|
||||
return envelopeshape
|
||||
|
||||
|
||||
def reverseEdge(e):
|
||||
if geomType(e) == "Circle":
|
||||
arcstpt = e.valueAt(e.FirstParameter)
|
||||
@@ -610,6 +617,7 @@ def rampPlunge(edge, rampangle, destZ, startZ):
|
||||
|
||||
return rampCmds
|
||||
|
||||
|
||||
def sort_jobs(locations, keys, attractors=[]):
|
||||
""" sort holes by the nearest neighbor method
|
||||
keys: two-element list of keys for X and Y coordinates. for example ['x','y']
|
||||
@@ -624,7 +632,7 @@ def sort_jobs(locations, keys, attractors=[]):
|
||||
""" square Euclidean distance """
|
||||
d = 0
|
||||
for k in keys:
|
||||
d += (a[k] - b[k]) ** 2
|
||||
d += (a[k] - b[k]) ** 2
|
||||
|
||||
return d
|
||||
|
||||
@@ -646,7 +654,6 @@ def sort_jobs(locations, keys, attractors=[]):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
out = []
|
||||
zero = defaultdict(lambda: 0)
|
||||
|
||||
@@ -744,15 +751,16 @@ class depth_params:
|
||||
else:
|
||||
return [stop] + depths.tolist()
|
||||
|
||||
|
||||
class CollisionTester:
|
||||
|
||||
def compareBBSpace(self, bb1, bb2):
|
||||
if ( bb1.XMin == bb2.XMin and
|
||||
bb1.XMax == bb2.XMax and
|
||||
bb1.YMin == bb2.YMin and
|
||||
bb1.YMax == bb2.YMax and
|
||||
bb1.ZMin == bb2.ZMin and
|
||||
bb1.ZMax == bb2.ZMax ) :
|
||||
if (bb1.XMin == bb2.XMin and
|
||||
bb1.XMax == bb2.XMax and
|
||||
bb1.YMin == bb2.YMin and
|
||||
bb1.YMax == bb2.YMax and
|
||||
bb1.ZMin == bb2.ZMin and
|
||||
bb1.ZMax == bb2.ZMax):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -774,13 +782,13 @@ class CollisionTester:
|
||||
if self.compareBBSpace(i.BoundBox, j.BoundBox):
|
||||
match = True
|
||||
if match is True:
|
||||
#print ("Need to highlight Face{}".format(idx+1))
|
||||
# print ("Need to highlight Face{}".format(idx+1))
|
||||
colorassignment.append(intersecColor)
|
||||
else:
|
||||
colorassignment.append(baseColor)
|
||||
collisionSim = FreeCAD.ActiveDocument.addObject("Part::Feature","Collision")
|
||||
collisionSim = FreeCAD.ActiveDocument.addObject("Part::Feature", "Collision")
|
||||
collisionSim.Shape = gougedShape
|
||||
collisionSim.ViewObject.DiffuseColor=colorassignment
|
||||
collisionSim.ViewObject.DiffuseColor = colorassignment
|
||||
return collisionSim
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -47,7 +47,7 @@ class TestPathCore(PathTestBase):
|
||||
self.assertEqual(c.Parameters, {'Y': 0.5, 'X': 1})
|
||||
|
||||
#output gcode
|
||||
self.assertEqual(c.toGCode(), 'G1 X1.00000 Y0.50000')
|
||||
self.assertEqual(c.toGCode(), 'G1 X1.000000 Y0.500000')
|
||||
|
||||
#create and assign name in one
|
||||
c2=Path.Command("G2")
|
||||
@@ -61,7 +61,7 @@ class TestPathCore(PathTestBase):
|
||||
|
||||
#use placement
|
||||
self.assertEqual( str(c3.Placement), 'Placement [Pos=(34,1.2,0), Yaw-Pitch-Roll=(0,0,0)]')
|
||||
self.assertEqual( c3.toGCode(), 'G1 X34.00000 Y1.20000')
|
||||
self.assertEqual( c3.toGCode(), 'G1 X34.000000 Y1.200000')
|
||||
p1 = FreeCAD.Placement()
|
||||
p1.Base = FreeCAD.Vector(3,2,1)
|
||||
self.assertEqual(str(p1), 'Placement [Pos=(3,2,1), Yaw-Pitch-Roll=(0,0,0)]')
|
||||
@@ -96,7 +96,7 @@ class TestPathCore(PathTestBase):
|
||||
self.assertEqual(str(p.Commands), '[Command G1 [ X:1 Y:0 ], Command G1 [ X:0 Y:2 ]]')
|
||||
self.assertAlmostEqual( p.Length, 3.2361, places=4)
|
||||
p.addCommands(c1)
|
||||
self.assertEqual(p.toGCode(), 'G1 X1.00000 Y0.00000\nG1 X0.00000 Y2.00000\nG1 X1.00000 Y0.00000\n')
|
||||
self.assertEqual(p.toGCode(), 'G1 X1.000000 Y0.000000\nG1 X0.000000 Y2.000000\nG1 X1.000000 Y0.000000\n')
|
||||
|
||||
lines = '''
|
||||
G0X-0.5905Y-0.3937S3000M03
|
||||
@@ -109,20 +109,15 @@ G1X-0.5905Y-0.3937
|
||||
G0Z0.5
|
||||
'''
|
||||
|
||||
|
||||
<<<<<<< d3838802b1665892c464bce8a340531cafcb66f2
|
||||
output = '''G0 S3000.000000 X-0.590500 Y-0.393700
|
||||
=======
|
||||
output = '''G0 S3000.00000 X0.-59050 Y0.-39370
|
||||
>>>>>>> Path: add output precision option to linuxcnc post.
|
||||
M03
|
||||
G0 Z0.12500
|
||||
G1 F3.00000 Z0.0-400
|
||||
G1 F14.17000 X0.98420 Y0.-39370
|
||||
G1 X0.98420 Y0.43300
|
||||
G1 X0.-59050 Y0.43300
|
||||
G1 X0.-59050 Y0.-39370
|
||||
G0 Z0.50000
|
||||
G0 Z0.125000
|
||||
G1 F3.000000 Z-0.004000
|
||||
G1 F14.170000 X0.984200 Y-0.393700
|
||||
G1 X0.984200 Y0.433000
|
||||
G1 X-0.590500 Y0.433000
|
||||
G1 X-0.590500 Y-0.393700
|
||||
G0 Z0.500000
|
||||
'''
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user