Merge branch 'master' of github.com:FreeCAD/FreeCAD
This commit is contained in:
@@ -30,8 +30,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>292</height>
|
||||
<width>108</width>
|
||||
<height>92</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -82,7 +82,7 @@
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="Gui::InputField" name="stepDown">
|
||||
<property name="minimum">
|
||||
<property name="minimum" stdset="0">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
@@ -97,8 +97,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>292</height>
|
||||
<width>141</width>
|
||||
<height>65</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -147,8 +147,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>292</height>
|
||||
<width>336</width>
|
||||
<height>303</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -212,13 +212,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="useEndPoint">
|
||||
<property name="text">
|
||||
<string>Use End Point</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -238,19 +231,9 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="Gui::InputField" name="rollRadius">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="Gui::InputField" name="extraOffset">
|
||||
<property name="minimum">
|
||||
<property name="minimum" stdset="0">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
@@ -258,13 +241,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Roll Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>323</width>
|
||||
<height>482</height>
|
||||
<width>379</width>
|
||||
<height>523</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
@@ -33,7 +33,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>305</width>
|
||||
<width>361</width>
|
||||
<height>277</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -111,8 +111,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>305</width>
|
||||
<height>124</height>
|
||||
<width>361</width>
|
||||
<height>130</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -192,8 +192,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>305</width>
|
||||
<height>109</height>
|
||||
<width>361</width>
|
||||
<height>130</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -242,8 +242,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>289</width>
|
||||
<height>297</height>
|
||||
<width>361</width>
|
||||
<height>329</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -254,94 +254,6 @@
|
||||
<string>Operation</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="0">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="2">
|
||||
<widget class="Gui::QuantitySpinBox" name="zigZagAngle">
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="useZigZag">
|
||||
<property name="text">
|
||||
<string>Use ZigZag</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="zigZagUnidirectional">
|
||||
<property name="text">
|
||||
<string>ZigZag Unidirectional</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>ZigZag Angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Cut Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Boundary Shape</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QComboBox" name="boundaryShape">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Perimeter</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Boundbox</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QComboBox" name="cutMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Climb</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Conventional</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QWidget" name="widget_4" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
@@ -410,6 +322,114 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Cut Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="cutMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Climb</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Conventional</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Boundary Shape</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="boundaryShape">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Perimeter</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Boundbox</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="offsetpattern">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ZigZag</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Spiral</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ZigZagOffset</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Line</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Grid</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Triangle</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Pattern</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="zigZagAngle">
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>ZigZag Angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
||||
@@ -166,13 +166,6 @@
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QSpinBox" name="spindleSpeed">
|
||||
<property name="maximum">
|
||||
<number>99999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="cboSpindleDirection">
|
||||
<item>
|
||||
@@ -187,6 +180,9 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QDoubleSpinBox" name="spindleSpeed"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -140,7 +140,7 @@ class PathWorkbench (Workbench):
|
||||
if "Profile" or "Contour" in FreeCADGui.Selection.getSelection()[0].Name:
|
||||
#self.appendContextMenu("", ["Add_Tag"])
|
||||
self.appendContextMenu("", ["Set_StartPoint"])
|
||||
self.appendContextMenu("", ["Set_EndPoint"])
|
||||
#self.appendContextMenu("", ["Set_EndPoint"])
|
||||
if "Remote" in FreeCADGui.Selection.getSelection()[0].Name:
|
||||
self.appendContextMenu("", ["Refresh_Path"])
|
||||
|
||||
|
||||
@@ -23,18 +23,20 @@
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD
|
||||
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 ArchPanel
|
||||
import Part
|
||||
from PathScripts.PathUtils import waiting_effects
|
||||
from PathScripts.PathUtils import makeWorkplane
|
||||
|
||||
LOG_MODULE = 'PathContour'
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
#PathLog.trackModule('PathContour')
|
||||
FreeCAD.setLogLevel('Path.Area', 0)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
@@ -78,15 +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"))
|
||||
@@ -96,10 +89,10 @@ 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
|
||||
self.endVector = None
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
@@ -109,6 +102,8 @@ class ObjectContour:
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
pass
|
||||
# if prop in ['ClearanceHeight', 'StartPoint']:
|
||||
# obj.StartPoint.z = obj.ClearanceHeight.Value
|
||||
|
||||
def setDepths(proxy, obj):
|
||||
PathLog.track()
|
||||
@@ -131,65 +126,67 @@ class ObjectContour:
|
||||
obj.ClearanceHeight = 10.0
|
||||
obj.SafeHeight = 8.0
|
||||
|
||||
def _buildPathLibarea(self, obj, edgelist):
|
||||
import PathScripts.PathKurveUtils as PathKurveUtils
|
||||
@waiting_effects
|
||||
def _buildPathArea(self, obj, baseobject, start=None):
|
||||
PathLog.track()
|
||||
# import math
|
||||
# import area
|
||||
output = ""
|
||||
if obj.Comment != "":
|
||||
output += '(' + str(obj.Comment)+')\n'
|
||||
profile = Path.Area()
|
||||
profile.setPlane(makeWorkplane(baseobject))
|
||||
profile.add(baseobject)
|
||||
|
||||
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.0
|
||||
profileparams = {'Fill': 0,
|
||||
'Coplanar': 0}
|
||||
|
||||
if obj.UseComp is False:
|
||||
obj.Side = 'On'
|
||||
profileparams['Offset'] = 0.0
|
||||
else:
|
||||
if obj.Direction == 'CW':
|
||||
obj.Side = 'Left'
|
||||
else:
|
||||
obj.Side = 'Right'
|
||||
profileparams['Offset'] = self.radius+obj.OffsetExtra.Value
|
||||
|
||||
depthparams = depth_params(
|
||||
obj.ClearanceHeight.Value,
|
||||
obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0,
|
||||
obj.FinalDepth.Value, 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)
|
||||
|
||||
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)
|
||||
PathLog.debug('depths: {}'.format(depthparams.get_depths()))
|
||||
profile.setParams(**profileparams)
|
||||
PathLog.debug("Contour with params: {}".format(profile.getParams()))
|
||||
|
||||
output += PathKurveUtils.retrieve_gcode()
|
||||
return output
|
||||
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 execute(self, obj):
|
||||
PathLog.track()
|
||||
import Part # math #DraftGeomUtils
|
||||
output = ""
|
||||
self.endVector = None
|
||||
|
||||
commandlist = []
|
||||
toolLoad = obj.ToolController
|
||||
|
||||
if toolLoad is None or toolLoad.ToolNumber == 0:
|
||||
@@ -200,20 +197,19 @@ 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 + ")"
|
||||
if not obj.UseComp:
|
||||
output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"
|
||||
commandlist.append(Path.Command("(" + obj.Label + ")"))
|
||||
|
||||
if obj.UseComp:
|
||||
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)
|
||||
if parentJob is None:
|
||||
@@ -222,33 +218,33 @@ class ObjectContour:
|
||||
if baseobject is None:
|
||||
return
|
||||
|
||||
# Let's always start by rapid to clearance...just for safety
|
||||
commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value}))
|
||||
|
||||
if hasattr(baseobject, "Proxy"):
|
||||
if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet
|
||||
baseobject.Proxy.execute(baseobject)
|
||||
for subobj in baseobject.Group: # process the group of panels
|
||||
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)
|
||||
try:
|
||||
output += self._buildPathLibarea(obj, edgelist)
|
||||
except:
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
shapes = baseobject.Proxy.getOutlines(baseobject, transform=True)
|
||||
for shape in shapes:
|
||||
f = Part.makeFace([shape], 'Part::FaceMakerSimple')
|
||||
thickness = baseobject.Group[0].Source.Thickness
|
||||
contourshape = f.extrude(FreeCAD.Vector(0, 0, thickness))
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, contourshape, start=obj.StartPoint).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:
|
||||
contourwire = TechDraw.findShapeOutline(baseobject.Shape, 1, Vector(0, 0, 1))
|
||||
|
||||
edgelist = contourwire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
|
||||
bb = baseobject.Shape.BoundBox
|
||||
env = PathUtils.getEnvelope(baseobject.Shape, bb.ZLength + (obj.StartDepth.Value-bb.ZMax))
|
||||
try:
|
||||
output += self._buildPathLibarea(obj, edgelist)
|
||||
except:
|
||||
commandlist.extend(self._buildPathArea(obj, env, start=obj.StartPoint).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(output)
|
||||
path = Path.Path(commandlist)
|
||||
obj.Path = path
|
||||
if obj.ViewObject:
|
||||
obj.ViewObject.Visibility = True
|
||||
@@ -298,28 +294,9 @@ class _CommandSetStartPoint:
|
||||
obj = FreeCADGui.Selection.getSelection()[0]
|
||||
obj.StartPoint.x = point.x
|
||||
obj.StartPoint.y = point.y
|
||||
obj.StartPoint.z = obj.ClearanceHeight.Value
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -402,14 +379,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, "UseStartPoint"):
|
||||
# self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
|
||||
if hasattr(self.obj, "Direction"):
|
||||
self.obj.Direction = str(self.form.direction.currentText())
|
||||
if hasattr(self.obj, "ToolController"):
|
||||
@@ -425,10 +398,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)
|
||||
# self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
|
||||
|
||||
index = self.form.direction.findText(
|
||||
self.obj.Direction, QtCore.Qt.MatchFixedString)
|
||||
@@ -481,9 +452,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()
|
||||
|
||||
@@ -506,6 +475,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")
|
||||
|
||||
@@ -25,14 +25,11 @@
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import FreeCAD
|
||||
# from FreeCAD import Vector
|
||||
import Path
|
||||
import PathScripts.PathLog as PathLog
|
||||
# import Part
|
||||
from PySide import QtCore, QtGui
|
||||
from PathScripts import PathUtils
|
||||
from PathScripts.PathUtils import fmt
|
||||
# from math import pi
|
||||
from PathScripts.PathUtils import fmt, waiting_effects
|
||||
import ArchPanel
|
||||
|
||||
|
||||
@@ -105,9 +102,8 @@ class ObjectDrilling:
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
pass
|
||||
# if prop == "UserLabel":
|
||||
# obj.Label = obj.UserLabel + " :" + obj.ToolDescription
|
||||
|
||||
@waiting_effects
|
||||
def execute(self, obj):
|
||||
PathLog.track()
|
||||
output = ""
|
||||
|
||||
@@ -118,7 +118,8 @@ class ObjectPathEngrave:
|
||||
return
|
||||
try:
|
||||
if baseobject.isDerivedFrom('Sketcher::SketchObject') or \
|
||||
baseobject.isDerivedFrom('Part::Part2DObject'):
|
||||
baseobject.isDerivedFrom('Part::Part2DObject') or \
|
||||
hasattr(baseobject, 'ArrayType'):
|
||||
|
||||
output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
|
||||
|
||||
@@ -181,7 +182,8 @@ class ObjectPathEngrave:
|
||||
if not last:
|
||||
# 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) + "F " + PathUtils.fmt(self.horizRapid) # Rapid sto starting position
|
||||
output += "G0" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) # Rapid to starting position
|
||||
output += "G0" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.SafeHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) # Rapid to safe height
|
||||
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
|
||||
@@ -208,7 +210,7 @@ class ObjectPathEngrave:
|
||||
output += " F " + PathUtils.fmt(self.horizFeed)
|
||||
output += "\n"
|
||||
last = point
|
||||
output += "G0 Z " + PathUtils.fmt(obj.SafeHeight.Value)
|
||||
output += "G0 Z " + PathUtils.fmt(obj.ClearanceHeight.Value)
|
||||
return output
|
||||
|
||||
|
||||
|
||||
@@ -28,15 +28,15 @@ import Path
|
||||
from PySide import QtCore, QtGui
|
||||
from PathScripts import PathUtils
|
||||
import Part
|
||||
import PathScripts.PathKurveUtils
|
||||
import area
|
||||
import TechDraw
|
||||
from FreeCAD import Vector
|
||||
import PathScripts.PathLog as PathLog
|
||||
from PathScripts.PathUtils import waiting_effects
|
||||
from PathScripts.PathUtils import makeWorkplane
|
||||
|
||||
LOG_MODULE = 'PathMillFace'
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
PathLog.trackModule()
|
||||
FreeCAD.setLogLevel('Path.Area', 0)
|
||||
|
||||
FreeCADGui = None
|
||||
if FreeCAD.GuiUp:
|
||||
@@ -88,6 +88,8 @@ class ObjectFace:
|
||||
obj.addProperty("App::PropertyFloat", "ZigZagAngle", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Angle of the zigzag pattern"))
|
||||
obj.addProperty("App::PropertyEnumeration", "BoundaryShape", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Shape to use for calculating Boundary"))
|
||||
obj.BoundaryShape = ['Perimeter', 'Boundbox']
|
||||
obj.addProperty("App::PropertyEnumeration", "OffsetPattern", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "clearing pattern to use"))
|
||||
obj.OffsetPattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
|
||||
|
||||
# Start Point Properties
|
||||
obj.addProperty("App::PropertyVector", "StartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "The start point of this path"))
|
||||
@@ -159,60 +161,63 @@ class ObjectFace:
|
||||
return self.getStock(o)
|
||||
return None
|
||||
|
||||
def buildpathlibarea(self, obj, a):
|
||||
"""Build the face path using libarea algorithm"""
|
||||
|
||||
import PathScripts.PathAreaUtils as PathAreaUtils
|
||||
@waiting_effects
|
||||
def _buildPathArea(self, obj, baseobject):
|
||||
"""build the face path using PathArea"""
|
||||
from PathScripts.PathUtils import depth_params
|
||||
|
||||
PathLog.track()
|
||||
for p in a.getCurves():
|
||||
PathLog.debug(p.text())
|
||||
boundary = Path.Area()
|
||||
boundary.setPlane(makeWorkplane(baseobject))
|
||||
boundary.add(baseobject)
|
||||
|
||||
FreeCAD.Console.PrintMessage(translate("PathMillFace", "Generating toolpath with libarea offsets.\n"))
|
||||
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.PassExtension.Value}
|
||||
|
||||
Pattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
|
||||
pocketparams['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1
|
||||
|
||||
depthparams = depth_params(
|
||||
obj.ClearanceHeight.Value,
|
||||
obj.SafeHeight.Value,
|
||||
obj.StartDepth.Value,
|
||||
obj.StepDown,
|
||||
obj.FinishDepth.Value,
|
||||
obj.FinalDepth.Value)
|
||||
clearance_height=obj.ClearanceHeight.Value,
|
||||
rapid_safety_space=obj.SafeHeight.Value,
|
||||
start_depth=obj.StartDepth.Value,
|
||||
step_down=obj.StepDown,
|
||||
z_finish_step=obj.FinishDepth.Value,
|
||||
final_depth=obj.FinalDepth.Value,
|
||||
user_depths=None)
|
||||
|
||||
extraoffset = - obj.PassExtension.Value
|
||||
stepover = (self.radius * 2) * (float(obj.StepOver)/100)
|
||||
use_zig_zag = obj.UseZigZag
|
||||
zig_angle = obj.ZigZagAngle
|
||||
from_center = (obj.StartAt == "Center")
|
||||
keep_tool_down = obj.KeepToolDown
|
||||
zig_unidirectional = obj.ZigUnidirectional
|
||||
start_point = None
|
||||
cut_mode = obj.CutMode
|
||||
boundary.setParams(**pocketparams)
|
||||
sections = boundary.makeSections(mode=0, project=False, heights=depthparams.get_depths())
|
||||
shapelist = [sec.getShape() for sec in sections]
|
||||
|
||||
PathAreaUtils.flush_nc()
|
||||
PathAreaUtils.output('mem')
|
||||
PathAreaUtils.feedrate_hv(self.horizFeed, self.vertFeed)
|
||||
if obj.UseStartPoint:
|
||||
start_point = (obj.StartPoint.x, obj.StartPoint.y)
|
||||
params = {'shapes': shapelist,
|
||||
'feedrate': self.horizFeed,
|
||||
'feedrate_v': self.vertFeed,
|
||||
'verbose': True,
|
||||
'resume_height': obj.StepDown,
|
||||
'retraction': obj.ClearanceHeight.Value}
|
||||
|
||||
PathAreaUtils.pocket(
|
||||
a,
|
||||
self.radius,
|
||||
extraoffset,
|
||||
stepover,
|
||||
depthparams,
|
||||
from_center,
|
||||
keep_tool_down,
|
||||
use_zig_zag,
|
||||
zig_angle,
|
||||
zig_unidirectional,
|
||||
start_point,
|
||||
cut_mode)
|
||||
return PathAreaUtils.retrieve_gcode()
|
||||
# if obj.Direction == 'CCW':
|
||||
# params['orientation'] = 1
|
||||
# else:
|
||||
# params['orientation'] = 0
|
||||
|
||||
PathLog.debug("Generating Path with params: {}".format(params))
|
||||
pp = Path.fromShapes(**params)
|
||||
|
||||
return pp
|
||||
|
||||
def execute(self, obj):
|
||||
PathLog.track()
|
||||
output = ""
|
||||
commandlist = []
|
||||
|
||||
toolLoad = obj.ToolController
|
||||
|
||||
@@ -232,9 +237,7 @@ class ObjectFace:
|
||||
else:
|
||||
self.radius = tool.Diameter/2
|
||||
|
||||
# Build preliminary comments
|
||||
output = ""
|
||||
output += "(" + obj.Label + ")"
|
||||
commandlist.append(Path.Command("(" + obj.Label + ")"))
|
||||
|
||||
# Facing is done either against base objects
|
||||
if obj.Base:
|
||||
@@ -266,36 +269,28 @@ class ObjectFace:
|
||||
|
||||
# if user wants the boundbox, calculate that
|
||||
PathLog.info("Boundary Shape: {}".format(obj.BoundaryShape))
|
||||
bb = planeshape.BoundBox
|
||||
if obj.BoundaryShape == 'Boundbox':
|
||||
bb = planeshape.BoundBox
|
||||
bbperim = Part.makeBox(bb.XLength, bb.YLength, 1, Vector(bb.XMin, bb.YMin, bb.ZMin), Vector(0, 0, 1))
|
||||
contourwire = TechDraw.findShapeOutline(bbperim, 1, Vector(0, 0, 1))
|
||||
env = PathUtils.getEnvelope(bbperim, bb.ZLength + (obj.StartDepth.Value-bb.ZMax))
|
||||
else:
|
||||
contourwire = TechDraw.findShapeOutline(planeshape, 1, Vector(0, 0, 1))
|
||||
env = PathUtils.getEnvelope(planeshape, bb.ZLength + (obj.StartDepth.Value-bb.ZMax))
|
||||
|
||||
# pocket = Path.Area(PocketMode=4,SectionCount=-1,SectionMode=1,Stepdown=0.499)
|
||||
# pocket.setParams(PocketExtraOffset = obj.PassExtension.Value, ToolRadius = self.radius)
|
||||
# pocket.add(planeshape, op=1)
|
||||
# #Part.show(contourwire)
|
||||
# path = Path.fromShapes(pocket.getShape())
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, env).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintWarning(translate("PathMillFace", "The selected settings did not produce a valid path.\n"))
|
||||
|
||||
edgelist = contourwire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
|
||||
# use libarea to build the pattern
|
||||
a = area.Area()
|
||||
c = PathScripts.PathKurveUtils.makeAreaCurve(edgelist, 'CW')
|
||||
PathLog.debug(c.text())
|
||||
a.append(c)
|
||||
a.Reorder()
|
||||
output += self.buildpathlibarea(obj, a)
|
||||
|
||||
path = Path.Path(output)
|
||||
if len(path.Commands) == 0:
|
||||
FreeCAD.Console.PrintMessage(translate("PathMillFace", "The selected settings did not produce a valid path.\n"))
|
||||
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = True
|
||||
if obj.Active:
|
||||
path = Path.Path(commandlist)
|
||||
obj.Path = path
|
||||
if obj.ViewObject:
|
||||
obj.ViewObject.Visibility = True
|
||||
else:
|
||||
path = Path.Path("(inactive operation)")
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = False
|
||||
|
||||
|
||||
class _CommandSetFaceStartPoint:
|
||||
@@ -375,8 +370,7 @@ class CommandPathMillFace:
|
||||
FreeCADGui.doCommand('obj.StepDown = 1.0')
|
||||
FreeCADGui.doCommand('obj.StartDepth = ' + str(ztop + 1))
|
||||
FreeCADGui.doCommand('obj.FinalDepth =' + str(ztop))
|
||||
FreeCADGui.doCommand('obj.ZigZagAngle = 0.0')
|
||||
FreeCADGui.doCommand('obj.UseZigZag = True')
|
||||
FreeCADGui.doCommand('obj.ZigZagAngle = 45.0')
|
||||
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
|
||||
FreeCADGui.doCommand('obj.ToolController = PathScripts.PathUtils.findToolController(obj)')
|
||||
snippet = '''
|
||||
@@ -436,16 +430,15 @@ class TaskPanel:
|
||||
self.obj.PassExtension = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value
|
||||
if hasattr(self.obj, "CutMode"):
|
||||
self.obj.CutMode = str(self.form.cutMode.currentText())
|
||||
if hasattr(self.obj, "UseZigZag"):
|
||||
self.obj.UseZigZag = self.form.useZigZag.isChecked()
|
||||
if hasattr(self.obj, "ZigUnidirectional"):
|
||||
self.obj.ZigUnidirectional = self.form.zigZagUnidirectional.isChecked()
|
||||
if hasattr(self.obj, "ZigZagAngle"):
|
||||
self.obj.ZigZagAngle = FreeCAD.Units.Quantity(self.form.zigZagAngle.text()).Value
|
||||
if hasattr(self.obj, "StepOver"):
|
||||
self.obj.StepOver = self.form.stepOverPercent.value()
|
||||
if hasattr(self.obj, "BoundaryShape"):
|
||||
self.obj.BoundaryShape = str(self.form.boundaryShape.currentText())
|
||||
if hasattr(self.obj, "OffsetPattern"):
|
||||
self.obj.OffsetPattern = str(self.form.offsetpattern.currentText())
|
||||
|
||||
if hasattr(self.obj, "ToolController"):
|
||||
tc = PathUtils.findToolController(self.obj, self.form.uiToolController.currentText())
|
||||
self.obj.ToolController = tc
|
||||
@@ -460,8 +453,6 @@ class TaskPanel:
|
||||
self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value, FreeCAD.Units.Length).UserString)
|
||||
|
||||
self.form.stepOverPercent.setValue(self.obj.StepOver)
|
||||
self.form.useZigZag.setChecked(self.obj.UseZigZag)
|
||||
self.form.zigZagUnidirectional.setChecked(self.obj.ZigUnidirectional)
|
||||
self.form.zigZagAngle.setValue(FreeCAD.Units.Quantity(self.obj.ZigZagAngle, FreeCAD.Units.Angle))
|
||||
self.form.extraOffset.setValue(self.obj.PassExtension.Value)
|
||||
|
||||
@@ -480,6 +471,13 @@ class TaskPanel:
|
||||
self.form.boundaryShape.setCurrentIndex(index)
|
||||
self.form.boundaryShape.blockSignals(False)
|
||||
|
||||
index = self.form.offsetpattern.findText(
|
||||
self.obj.OffsetPattern, QtCore.Qt.MatchFixedString)
|
||||
if index >= 0:
|
||||
self.form.offsetpattern.blockSignals(True)
|
||||
self.form.offsetpattern.setCurrentIndex(index)
|
||||
self.form.offsetpattern.blockSignals(False)
|
||||
|
||||
for i in self.obj.Base:
|
||||
for sub in i[1]:
|
||||
self.form.baseList.addItem(i[0].Name + "." + sub)
|
||||
@@ -616,8 +614,7 @@ class TaskPanel:
|
||||
self.form.extraOffset.editingFinished.connect(self.getFields)
|
||||
self.form.boundaryShape.currentIndexChanged.connect(self.getFields)
|
||||
self.form.stepOverPercent.editingFinished.connect(self.getFields)
|
||||
self.form.useZigZag.clicked.connect(self.getFields)
|
||||
self.form.zigZagUnidirectional.clicked.connect(self.getFields)
|
||||
self.form.offsetpattern.currentIndexChanged.connect(self.getFields)
|
||||
self.form.zigZagAngle.editingFinished.connect(self.getFields)
|
||||
self.form.uiToolController.currentIndexChanged.connect(self.getFields)
|
||||
|
||||
|
||||
@@ -109,9 +109,6 @@ class ObjectPocket:
|
||||
obj.setEditorMode('RampAngle', 2) # make this hidden
|
||||
obj.setEditorMode('RampSize', 2) # make this hidden
|
||||
|
||||
if prop == "UserLabel":
|
||||
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ from PathScripts import PathUtils
|
||||
from PathScripts.PathUtils import depth_params
|
||||
from DraftGeomUtils import findWires
|
||||
import PathScripts.PathLog as PathLog
|
||||
from PathScripts.PathUtils import waiting_effects
|
||||
|
||||
"""Path Profile from Edges Object and Command"""
|
||||
|
||||
@@ -107,8 +108,7 @@ class ObjectProfile:
|
||||
return None
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "UserLabel":
|
||||
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
|
||||
pass
|
||||
|
||||
def addprofilebase(self, obj, ss, sub=""):
|
||||
baselist = obj.Base
|
||||
@@ -144,6 +144,7 @@ class ObjectProfile:
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
|
||||
@waiting_effects
|
||||
def _buildPathLibarea(self, obj, edgelist):
|
||||
import PathScripts.PathKurveUtils as PathKurveUtils
|
||||
# import math
|
||||
|
||||
@@ -27,6 +27,7 @@ import FreeCAD
|
||||
import Path
|
||||
from PathScripts import PathUtils
|
||||
import PathScripts.PathLog as PathLog
|
||||
from PathScripts.PathUtils import waiting_effects
|
||||
import sys
|
||||
|
||||
# xrange is not available in python3
|
||||
@@ -129,8 +130,7 @@ class ObjectSurface:
|
||||
return None
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "UserLabel":
|
||||
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
|
||||
pass
|
||||
|
||||
def _waterline(self, obj, s, bb):
|
||||
import ocl
|
||||
@@ -262,6 +262,7 @@ class ObjectSurface:
|
||||
|
||||
return output
|
||||
|
||||
@waiting_effects
|
||||
def execute(self, obj):
|
||||
import MeshPart
|
||||
FreeCAD.Console.PrintWarning(
|
||||
|
||||
@@ -31,16 +31,38 @@ import PathScripts
|
||||
from PathScripts import PathJob
|
||||
import numpy
|
||||
import PathLog
|
||||
#from math import pi
|
||||
from FreeCAD import Vector
|
||||
import Path
|
||||
from PySide import QtCore
|
||||
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:
|
||||
return function(*args, **kwargs)
|
||||
QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
|
||||
res = None
|
||||
try:
|
||||
res = function(*args, **kwargs)
|
||||
except Exception as e:
|
||||
raise e
|
||||
print("Error {}".format(e.args[0]))
|
||||
finally:
|
||||
QtGui.QApplication.restoreOverrideCursor()
|
||||
return res
|
||||
return new_function
|
||||
|
||||
|
||||
def cleanedges(splines, precision):
|
||||
'''cleanedges([splines],precision). Convert BSpline curves, Beziers, to arcs that can be used for cnc paths.
|
||||
Returns Lines as is. Filters Circle and Arcs for over 180 degrees. Discretizes Ellipses. Ignores other geometry. '''
|
||||
PathLog.track()
|
||||
edges = []
|
||||
for spline in splines:
|
||||
if geomType(spline) == "BSplineCurve":
|
||||
@@ -73,8 +95,11 @@ def cleanedges(splines, precision):
|
||||
|
||||
return edges
|
||||
|
||||
|
||||
def curvetowire(obj, steps):
|
||||
'''adapted from DraftGeomUtils, because the discretize function changed a bit '''
|
||||
|
||||
PathLog.track()
|
||||
points = obj.copy().discretize(Distance=eval('steps'))
|
||||
p0 = points[0]
|
||||
edgelist = []
|
||||
@@ -84,6 +109,7 @@ def curvetowire(obj, steps):
|
||||
p0 = p
|
||||
return edgelist
|
||||
|
||||
|
||||
def isDrillable(obj, candidate, tooldiameter=None):
|
||||
PathLog.track('obj: {} candidate: {} tooldiameter {}'.format(obj, candidate, tooldiameter))
|
||||
drillable = False
|
||||
@@ -98,13 +124,13 @@ def isDrillable(obj, candidate, tooldiameter=None):
|
||||
v1 = edge.Vertexes[1].Point
|
||||
if (v1.sub(v0).x == 0) and (v1.sub(v0).y == 0):
|
||||
# vector of top center
|
||||
lsp = Vector(face.BoundBox.Center.x,face.BoundBox.Center.y, face.BoundBox.ZMax)
|
||||
lsp = Vector(face.BoundBox.Center.x, face.BoundBox.Center.y, face.BoundBox.ZMax)
|
||||
# vector of bottom center
|
||||
lep = Vector(face.BoundBox.Center.x,face.BoundBox.Center.y, face.BoundBox.ZMin)
|
||||
lep = Vector(face.BoundBox.Center.x, face.BoundBox.Center.y, face.BoundBox.ZMin)
|
||||
if obj.isInside(lsp, 0, False) or obj.isInside(lep, 0, False):
|
||||
drillable = False
|
||||
# eliminate elliptical holes
|
||||
elif not hasattr(face.Surface, "Radius"): #abs(face.BoundBox.XLength - face.BoundBox.YLength) > 0.05:
|
||||
elif not hasattr(face.Surface, "Radius"):
|
||||
drillable = False
|
||||
else:
|
||||
if tooldiameter is not None:
|
||||
@@ -115,7 +141,7 @@ def isDrillable(obj, candidate, tooldiameter=None):
|
||||
for edge in candidate.Edges:
|
||||
if isinstance(edge.Curve, Part.Circle) and edge.isClosed():
|
||||
PathLog.debug("candidate is a circle or ellipse")
|
||||
if not hasattr(edge.Curve, "Radius"): #bbdiff > 0.05:
|
||||
if not hasattr(edge.Curve, "Radius"):
|
||||
PathLog.debug("No radius. Ellipse.")
|
||||
drillable = False
|
||||
else:
|
||||
@@ -127,13 +153,16 @@ def isDrillable(obj, candidate, tooldiameter=None):
|
||||
PathLog.debug("candidate is drillable: {}".format(drillable))
|
||||
return drillable
|
||||
|
||||
|
||||
# fixme set at 4 decimal places for testing
|
||||
def fmt(val): return format(val, '.4f')
|
||||
|
||||
|
||||
def segments(poly):
|
||||
''' A sequence of (x,y) numeric coordinates pairs '''
|
||||
return zip(poly, poly[1:] + [poly[0]])
|
||||
|
||||
|
||||
def loopdetect(obj, edge1, edge2):
|
||||
'''
|
||||
Returns a loop wire that includes the two edges.
|
||||
@@ -148,17 +177,19 @@ def loopdetect(obj, edge1, edge2):
|
||||
for wire in obj.Shape.Wires:
|
||||
for e in wire.Edges:
|
||||
if e.hashCode() == edge1.hashCode():
|
||||
candidates.append((wire.hashCode(),wire))
|
||||
candidates.append((wire.hashCode(), wire))
|
||||
if e.hashCode() == edge2.hashCode():
|
||||
candidates.append((wire.hashCode(),wire))
|
||||
loop = set([x for x in candidates if candidates.count(x) > 1]) #return the duplicate item
|
||||
candidates.append((wire.hashCode(), wire))
|
||||
loop = set([x for x in candidates if candidates.count(x) > 1]) # return the duplicate item
|
||||
if len(loop) != 1:
|
||||
return None
|
||||
loopwire = next(x for x in loop)[1]
|
||||
return loopwire
|
||||
|
||||
|
||||
def filterArcs(arcEdge):
|
||||
'''filterArcs(Edge) -used to split arcs that over 180 degrees. Returns list '''
|
||||
PathLog.track()
|
||||
s = arcEdge
|
||||
if isinstance(s.Curve, Part.Circle):
|
||||
splitlist = []
|
||||
@@ -174,10 +205,10 @@ def filterArcs(arcEdge):
|
||||
arcstpt = s.valueAt(s.FirstParameter)
|
||||
arcmid = s.valueAt(
|
||||
(s.LastParameter - s.FirstParameter) * 0.5 + s.FirstParameter)
|
||||
arcquad1 = s.valueAt((s.LastParameter - s.FirstParameter)
|
||||
* 0.25 + s.FirstParameter) # future midpt for arc1
|
||||
arcquad2 = s.valueAt((s.LastParameter - s.FirstParameter)
|
||||
* 0.75 + s.FirstParameter) # future midpt for arc2
|
||||
arcquad1 = s.valueAt((s.LastParameter - s.FirstParameter) *
|
||||
0.25 + s.FirstParameter) # future midpt for arc1
|
||||
arcquad2 = s.valueAt((s.LastParameter - s.FirstParameter) *
|
||||
0.75 + s.FirstParameter) # future midpt for arc2
|
||||
arcendpt = s.valueAt(s.LastParameter)
|
||||
# reconstruct with 2 arcs
|
||||
arcseg1 = Part.ArcOfCircle(arcstpt, arcquad1, arcmid)
|
||||
@@ -194,6 +225,40 @@ def filterArcs(arcEdge):
|
||||
return splitlist
|
||||
|
||||
|
||||
def makeWorkplane(shape):
|
||||
"""
|
||||
Creates a workplane circle at the ZMin level.
|
||||
"""
|
||||
PathLog.track()
|
||||
loc = FreeCAD.Vector(shape.BoundBox.Center.x,
|
||||
shape.BoundBox.Center.y,
|
||||
shape.BoundBox.ZMin)
|
||||
c = Part.makeCircle(10, loc)
|
||||
return c
|
||||
|
||||
|
||||
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 reverseEdge(e):
|
||||
if geomType(e) == "Circle":
|
||||
arcstpt = e.valueAt(e.FirstParameter)
|
||||
@@ -208,6 +273,7 @@ def reverseEdge(e):
|
||||
|
||||
return newedge
|
||||
|
||||
|
||||
def changeTool(obj, job):
|
||||
tlnum = 0
|
||||
for p in job.Group:
|
||||
@@ -223,6 +289,7 @@ def changeTool(obj, job):
|
||||
if g == obj:
|
||||
return tlnum
|
||||
|
||||
|
||||
def getToolControllers(obj):
|
||||
'''returns all the tool controllers'''
|
||||
controllers = []
|
||||
@@ -238,6 +305,7 @@ def getToolControllers(obj):
|
||||
controllers.append(g)
|
||||
return controllers
|
||||
|
||||
|
||||
def findToolController(obj, name=None):
|
||||
'''returns a tool controller with a given name.
|
||||
If no name is specified, returns the first controller.
|
||||
@@ -245,7 +313,7 @@ def findToolController(obj, name=None):
|
||||
|
||||
PathLog.track('name: {}'.format(name))
|
||||
c = None
|
||||
#First check if a user has selected a tool controller in the tree. Return the first one and remove all from selection
|
||||
# First check if a user has selected a tool controller in the tree. Return the first one and remove all from selection
|
||||
for sel in FreeCADGui.Selection.getSelectionEx():
|
||||
if hasattr(sel.Object, 'Proxy'):
|
||||
if isinstance(sel.Object.Proxy, PathScripts.PathLoadTool.LoadTool):
|
||||
@@ -260,16 +328,16 @@ def findToolController(obj, name=None):
|
||||
if len(controllers) == 0:
|
||||
return None
|
||||
|
||||
#If there's only one in the job, use it.
|
||||
# If there's only one in the job, use it.
|
||||
if len(controllers) == 1:
|
||||
if name is None or name == controllers[0].Label:
|
||||
tc = controllers[0]
|
||||
else:
|
||||
tc = None
|
||||
elif name is not None: #More than one, make the user choose.
|
||||
elif name is not None: # More than one, make the user choose.
|
||||
tc = [i for i in controllers if i.Label == name][0]
|
||||
else:
|
||||
#form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/DlgTCChooser.ui")
|
||||
# form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/DlgTCChooser.ui")
|
||||
form = FreeCADGui.PySideUic.loadUi(":/panels/DlgTCChooser.ui")
|
||||
mylist = [i.Label for i in controllers]
|
||||
form.uiToolController.addItems(mylist)
|
||||
@@ -280,6 +348,7 @@ def findToolController(obj, name=None):
|
||||
tc = [i for i in controllers if i.Label == form.uiToolController.currentText()][0]
|
||||
return tc
|
||||
|
||||
|
||||
def findParentJob(obj):
|
||||
'''retrieves a parent job object for an operation or other Path object'''
|
||||
PathLog.track()
|
||||
@@ -292,7 +361,8 @@ def findParentJob(obj):
|
||||
return grandParent
|
||||
return None
|
||||
|
||||
def GetJobs(jobname = None):
|
||||
|
||||
def GetJobs(jobname=None):
|
||||
'''returns all jobs in the current document. If name is given, returns that job'''
|
||||
PathLog.track()
|
||||
jobs = []
|
||||
@@ -306,7 +376,8 @@ def GetJobs(jobname = None):
|
||||
jobs.append(o)
|
||||
return jobs
|
||||
|
||||
def addToJob(obj, jobname = None):
|
||||
|
||||
def addToJob(obj, jobname=None):
|
||||
'''adds a path object to a job
|
||||
obj = obj
|
||||
jobname = None'''
|
||||
@@ -326,7 +397,7 @@ def addToJob(obj, jobname = None):
|
||||
elif len(jobs) == 1:
|
||||
job = jobs[0]
|
||||
else:
|
||||
#form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/DlgJobChooser.ui")
|
||||
# form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/DlgJobChooser.ui")
|
||||
form = FreeCADGui.PySideUic.loadUi(":/panels/DlgJobChooser.ui")
|
||||
mylist = [i.Name for i in jobs]
|
||||
form.cboProject.addItems(mylist)
|
||||
@@ -342,6 +413,7 @@ def addToJob(obj, jobname = None):
|
||||
job.Group = g
|
||||
return job
|
||||
|
||||
|
||||
def rapid(x=None, y=None, z=None):
|
||||
""" Returns gcode string to perform a rapid move."""
|
||||
retstr = "G00"
|
||||
@@ -356,6 +428,7 @@ def rapid(x=None, y=None, z=None):
|
||||
return ""
|
||||
return retstr + "\n"
|
||||
|
||||
|
||||
def feed(x=None, y=None, z=None, horizFeed=0, vertFeed=0):
|
||||
""" Return gcode string to perform a linear feed."""
|
||||
global feedxy
|
||||
@@ -376,6 +449,7 @@ def feed(x=None, y=None, z=None, horizFeed=0, vertFeed=0):
|
||||
return ""
|
||||
return retstr + "\n"
|
||||
|
||||
|
||||
def arc(cx, cy, sx, sy, ex, ey, horizFeed=0, ez=None, ccw=False):
|
||||
"""
|
||||
Return gcode string to perform an arc.
|
||||
@@ -412,6 +486,7 @@ def arc(cx, cy, sx, sy, ex, ey, horizFeed=0, ez=None, ccw=False):
|
||||
|
||||
return retstr + "\n"
|
||||
|
||||
|
||||
def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed):
|
||||
"""
|
||||
Return gcode string to perform helical entry move.
|
||||
@@ -458,6 +533,7 @@ def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed
|
||||
|
||||
return helixCmds
|
||||
|
||||
|
||||
def rampPlunge(edge, rampangle, destZ, startZ):
|
||||
"""
|
||||
Return gcode string to linearly ramp down to milling level.
|
||||
@@ -562,6 +638,7 @@ def sort_jobs(locations, keys, attractors=[]):
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class depth_params:
|
||||
'''calculates the intermediate depth values for various operations given the starting, ending, and stepdown parameters
|
||||
(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_depth, final_depth, [user_depths=None])
|
||||
|
||||
@@ -39,6 +39,7 @@ Arguments for linuxcnc:
|
||||
--comments,--no-comments ... output comments (--comments)
|
||||
--line-numbers,--no-line-numbers ... prefix with line numbers (--no-lin-numbers)
|
||||
--show-editor, --no-show-editor ... pop up editor before writing output(--show-editor)
|
||||
--output-precision=4 ... number of digits of precision. Default=4
|
||||
'''
|
||||
import FreeCAD
|
||||
from FreeCAD import Units
|
||||
@@ -66,6 +67,7 @@ UNIT_FORMAT = 'mm/min'
|
||||
MACHINE_NAME = "LinuxCNC"
|
||||
CORNER_MIN = {'x': 0, 'y': 0, 'z': 0}
|
||||
CORNER_MAX = {'x': 500, 'y': 300, 'z': 300}
|
||||
PRECISION=4
|
||||
|
||||
# Preamble text will appear at the beginning of the GCODE output file.
|
||||
PREAMBLE = '''G17 G90
|
||||
@@ -98,6 +100,8 @@ def processArguments(argstring):
|
||||
global OUTPUT_COMMENTS
|
||||
global OUTPUT_LINE_NUMBERS
|
||||
global SHOW_EDITOR
|
||||
global PRECISION
|
||||
|
||||
for arg in argstring.split():
|
||||
if arg == '--header':
|
||||
OUTPUT_HEADER = True
|
||||
@@ -115,6 +119,8 @@ def processArguments(argstring):
|
||||
SHOW_EDITOR = True
|
||||
elif arg == '--no-show-editor':
|
||||
SHOW_EDITOR = False
|
||||
elif arg.split('=')[0] == '--output-precision':
|
||||
PRECISION = arg.split('=')[1]
|
||||
|
||||
def export(objectslist, filename, argstring):
|
||||
processArguments(argstring)
|
||||
@@ -211,8 +217,10 @@ def linenumber():
|
||||
return ""
|
||||
|
||||
def parse(pathobj):
|
||||
global PRECISION
|
||||
out = ""
|
||||
lastcommand = None
|
||||
precision_string = '.' + str(PRECISION) +'f'
|
||||
|
||||
# params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control
|
||||
# the order of parameters
|
||||
@@ -251,12 +259,12 @@ def parse(pathobj):
|
||||
if c.Name not in ["G0", "G00"]: #linuxcnc doesn't use rapid speeds
|
||||
speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity)
|
||||
outstring.append(
|
||||
param + format(float(speed.getValueAs(UNIT_FORMAT)), '.2f') )
|
||||
param + format(float(speed.getValueAs(UNIT_FORMAT)), precision_string) )
|
||||
elif param == 'T':
|
||||
outstring.append(param + str(c.Parameters['T']))
|
||||
else:
|
||||
outstring.append(
|
||||
param + format(c.Parameters[param], '.4f'))
|
||||
param + format(c.Parameters[param], precision_string))
|
||||
|
||||
# store the latest command
|
||||
lastcommand = command
|
||||
|
||||
@@ -56,6 +56,8 @@ OUTPUT_LINE_NUMBERS = False
|
||||
IP_ADDR = None
|
||||
VERBOSE = False
|
||||
|
||||
SPINDLE_SPEED = 0.0
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
SHOW_EDITOR = True
|
||||
else:
|
||||
@@ -298,6 +300,7 @@ def linenumber():
|
||||
def parse(pathobj):
|
||||
out = ""
|
||||
lastcommand = None
|
||||
global SPINDLE_SPEED
|
||||
|
||||
# params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control
|
||||
# the order of parameters
|
||||
@@ -339,9 +342,14 @@ def parse(pathobj):
|
||||
param + format(float(speed.getValueAs(UNIT_FORMAT)), '.2f') )
|
||||
elif param == 'T':
|
||||
outstring.append(param + str(c.Parameters['T']))
|
||||
elif param == 'S':
|
||||
outstring.append(param + str(c.Parameters['S']))
|
||||
SPINDLE_SPEED = c.Parameters['S']
|
||||
else:
|
||||
outstring.append(
|
||||
param + format(c.Parameters[param], '.4f'))
|
||||
if command in ['G1', 'G01', 'G2', 'G02', 'G3', 'G03']:
|
||||
outstring.append('S' + str(SPINDLE_SPEED))
|
||||
|
||||
# store the latest command
|
||||
lastcommand = command
|
||||
@@ -366,7 +374,7 @@ def parse(pathobj):
|
||||
|
||||
# append the line to the final output
|
||||
for w in outstring:
|
||||
out += w + COMMAND_SPACE
|
||||
out += w + COMMAND_SPACE
|
||||
out = out.strip() + "\n"
|
||||
|
||||
return out
|
||||
|
||||
@@ -109,6 +109,7 @@ G1X-0.5905Y-0.3937
|
||||
G0Z0.5
|
||||
'''
|
||||
|
||||
|
||||
output = '''G0 S3000.000000 X-0.590500 Y-0.393700
|
||||
M03
|
||||
G0 Z0.125000
|
||||
@@ -119,6 +120,8 @@ G1 X-0.590500 Y0.433000
|
||||
G1 X-0.590500 Y-0.393700
|
||||
G0 Z0.500000
|
||||
'''
|
||||
|
||||
|
||||
#create a path directly form a piece of gcode.
|
||||
p = Path.Path()
|
||||
p.setFromGCode(lines)
|
||||
|
||||
@@ -78,13 +78,13 @@ class PathPostTestCases(unittest.TestCase):
|
||||
contour.OffsetExtra = 0.0
|
||||
contour.Direction = 'CW'
|
||||
contour.ToolController = tc
|
||||
contour.UseComp = True
|
||||
contour.UseComp = False
|
||||
PathScripts.PathUtils.addToJob(contour)
|
||||
PathScripts.PathContour.ObjectContour.setDepths(contour.Proxy, contour)
|
||||
self.doc.recompute()
|
||||
|
||||
job.PostProcessor = 'linuxcnc'
|
||||
job.PostProcessorArgs = '--no-header --no-line-numbers --no-comments --no-show-editor'
|
||||
job.PostProcessorArgs = '--no-header --no-line-numbers --no-comments --no-show-editor --output-precision=2'
|
||||
|
||||
post = PathScripts.PathPost.CommandPathPost()
|
||||
(fail, gcode) = post.exportObjectsWith([job], job, False)
|
||||
|
||||
@@ -2,106 +2,68 @@ G17 G90
|
||||
G21
|
||||
(Default_Tool)
|
||||
M6 T1.0
|
||||
M3 S0.0000
|
||||
M3 S0.00
|
||||
(TC)
|
||||
M6 T2.0
|
||||
M3 S0.0000
|
||||
M3 S0.00
|
||||
(Contour)
|
||||
(Uncompensated Tool Path)
|
||||
G0 Z15.0000
|
||||
G00 X-2.5000 Y0.0000
|
||||
G00 Z23.0000
|
||||
G01 X-2.5000 Y0.0000 Z9.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z9.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z9.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z9.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z9.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z9.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z9.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z9.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z9.0000 I0.0000 J2.5000 F0.00
|
||||
G01 X-2.5000 Y0.0000 Z8.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z8.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z8.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z8.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z8.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z8.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z8.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z8.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z8.0000 I0.0000 J2.5000 F0.00
|
||||
G01 X-2.5000 Y0.0000 Z7.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z7.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z7.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z7.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z7.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z7.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z7.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z7.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z7.0000 I0.0000 J2.5000 F0.00
|
||||
G01 X-2.5000 Y0.0000 Z6.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z6.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z6.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z6.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z6.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z6.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z6.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z6.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z6.0000 I0.0000 J2.5000 F0.00
|
||||
G01 X-2.5000 Y0.0000 Z5.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z5.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z5.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z5.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z5.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z5.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z5.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z5.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z5.0000 I0.0000 J2.5000 F0.00
|
||||
G01 X-2.5000 Y0.0000 Z4.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z4.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z4.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z4.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z4.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z4.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z4.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z4.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z4.0000 I0.0000 J2.5000 F0.00
|
||||
G01 X-2.5000 Y0.0000 Z3.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z3.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z3.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z3.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z3.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z3.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z3.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z3.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z3.0000 I0.0000 J2.5000 F0.00
|
||||
G01 X-2.5000 Y0.0000 Z2.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z2.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z2.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z2.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z2.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z2.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z2.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z2.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z2.0000 I0.0000 J2.5000 F0.00
|
||||
G01 X-2.5000 Y0.0000 Z1.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z1.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z1.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z1.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z1.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z1.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z1.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z1.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z1.0000 I0.0000 J2.5000 F0.00
|
||||
G01 X-2.5000 Y0.0000 Z0.0000 F0.00
|
||||
G01 X-2.5000 Y10.0000 Z0.0000 F0.00
|
||||
G02 X0.0000 Y12.5000 Z0.0000 I2.5000 J0.0000 F0.00
|
||||
G01 X10.0000 Y12.5000 Z0.0000 F0.00
|
||||
G02 X12.5000 Y10.0000 Z0.0000 I0.0000 J-2.5000 F0.00
|
||||
G01 X12.5000 Y0.0000 Z0.0000 F0.00
|
||||
G02 X10.0000 Y-2.5000 Z0.0000 I-2.5000 J0.0000 F0.00
|
||||
G01 X0.0000 Y-2.5000 Z0.0000 F0.00
|
||||
G02 X-2.5000 Y0.0000 Z0.0000 I0.0000 J2.5000 F0.00
|
||||
G00 Z15.0000
|
||||
G0 Z15.00
|
||||
G90
|
||||
G17
|
||||
G0 X0.00 Y0.00 Z15.00
|
||||
G0 X10.00 Y10.00 Z15.00
|
||||
G0 X10.00 Y10.00 Z10.00
|
||||
G1 X10.00 Y10.00 Z9.00
|
||||
G1 X10.00 Y0.00 Z9.00
|
||||
G1 X0.00 Y0.00 Z9.00
|
||||
G1 X0.00 Y10.00 Z9.00
|
||||
G1 X10.00 Y10.00 Z9.00
|
||||
G1 X10.00 Y10.00 Z8.00
|
||||
G1 X10.00 Y0.00 Z8.00
|
||||
G1 X0.00 Y0.00 Z8.00
|
||||
G1 X0.00 Y10.00 Z8.00
|
||||
G1 X10.00 Y10.00 Z8.00
|
||||
G1 X10.00 Y10.00 Z7.00
|
||||
G1 X10.00 Y0.00 Z7.00
|
||||
G1 X0.00 Y0.00 Z7.00
|
||||
G1 X0.00 Y10.00 Z7.00
|
||||
G1 X10.00 Y10.00 Z7.00
|
||||
G1 X10.00 Y10.00 Z6.00
|
||||
G1 X10.00 Y0.00 Z6.00
|
||||
G1 X0.00 Y0.00 Z6.00
|
||||
G1 X0.00 Y10.00 Z6.00
|
||||
G1 X10.00 Y10.00 Z6.00
|
||||
G1 X10.00 Y10.00 Z5.00
|
||||
G1 X10.00 Y0.00 Z5.00
|
||||
G1 X0.00 Y0.00 Z5.00
|
||||
G1 X0.00 Y10.00 Z5.00
|
||||
G1 X10.00 Y10.00 Z5.00
|
||||
G1 X10.00 Y10.00 Z4.00
|
||||
G1 X10.00 Y0.00 Z4.00
|
||||
G1 X0.00 Y0.00 Z4.00
|
||||
G1 X0.00 Y10.00 Z4.00
|
||||
G1 X10.00 Y10.00 Z4.00
|
||||
G1 X10.00 Y10.00 Z3.00
|
||||
G1 X10.00 Y0.00 Z3.00
|
||||
G1 X0.00 Y0.00 Z3.00
|
||||
G1 X0.00 Y10.00 Z3.00
|
||||
G1 X10.00 Y10.00 Z3.00
|
||||
G1 X10.00 Y10.00 Z2.00
|
||||
G1 X10.00 Y0.00 Z2.00
|
||||
G1 X0.00 Y0.00 Z2.00
|
||||
G1 X0.00 Y10.00 Z2.00
|
||||
G1 X10.00 Y10.00 Z2.00
|
||||
G1 X10.00 Y10.00 Z1.00
|
||||
G1 X10.00 Y0.00 Z1.00
|
||||
G1 X0.00 Y0.00 Z1.00
|
||||
G1 X0.00 Y10.00 Z1.00
|
||||
G1 X10.00 Y10.00 Z1.00
|
||||
G1 X10.00 Y10.00 Z0.00
|
||||
G1 X10.00 Y0.00 Z0.00
|
||||
G1 X0.00 Y0.00 Z0.00
|
||||
G1 X0.00 Y10.00 Z0.00
|
||||
G1 X10.00 Y10.00 Z0.00
|
||||
M05
|
||||
G00 X-1.0 Y1.0
|
||||
G17 G90
|
||||
|
||||
@@ -960,7 +960,8 @@ int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toG
|
||||
std::vector<Constraint *> changed;
|
||||
for (int i=0; i < int(newVals.size()); i++) {
|
||||
if (vals[i]->First == fromGeoId && vals[i]->FirstPos == fromPosId &&
|
||||
!(vals[i]->Second == toGeoId && vals[i]->SecondPos == toPosId)) {
|
||||
!(vals[i]->Second == toGeoId && vals[i]->SecondPos == toPosId) &&
|
||||
!(toGeoId < 0 && vals[i]->Second <0) ) {
|
||||
Constraint *constNew = newVals[i]->clone();
|
||||
constNew->First = toGeoId;
|
||||
constNew->FirstPos = toPosId;
|
||||
@@ -968,7 +969,8 @@ int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toG
|
||||
changed.push_back(constNew);
|
||||
}
|
||||
else if (vals[i]->Second == fromGeoId && vals[i]->SecondPos == fromPosId &&
|
||||
!(vals[i]->First == toGeoId && vals[i]->FirstPos == toPosId)) {
|
||||
!(vals[i]->First == toGeoId && vals[i]->FirstPos == toPosId) &&
|
||||
!(toGeoId < 0 && vals[i]->First< 0)) {
|
||||
Constraint *constNew = newVals[i]->clone();
|
||||
constNew->Second = toGeoId;
|
||||
constNew->SecondPos = toPosId;
|
||||
|
||||
Reference in New Issue
Block a user