Path: remove Pocket OCC algorithm
This commit is contained in:
committed by
Yorik van Havre
parent
936bbedaeb
commit
c97724ef30
@@ -26,10 +26,10 @@
|
||||
<string>Pocket</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<item row="0" column="1">
|
||||
<widget class="QToolBox" name="toolBox">
|
||||
<property name="currentIndex">
|
||||
<number>5</number>
|
||||
<number>3</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="Geometry">
|
||||
<property name="enabled">
|
||||
@@ -40,7 +40,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>331</height>
|
||||
<height>387</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -118,7 +118,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>331</height>
|
||||
<height>387</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -196,7 +196,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>331</height>
|
||||
<height>387</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -240,108 +240,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="Entry">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>331</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Entry</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_3"/>
|
||||
</widget>
|
||||
<widget class="QWidget" name="Pattern">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>331</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Pattern</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QSpinBox" name="stepOverPercent">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Step Over Percent</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<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="2" column="1">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>ZigZag Angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="Gui::InputField" name="zigZagAngle">
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>331</height>
|
||||
<height>387</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="icon">
|
||||
@@ -383,48 +288,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_4">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Algorithm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="algorithmSelect">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>OCC Native</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>libarea</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="frameShape">
|
||||
@@ -440,54 +303,27 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Cut Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="useStartPoint">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Use Start Point</string>
|
||||
<string>Pattern</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Material Allowance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="Gui::InputField" name="extraOffset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
@@ -506,9 +342,113 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Cut Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="stepOverPercent">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Step Over Percent</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="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_10">
|
||||
<property name="text">
|
||||
<string>ZigZag Angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::InputField" name="zigZagAngle">
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="useStartPoint">
|
||||
<property name="text">
|
||||
<string>Use Start Point</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -27,6 +27,8 @@ import Path
|
||||
from PySide import QtCore, QtGui
|
||||
from PathScripts import PathUtils
|
||||
import PathScripts.PathLog as PathLog
|
||||
from PathScripts.PathUtils import waiting_effects, depth_params
|
||||
import Part
|
||||
|
||||
FreeCADGui = None
|
||||
if FreeCAD.GuiUp:
|
||||
@@ -35,8 +37,9 @@ if FreeCAD.GuiUp:
|
||||
"""Path Pocket object and FreeCAD command"""
|
||||
|
||||
LOG_MODULE = 'PathPocket'
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
# PathLog.trackModule('PathPocket')
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, LOG_MODULE)
|
||||
PathLog.trackModule('PathPocket')
|
||||
FreeCAD.setLogLevel('Path.Area',0)
|
||||
|
||||
# Qt tanslation handling
|
||||
def translate(context, text, disambig=None):
|
||||
@@ -50,9 +53,6 @@ class ObjectPocket:
|
||||
obj.addProperty("App::PropertyString", "Comment", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "An optional comment for this profile"))
|
||||
obj.addProperty("App::PropertyString", "UserLabel", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "User Assigned Label"))
|
||||
|
||||
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm", QtCore.QT_TRANSLATE_NOOP("App::Property", "The library to use to generate the path"))
|
||||
obj.Algorithm = ['OCC Native', 'libarea']
|
||||
|
||||
# Tool Properties
|
||||
obj.addProperty("App::PropertyLink", "ToolController", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool controller that will be used to calculate the path"))
|
||||
|
||||
@@ -71,19 +71,10 @@ class ObjectPocket:
|
||||
obj.addProperty("App::PropertyEnumeration", "StartAt", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Start pocketing at center or boundary"))
|
||||
obj.StartAt = ['Center', 'Edge']
|
||||
obj.addProperty("App::PropertyPercent", "StepOver", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Percent of cutter diameter to step over on each pass"))
|
||||
obj.addProperty("App::PropertyBool", "KeepToolDown", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Attempts to avoid unnecessary retractions."))
|
||||
obj.addProperty("App::PropertyBool", "ZigUnidirectional", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Lifts tool at the end of each pass to respect cut mode."))
|
||||
obj.addProperty("App::PropertyBool", "UseZigZag", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Use Zig Zag pattern to clear area."))
|
||||
obj.addProperty("App::PropertyFloat", "ZigZagAngle", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Angle of the zigzag pattern"))
|
||||
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']
|
||||
|
||||
# Entry Properties
|
||||
obj.addProperty("App::PropertyBool", "UseEntry", "Entry", QtCore.QT_TRANSLATE_NOOP("App::Property", "Allow Cutter enter material with a straight plunge."))
|
||||
obj.addProperty("App::PropertyFloatConstraint", "RampSize", "Entry", QtCore.QT_TRANSLATE_NOOP("App::Property", "The minimum fraction of tool diameter to use for ramp length"))
|
||||
obj.RampSize = (0.0, 0.01, 100.0, 0.5)
|
||||
obj.addProperty("App::PropertyFloatConstraint", "HelixSize", "Entry", QtCore.QT_TRANSLATE_NOOP("App::Property", "The fraction of tool diameter to use for calculating helix size."))
|
||||
obj.HelixSize = (0.0, 0.01, 100.0, 0.5)
|
||||
obj.addProperty("App::PropertyFloatConstraint", "RampAngle", "Entry", QtCore.QT_TRANSLATE_NOOP("App::Property", "The Angle of the ramp entry."))
|
||||
obj.RampAngle = (0.0, 0.01, 100.0, 0.5)
|
||||
|
||||
# Start Point Properties
|
||||
obj.addProperty("App::PropertyVector", "StartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "The start point of this path"))
|
||||
@@ -92,15 +83,7 @@ class ObjectPocket:
|
||||
obj.Proxy = self
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "UseEntry":
|
||||
if obj.UseEntry:
|
||||
obj.setEditorMode('HelixSize', 0) # make this visible
|
||||
obj.setEditorMode('RampAngle', 0) # make this visible
|
||||
obj.setEditorMode('RampSize', 0) # make this visible
|
||||
else:
|
||||
obj.setEditorMode('HelixSize', 2) # make this hidden
|
||||
obj.setEditorMode('RampAngle', 2) # make this hidden
|
||||
obj.setEditorMode('RampSize', 2) # make this hidden
|
||||
pass
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
@@ -108,7 +91,29 @@ class ObjectPocket:
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def setDepths(proxy, obj):
|
||||
PathLog.track()
|
||||
parentJob = PathUtils.findParentJob(obj)
|
||||
if parentJob is None:
|
||||
return
|
||||
baseobject = parentJob.Base
|
||||
if baseobject is None:
|
||||
return
|
||||
|
||||
try:
|
||||
bb = baseobject.Shape.BoundBox # parent boundbox
|
||||
obj.StartDepth = bb.ZMax
|
||||
obj.ClearanceHeight = bb.ZMax + 5.0
|
||||
obj.SafeHeight = bb.ZMax + 3.0
|
||||
obj.FinalDepth = bb.ZMin
|
||||
|
||||
except:
|
||||
obj.StartDepth = 5.0
|
||||
obj.ClearanceHeight = 10.0
|
||||
obj.SafeHeight = 8.0
|
||||
|
||||
def addpocketbase(self, obj, ss, sub=""):
|
||||
PathLog.track()
|
||||
baselist = obj.Base
|
||||
if baselist is None:
|
||||
baselist = []
|
||||
@@ -143,7 +148,6 @@ class ObjectPocket:
|
||||
else:
|
||||
baselist.append(item)
|
||||
obj.Base = baselist
|
||||
print("this base is: " + str(baselist))
|
||||
self.execute(obj)
|
||||
|
||||
def getStock(self, obj):
|
||||
@@ -158,191 +162,68 @@ class ObjectPocket:
|
||||
return self.getStock(o)
|
||||
return None
|
||||
|
||||
def buildpathlibarea(self, obj, a):
|
||||
"""Build the pocket path using libarea algorithm"""
|
||||
import PathScripts.PathAreaUtils as PathAreaUtils
|
||||
from PathScripts.PathUtils import depth_params
|
||||
PathLog.debug("Generating toolpath with libarea offsets.\n")
|
||||
@waiting_effects
|
||||
def _buildPathArea(self, obj, baseobject):
|
||||
PathLog.track()
|
||||
pocket = Path.Area()
|
||||
pocket.setPlane(Part.makeCircle(10))
|
||||
pocket.add(baseobject)
|
||||
|
||||
depthparams = depth_params(
|
||||
obj.ClearanceHeight.Value,
|
||||
obj.SafeHeight.Value,
|
||||
obj.StartDepth.Value,
|
||||
obj.StepDown,
|
||||
obj.FinishDepth.Value,
|
||||
obj.FinalDepth.Value)
|
||||
|
||||
extraoffset = obj.MaterialAllowance.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
|
||||
|
||||
PathAreaUtils.flush_nc()
|
||||
PathAreaUtils.output('mem')
|
||||
PathAreaUtils.feedrate_hv(self.horizFeed, self.vertFeed)
|
||||
if obj.UseStartPoint:
|
||||
start_point = (obj.StartPoint.x, obj.StartPoint.y)
|
||||
pocketparams = {'Fill': 0,
|
||||
'Coplanar': 0,
|
||||
'PocketMode': 1,
|
||||
'SectionCount': -1,
|
||||
'Angle': obj.ZigZagAngle,
|
||||
'FromCenter': (obj.StartAt == "Center"),
|
||||
'PocketStepover': stepover,
|
||||
'PocketExtraOffset': obj.MaterialAllowance.Value}
|
||||
|
||||
# print "a," + str(self.radius) + "," + str(extraoffset) + "," + str(stepover) + ",depthparams, " + str(from_center) + "," + str(keep_tool_down) + "," + str(use_zig_zag) + "," + str(zig_angle) + "," + str(zig_unidirectional) + "," + str(start_point) + "," + str(cut_mode)
|
||||
Pattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
|
||||
pocketparams['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1
|
||||
|
||||
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()
|
||||
|
||||
def buildpathocc(self, obj, shape):
|
||||
"""Build pocket Path using Native OCC algorithm."""
|
||||
import Part
|
||||
import DraftGeomUtils
|
||||
from PathScripts.PathUtils import fmt, helicalPlunge, rampPlunge, depth_params
|
||||
|
||||
PathLog.debug("Generating toolpath with OCC native offsets.\n")
|
||||
extraoffset = obj.MaterialAllowance.Value
|
||||
|
||||
# Build up the offset loops
|
||||
output = ""
|
||||
if obj.Comment != "":
|
||||
output += '(' + str(obj.Comment)+')\n'
|
||||
output += 'G0 Z' + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
|
||||
|
||||
offsets = []
|
||||
nextradius = self.radius + extraoffset
|
||||
result = DraftGeomUtils.pocket2d(shape, nextradius)
|
||||
while result:
|
||||
offsets.extend(result)
|
||||
nextradius += (self.radius * 2) * (float(obj.StepOver)/100)
|
||||
result = DraftGeomUtils.pocket2d(shape, nextradius)
|
||||
|
||||
# revert the list so we start with the outer wires
|
||||
if obj.StartAt != 'Edge':
|
||||
offsets.reverse()
|
||||
|
||||
plungePos = None
|
||||
rampEdge = None
|
||||
if obj.UseEntry:
|
||||
# Try to find an entry location
|
||||
toold = self.radius*2
|
||||
helixBounds = DraftGeomUtils.pocket2d(shape, self.radius * (1 + obj.HelixSize))
|
||||
|
||||
if helixBounds:
|
||||
rampD = obj.RampSize
|
||||
|
||||
if obj.StartAt == 'Edge':
|
||||
plungePos = helixBounds[0].Edges[0].Vertexes[0].Point
|
||||
else:
|
||||
plungePos = offsets[0].Edges[0].Vertexes[0].Point
|
||||
|
||||
# If it turns out this is invalid for some reason, nuke plungePos
|
||||
[perp, idx] = DraftGeomUtils.findPerpendicular(plungePos, shape.Edges)
|
||||
if not perp or perp.Length < self.radius * (1 + obj.HelixSize):
|
||||
plungePos = None
|
||||
FreeCAD.Console.PrintError(translate("PathPocket", "Helical Entry location not found.\n"))
|
||||
# FIXME: Really need to do a point-in-polygon operation to make sure this is within helixBounds
|
||||
# Or some math to prove that it has to be (doubt that's true)
|
||||
# Maybe reverse helixBounds and pick off that?
|
||||
|
||||
if plungePos is None: # If we didn't find a place to helix, how about a ramp?
|
||||
FreeCAD.Console.PrintMessage(translate("PathPocket", "Attempting ramp entry.\n"))
|
||||
if (offsets[0].Edges[0].Length >= toold * rampD) and not (isinstance(offsets[0].Edges[0].Curve, Part.Circle)):
|
||||
rampEdge = offsets[0].Edges[0]
|
||||
# The last edge also connects with the starting location- try that
|
||||
elif (offsets[0].Edges[-1].Length >= toold * rampD) and not (isinstance(offsets[0].Edges[-1].Curve, Part.Circle)):
|
||||
rampEdge = offsets[0].Edges[-1]
|
||||
else:
|
||||
FreeCAD.Console.PrintError(translate("PathPocket", "Ramp Entry location not found.\n"))
|
||||
# print "Neither edge works: " + str(offsets[0].Edges[0]) + ", " + str(offsets[0].Edges[-1])
|
||||
# FIXME: There's got to be a smarter way to find a place to ramp
|
||||
|
||||
# For helix-ing/ramping, know where we were last time
|
||||
# FIXME: Can probably get this from the "machine"?
|
||||
lastZ = obj.ClearanceHeight.Value
|
||||
|
||||
startPoint = None
|
||||
pocket.setParams(**pocketparams)
|
||||
PathLog.debug("Pocketing with params: {}".format(pocket.getParams()))
|
||||
|
||||
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.Value,
|
||||
z_finish_step=0.0,
|
||||
final_depth=obj.FinalDepth.Value,
|
||||
user_depths=None)
|
||||
|
||||
for vpos in depthparams.get_depths():
|
||||
sections = pocket.makeSections(mode=0, project=False, heights=depthparams.get_depths())
|
||||
shapelist = [sec.getShape() for sec in sections]
|
||||
|
||||
first = True
|
||||
# loop over successive wires
|
||||
for currentWire in offsets:
|
||||
last = None
|
||||
for edge in currentWire.Edges:
|
||||
if not last:
|
||||
# we set the base GO to our fast move to our starting pos
|
||||
if first:
|
||||
# If we can helix, do so
|
||||
if plungePos:
|
||||
output += helicalPlunge(plungePos, obj.RampAngle, vpos, lastZ, self.radius*2, obj.HelixSize, self.horizFeed)
|
||||
lastZ = vpos
|
||||
# Otherwise, see if we can ramp
|
||||
# FIXME: This could be a LOT smarter (eg, searching for a longer leg of the edge to ramp along)
|
||||
elif rampEdge:
|
||||
output += rampPlunge(rampEdge, obj.RampAngle, vpos, lastZ)
|
||||
lastZ = vpos
|
||||
# Otherwise, straight plunge... Don't want to, but sometimes you might not have a choice.
|
||||
# FIXME: At least not with the lazy ramp programming above...
|
||||
else:
|
||||
print("WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp")
|
||||
startPoint = edge.Vertexes[0].Point
|
||||
output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
|
||||
output += "G0 X" + fmt(startPoint.x) + " Y" + fmt(startPoint.y) +\
|
||||
" Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
|
||||
first = False
|
||||
# then move slow down to our starting point for our profile
|
||||
last = edge.Vertexes[0].Point
|
||||
output += "G1 X" + fmt(last.x) + " Y" + fmt(last.y) + " Z" + fmt(vpos) + " F" + fmt(self.vertFeed) + "\n"
|
||||
if DraftGeomUtils.geomType(edge) == "Circle":
|
||||
point = edge.Vertexes[-1].Point
|
||||
if point == last: # edges can come flipped
|
||||
point = edge.Vertexes[0].Point
|
||||
center = edge.Curve.Center
|
||||
relcenter = center.sub(last)
|
||||
v1 = last.sub(center)
|
||||
v2 = point.sub(center)
|
||||
if v1.cross(v2).z < 0:
|
||||
output += "G2"
|
||||
else:
|
||||
output += "G3"
|
||||
output += " X" + fmt(point.x) + " Y" + fmt(point.y) + " Z" + fmt(vpos)
|
||||
output += " I" + fmt(relcenter.x) + " J" + fmt(relcenter.y) + " K" + fmt(relcenter.z) + " F" + fmt(self.horizFeed)
|
||||
output += "\n"
|
||||
last = point
|
||||
else:
|
||||
point = edge.Vertexes[-1].Point
|
||||
if point == last: # edges can come flipped
|
||||
point = edge.Vertexes[0].Point
|
||||
output += "G1 X" + fmt(point.x) + " Y" + fmt(point.y) + " Z" + fmt(vpos) + " F" + fmt(self.horizFeed) + "\n"
|
||||
last = point
|
||||
params = {'shapes': shapelist,
|
||||
'feedrate': self.horizFeed,
|
||||
'feedrate_v': self.vertFeed,
|
||||
'verbose': True,
|
||||
'resume_height': obj.StepDown.Value,
|
||||
'retraction': obj.ClearanceHeight.Value}
|
||||
|
||||
|
||||
# if obj.UseStartPoint is True and obj.StartPoint is not None:
|
||||
# params['start'] = obj.StartPoint
|
||||
|
||||
pp = Path.fromShapes(**params)
|
||||
PathLog.debug("Generating Path with params: {}".format(params))
|
||||
PathLog.debug(pp)
|
||||
return pp
|
||||
|
||||
# move back up
|
||||
output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
|
||||
return output
|
||||
|
||||
# To reload this from FreeCAD, use: import PathScripts.PathPocket; reload(PathScripts.PathPocket)
|
||||
def execute(self, obj):
|
||||
output = ""
|
||||
PathLog.track()
|
||||
commandlist = []
|
||||
commandlist.append(Path.Command("(" + obj.Label + ")"))
|
||||
if not obj.Active:
|
||||
path = Path.Path("(inactive operation)")
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = False
|
||||
return
|
||||
|
||||
toolLoad = obj.ToolController
|
||||
if toolLoad is None or toolLoad.ToolNumber == 0:
|
||||
@@ -360,51 +241,40 @@ class ObjectPocket:
|
||||
self.radius = tool.Diameter/2
|
||||
|
||||
if obj.Base:
|
||||
PathLog.debug("base items exist. Processing...")
|
||||
for b in obj.Base:
|
||||
PathLog.debug("Base item: {}".format(b))
|
||||
for sub in b[1]:
|
||||
import Part
|
||||
import PathScripts.PathKurveUtils
|
||||
if "Face" in sub:
|
||||
shape = getattr(b[0].Shape, sub)
|
||||
wire = shape.OuterWire
|
||||
edges = wire.Edges
|
||||
else:
|
||||
edges = [getattr(b[0].Shape, sub) for sub in b[1]]
|
||||
wire = Part.Wire(edges)
|
||||
shape = None
|
||||
shape = Part.makeFace(edges, 'Part::FaceMakerSimple')
|
||||
|
||||
# output = ""
|
||||
if obj.Algorithm == "OCC Native":
|
||||
if shape is None:
|
||||
shape = wire
|
||||
output += self.buildpathocc(obj, shape)
|
||||
else:
|
||||
try:
|
||||
import area
|
||||
except:
|
||||
FreeCAD.Console.PrintError(translate("PathKurve", "libarea needs to be installed for this command to work.\n"))
|
||||
return
|
||||
env = PathUtils.getEnvelope(shape, obj.StartDepth)
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, env.cut(b[0].Shape)).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a pocket path. Check project and tool config.")
|
||||
else: # process the job base object as a whole
|
||||
PathLog.debug("processing the whole job base object")
|
||||
parentJob = PathUtils.findParentJob(obj)
|
||||
if parentJob is None:
|
||||
return
|
||||
baseobject = parentJob.Base
|
||||
if baseobject is None:
|
||||
return
|
||||
env = PathUtils.getEnvelope(baseobject.Shape, obj.StartDepth)
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, env.cut(baseobject.Shape)).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a pocket path. Check project and tool config.")
|
||||
|
||||
a = area.Area()
|
||||
if shape is None:
|
||||
c = PathScripts.PathKurveUtils.makeAreaCurve(wire.Edges, 'CW')
|
||||
a.append(c)
|
||||
else:
|
||||
for w in shape.Wires:
|
||||
c = PathScripts.PathKurveUtils.makeAreaCurve(w.Edges, 'CW')
|
||||
a.append(c)
|
||||
|
||||
a.Reorder()
|
||||
output += self.buildpathlibarea(obj, a)
|
||||
|
||||
if obj.Active:
|
||||
path = Path.Path(output)
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = True
|
||||
else:
|
||||
path = Path.Path("(inactive operation)")
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = False
|
||||
path = Path.Path(commandlist)
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = True
|
||||
|
||||
|
||||
class _CommandSetPocketStartPoint:
|
||||
@@ -468,6 +338,7 @@ class CommandPathPocket:
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
PathLog.track()
|
||||
|
||||
zbottom = 0.0
|
||||
ztop = 10.0
|
||||
@@ -480,22 +351,18 @@ class CommandPathPocket:
|
||||
FreeCADGui.doCommand('obj.Active = True')
|
||||
FreeCADGui.doCommand('PathScripts.PathPocket.ViewProviderPocket(obj.ViewObject)')
|
||||
FreeCADGui.doCommand('from PathScripts import PathUtils')
|
||||
FreeCADGui.doCommand('obj.Algorithm = "libarea"')
|
||||
FreeCADGui.doCommand('obj.StepOver = 100')
|
||||
FreeCADGui.doCommand('obj.ClearanceHeight = 10') # + str(bb.ZMax + 2.0))
|
||||
FreeCADGui.doCommand('obj.StepDown = 1.0')
|
||||
FreeCADGui.doCommand('obj.StartDepth = ' + str(ztop))
|
||||
FreeCADGui.doCommand('obj.FinalDepth =' + str(zbottom))
|
||||
FreeCADGui.doCommand('obj.ZigZagAngle = 45')
|
||||
FreeCADGui.doCommand('obj.UseEntry = False')
|
||||
FreeCADGui.doCommand('obj.RampAngle = 3.0')
|
||||
FreeCADGui.doCommand('obj.RampSize = 0.75')
|
||||
FreeCADGui.doCommand('obj.HelixSize = 0.75')
|
||||
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
|
||||
FreeCADGui.doCommand('PathScripts.PathPocket.ObjectPocket.setDepths(obj.Proxy, obj)')
|
||||
FreeCADGui.doCommand('obj.ToolController = PathScripts.PathUtils.findToolController(obj)')
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
#FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
|
||||
|
||||
|
||||
@@ -534,14 +401,8 @@ class TaskPanel:
|
||||
self.obj.MaterialAllowance = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value
|
||||
if hasattr(self.obj, "UseStartPoint"):
|
||||
self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
|
||||
if hasattr(self.obj, "Algorithm"):
|
||||
self.obj.Algorithm = str(self.form.algorithmSelect.currentText())
|
||||
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"):
|
||||
@@ -561,16 +422,14 @@ class TaskPanel:
|
||||
self.form.stepDown.setText(FreeCAD.Units.Quantity(self.obj.StepDown.Value, FreeCAD.Units.Length).UserString)
|
||||
self.form.extraOffset.setText(FreeCAD.Units.Quantity(self.obj.MaterialAllowance, FreeCAD.Units.Length).UserString)
|
||||
self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
|
||||
self.form.useZigZag.setChecked(self.obj.UseZigZag)
|
||||
self.form.zigZagUnidirectional.setChecked(self.obj.ZigUnidirectional)
|
||||
self.form.zigZagAngle.setText(FreeCAD.Units.Quantity(self.obj.ZigZagAngle, FreeCAD.Units.Angle).UserString)
|
||||
self.form.stepOverPercent.setValue(self.obj.StepOver)
|
||||
|
||||
index = self.form.algorithmSelect.findText(self.obj.Algorithm, QtCore.Qt.MatchFixedString)
|
||||
if index >= 0:
|
||||
self.form.algorithmSelect.blockSignals(True)
|
||||
self.form.algorithmSelect.setCurrentIndex(index)
|
||||
self.form.algorithmSelect.blockSignals(False)
|
||||
# index = self.form.algorithmSelect.findText(self.obj.Algorithm, QtCore.Qt.MatchFixedString)
|
||||
# if index >= 0:
|
||||
# self.form.algorithmSelect.blockSignals(True)
|
||||
# self.form.algorithmSelect.setCurrentIndex(index)
|
||||
# self.form.algorithmSelect.blockSignals(False)
|
||||
|
||||
index = self.form.cutMode.findText(
|
||||
self.obj.CutMode, QtCore.Qt.MatchFixedString)
|
||||
@@ -579,8 +438,6 @@ class TaskPanel:
|
||||
self.form.cutMode.setCurrentIndex(index)
|
||||
self.form.cutMode.blockSignals(False)
|
||||
|
||||
# for i in self.obj.Base:
|
||||
# self.form.baseList.addItem(i[0].Name + "." + i[1][0])
|
||||
self.form.baseList.blockSignals(True)
|
||||
for i in self.obj.Base:
|
||||
for sub in i[1]:
|
||||
@@ -632,9 +489,6 @@ class TaskPanel:
|
||||
for sub in i[1]:
|
||||
self.form.baseList.addItem(i[0].Name + "." + sub)
|
||||
|
||||
# for i in self.obj.Base:
|
||||
# self.form.baseList.addItem(i[0].Name + "." + i[1][0])
|
||||
|
||||
def deleteBase(self):
|
||||
dlist = self.form.baseList.selectedItems()
|
||||
newlist = []
|
||||
@@ -701,15 +555,12 @@ class TaskPanel:
|
||||
self.form.clearanceHeight.editingFinished.connect(self.getFields)
|
||||
|
||||
# operation
|
||||
self.form.algorithmSelect.currentIndexChanged.connect(self.getFields)
|
||||
self.form.cutMode.currentIndexChanged.connect(self.getFields)
|
||||
self.form.useStartPoint.clicked.connect(self.getFields)
|
||||
self.form.extraOffset.editingFinished.connect(self.getFields)
|
||||
|
||||
# Pattern
|
||||
self.form.stepOverPercent.editingFinished.connect(self.getFields)
|
||||
self.form.useZigZag.clicked.connect(self.getFields)
|
||||
self.form.zigZagUnidirectional.clicked.connect(self.getFields)
|
||||
self.form.zigZagAngle.editingFinished.connect(self.getFields)
|
||||
|
||||
self.setFields()
|
||||
|
||||
@@ -25,17 +25,17 @@
|
||||
import FreeCAD
|
||||
import Path
|
||||
import numpy
|
||||
import TechDraw
|
||||
import ArchPanel
|
||||
import Part
|
||||
|
||||
from FreeCAD import Vector
|
||||
from PathScripts import PathUtils
|
||||
from PathScripts.PathUtils import depth_params
|
||||
import PathScripts.PathLog as PathLog
|
||||
|
||||
LOG_MODULE = 'PathProfile'
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, LOG_MODULE)
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
# PathLog.trackModule('PathProfile')
|
||||
FreeCAD.setLogLevel('Path.Area', 0)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
@@ -73,14 +73,6 @@ class ObjectProfile:
|
||||
# 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"))
|
||||
|
||||
# Profile Properties
|
||||
obj.addProperty("App::PropertyEnumeration", "Side", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Side of edge that tool should cut"))
|
||||
@@ -88,8 +80,6 @@ class ObjectProfile:
|
||||
obj.addProperty("App::PropertyEnumeration", "Direction", "Profile", 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 profile runs
|
||||
obj.addProperty("App::PropertyBool", "UseComp", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if using Cutter Radius Compensation"))
|
||||
|
||||
obj.addProperty("App::PropertyDistance", "RollRadius", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Radius at start and end"))
|
||||
obj.addProperty("App::PropertyDistance", "OffsetExtra", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra value to stay away from final profile- good for roughing toolpath"))
|
||||
obj.addProperty("App::PropertyBool", "processHoles", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile holes as well as the outline"))
|
||||
obj.addProperty("App::PropertyBool", "processPerimeter", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile the outline"))
|
||||
@@ -145,29 +135,45 @@ class ObjectProfile:
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
|
||||
def _buildPathLibarea(self, obj, edgelist, isHole):
|
||||
import PathScripts.PathKurveUtils as PathKurveUtils
|
||||
# import math
|
||||
# import area
|
||||
def _buildPathArea(self, obj, baseobject, isHole, start=None):
|
||||
PathLog.track()
|
||||
profile = Path.Area()
|
||||
profile.setPlane(Part.makeCircle(10))
|
||||
profile.add(baseobject)
|
||||
|
||||
PathLog.track("edgelist: {} \n".format(edgelist))
|
||||
profileparams = {'Fill': 0,
|
||||
'Coplanar': 0,
|
||||
'Offset': 0.0,
|
||||
'SectionCount': -1}
|
||||
|
||||
output = ""
|
||||
if obj.Comment != "":
|
||||
output += '(' + str(obj.Comment)+')\n'
|
||||
if obj.UseComp:
|
||||
if isHole:
|
||||
profileparams['Offset'] = 0 - self.radius+obj.OffsetExtra.Value
|
||||
else:
|
||||
profileparams['Offset'] = self.radius+obj.OffsetExtra.Value
|
||||
|
||||
if obj.StartPoint and obj.UseStartPoint:
|
||||
startpoint = obj.StartPoint
|
||||
else:
|
||||
startpoint = None
|
||||
profile.setParams(**profileparams)
|
||||
# PathLog.debug("About to profile with params: {}".format(profileparams))
|
||||
PathLog.debug("About to profile with params: {}".format(profile.getParams()))
|
||||
|
||||
if obj.EndPoint and obj.UseEndPoint:
|
||||
endpoint = obj.EndPoint
|
||||
else:
|
||||
endpoint = None
|
||||
depthparams = depth_params(
|
||||
clearance_height=obj.ClearanceHeight.Value,
|
||||
rapid_safety_space=obj.SafeHeight.Value,
|
||||
start_depth=obj.StartDepth.Value,
|
||||
step_down=obj.StepDown.Value,
|
||||
z_finish_step=0.0,
|
||||
final_depth=obj.FinalDepth.Value,
|
||||
user_depths=None)
|
||||
|
||||
PathKurveUtils.output('mem')
|
||||
PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed)
|
||||
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': False,
|
||||
'resume_height': obj.StepDown.Value,
|
||||
'retraction': obj.ClearanceHeight.Value}
|
||||
|
||||
# Reverse the direction for holes
|
||||
if isHole:
|
||||
@@ -175,50 +181,28 @@ class ObjectProfile:
|
||||
else:
|
||||
direction = obj.Direction
|
||||
|
||||
output = ""
|
||||
output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
|
||||
curve = PathKurveUtils.makeAreaCurve(edgelist, direction, startpoint, endpoint)
|
||||
if direction == 'CCW':
|
||||
params['orientation'] = 1
|
||||
else:
|
||||
params['orientation'] = 0
|
||||
|
||||
'''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle
|
||||
print "x = " + str(point.x)
|
||||
print "y - " + str(point.y)
|
||||
holding tags
|
||||
start location
|
||||
CRC
|
||||
or probably other features in heekscnc'''
|
||||
if obj.UseStartPoint is True and obj.StartPoint is not None:
|
||||
params['start'] = obj.StartPoint
|
||||
|
||||
'''The following calls the original procedure from h
|
||||
toolLoad = obj.activeTCeekscnc profile function. This, in turn, calls many other procedures to modify the profile.
|
||||
This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be
|
||||
thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16'''
|
||||
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
|
||||
pp = Path.fromShapes(**params)
|
||||
PathLog.debug("Generating Path with params: {}".format(params))
|
||||
PathLog.debug(pp)
|
||||
|
||||
depthparams = depth_params(
|
||||
obj.ClearanceHeight.Value,
|
||||
obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0,
|
||||
obj.FinalDepth.Value, None)
|
||||
|
||||
PathKurveUtils.profile2(
|
||||
curve, obj.Side, self.radius, self.vertFeed, self.horizFeed,
|
||||
self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius,
|
||||
None, None, depthparams, extend_at_start, extend_at_end,
|
||||
lead_in_line_len, lead_out_line_len)
|
||||
|
||||
output += PathKurveUtils.retrieve_gcode()
|
||||
return output
|
||||
return pp
|
||||
|
||||
def execute(self, obj):
|
||||
import Part # math #DraftGeomUtils
|
||||
output = ""
|
||||
import Part
|
||||
commandlist = []
|
||||
|
||||
toolLoad = obj.ToolController
|
||||
if toolLoad is None or toolLoad.ToolNumber == 0:
|
||||
FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.")
|
||||
#return
|
||||
return
|
||||
else:
|
||||
self.vertFeed = toolLoad.VertFeed.Value
|
||||
self.horizFeed = toolLoad.HorizFeed.Value
|
||||
@@ -231,11 +215,12 @@ print "y - " + str(point.y)
|
||||
else:
|
||||
self.radius = tool.Diameter/2
|
||||
|
||||
output += "(" + obj.Label + ")"
|
||||
commandlist.append(Path.Command("(" + obj.Label + ")"))
|
||||
|
||||
if obj.UseComp:
|
||||
output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"
|
||||
commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"))
|
||||
else:
|
||||
output += "(Uncompensated Tool Path)"
|
||||
commandlist.append(Path.Command("(Uncompensated Tool Path)"))
|
||||
|
||||
if obj.Base:
|
||||
holes = []
|
||||
@@ -247,25 +232,40 @@ print "y - " + str(point.y)
|
||||
faces.append(shape)
|
||||
if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face
|
||||
holes += shape.Wires[1:]
|
||||
|
||||
else:
|
||||
print ("found a base object which is not a face. Can't continue.")
|
||||
return
|
||||
profileshape = Part.makeCompound(faces)
|
||||
profilewire = TechDraw.findShapeOutline(profileshape, 1, Vector(0, 0, 1))
|
||||
|
||||
if obj.processHoles:
|
||||
for wire in holes:
|
||||
edgelist = wire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
output += self._buildPathLibarea(obj, edgelist, True)
|
||||
f = Part.makeFace(wire, 'Part::FaceMakerSimple')
|
||||
|
||||
# shift the compound to the bottom of the base object for
|
||||
# proper sectioning
|
||||
zShift = b[0].Shape.BoundBox.ZMin - f.BoundBox.ZMin
|
||||
newPlace = FreeCAD.Placement(FreeCAD.Vector(0, 0, zShift), f.Placement.Rotation)
|
||||
f.Placement = newPlace
|
||||
env = PathUtils.getEnvelope(f, obj.StartDepth)
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, baseobject=env, isHole=True, start=None).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
|
||||
profileshape = Part.makeCompound(faces)
|
||||
zShift = b[0].Shape.BoundBox.ZMin - profileshape.BoundBox.ZMin
|
||||
newPlace = FreeCAD.Placement(FreeCAD.Vector(0, 0, zShift), profileshape.Placement.Rotation)
|
||||
profileshape.Placement = newPlace
|
||||
|
||||
if obj.processPerimeter:
|
||||
edgelist = profilewire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
output += self._buildPathLibarea(obj, edgelist, False)
|
||||
env = PathUtils.getEnvelope(profileshape, obj.StartDepth)
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, baseobject=env, isHole=False, start=None).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: #Try to build targets frorm the job base
|
||||
else: # Try to build targets frorm the job base
|
||||
parentJob = PathUtils.findParentJob(obj)
|
||||
if parentJob is None:
|
||||
return
|
||||
@@ -279,28 +279,29 @@ print "y - " + str(point.y)
|
||||
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)))
|
||||
try:
|
||||
output += self._buildPathLibarea(obj, edgelist, isHole=False)
|
||||
except:
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
f = Part.makeFace(wire, 'Part::FaceMakerSimple')
|
||||
env = PathUtils.getEnvelope(f, obj.StartDepth)
|
||||
try:
|
||||
commandlist.extend(self._buildPathArea(obj, baseobject=env, isHole=False, start=None).Commands)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
|
||||
shapes = baseobject.Proxy.getHoles(baseobject, transform=True)
|
||||
for shape in shapes:
|
||||
for wire in shape.Wires:
|
||||
drillable = PathUtils.isDrillable(baseobject.Proxy, wire)
|
||||
if (drillable and obj.processCircles) or (not drillable and obj.processHoles):
|
||||
edgelist = wire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
f = Part.makeFace(wire, 'Part::FaceMakerSimple')
|
||||
env = PathUtils.getEnvelope(f, obj.StartDepth)
|
||||
try:
|
||||
output += self._buildPathLibarea(obj, edgelist, isHole=True)
|
||||
except:
|
||||
commandlist.extend(self._buildPathArea(obj, baseobject=env, isHole=True, start=None).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
|
||||
obj.ViewObject.Visibility = True
|
||||
|
||||
@@ -356,25 +357,6 @@ class _CommandSetStartPoint:
|
||||
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
|
||||
|
||||
|
||||
class _CommandSetEndPoint:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Path-EndPoint',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick End Point"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "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)
|
||||
|
||||
|
||||
class CommandPathProfile:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Path-Profile-Face',
|
||||
@@ -454,14 +436,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, "Side"):
|
||||
self.obj.Side = str(self.form.cutSide.currentText())
|
||||
if hasattr(self.obj, "Direction"):
|
||||
@@ -486,10 +464,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.processHoles.setChecked(self.obj.processHoles)
|
||||
self.form.processPerimeter.setChecked(self.obj.processPerimeter)
|
||||
self.form.processCircles.setChecked(self.obj.processCircles)
|
||||
@@ -513,6 +489,7 @@ class TaskPanel:
|
||||
self.form.uiToolController.blockSignals(True)
|
||||
self.form.uiToolController.addItems(labels)
|
||||
self.form.uiToolController.blockSignals(False)
|
||||
|
||||
if self.obj.ToolController is not None:
|
||||
index = self.form.uiToolController.findText(
|
||||
self.obj.ToolController.Label, QtCore.Qt.MatchFixedString)
|
||||
@@ -628,9 +605,7 @@ class TaskPanel:
|
||||
self.form.direction.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.form.processHoles.clicked.connect(self.getFields)
|
||||
self.form.processPerimeter.clicked.connect(self.getFields)
|
||||
self.form.processCircles.clicked.connect(self.getFields)
|
||||
@@ -660,6 +635,5 @@ if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Profile', CommandPathProfile())
|
||||
FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint())
|
||||
FreeCADGui.addCommand('Set_EndPoint', _CommandSetEndPoint())
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathProfile... done\n")
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
import FreeCAD
|
||||
import Path
|
||||
import Part
|
||||
from PathScripts import PathUtils
|
||||
from PathScripts.PathUtils import depth_params
|
||||
from DraftGeomUtils import findWires
|
||||
@@ -33,7 +34,7 @@ from PathScripts.PathUtils import waiting_effects
|
||||
"""Path Profile from Edges Object and Command"""
|
||||
|
||||
LOG_MODULE = 'PathProfileEdges'
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, LOG_MODULE)
|
||||
# PathLog.trackModule('PathProfileEdges')
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
@@ -72,23 +73,14 @@ class ObjectProfile:
|
||||
# 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"))
|
||||
|
||||
# Profile Properties
|
||||
obj.addProperty("App::PropertyEnumeration", "Side", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Side of edge that tool should cut"))
|
||||
obj.Side = ['Left', 'Right', 'On'] # side of profile that cutter is on in relation to direction of profile
|
||||
obj.Side = ['Left', 'Right'] # side of profile that cutter is on in relation to direction of profile
|
||||
obj.addProperty("App::PropertyEnumeration", "Direction", "Profile", 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 profile runs
|
||||
obj.addProperty("App::PropertyBool", "UseComp", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if using Cutter Radius Compensation"))
|
||||
|
||||
obj.addProperty("App::PropertyDistance", "RollRadius", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Radius at start and end"))
|
||||
obj.addProperty("App::PropertyDistance", "OffsetExtra", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra value to stay away from final profile- good for roughing toolpath"))
|
||||
|
||||
obj.Proxy = self
|
||||
@@ -134,70 +126,82 @@ class ObjectProfile:
|
||||
else:
|
||||
baselist.append(item)
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
#self.execute(obj)
|
||||
|
||||
|
||||
@waiting_effects
|
||||
def _buildPathLibarea(self, obj, edgelist):
|
||||
import PathScripts.PathKurveUtils as PathKurveUtils
|
||||
# import math
|
||||
# import area
|
||||
output = ""
|
||||
if obj.Comment != "":
|
||||
output += '(' + str(obj.Comment)+')\n'
|
||||
def _buildPathArea(self, obj, baseobject, start=None):
|
||||
PathLog.track()
|
||||
profile = Path.Area()
|
||||
profile.setPlane(Part.makeCircle(10))
|
||||
profile.add(baseobject)
|
||||
|
||||
if obj.StartPoint and obj.UseStartPoint:
|
||||
startpoint = obj.StartPoint
|
||||
else:
|
||||
startpoint = None
|
||||
profileparams = {'Fill': 0,
|
||||
'Coplanar': 0,
|
||||
'Offset': 0.0,
|
||||
'SectionCount': -1}
|
||||
|
||||
if obj.EndPoint and obj.UseEndPoint:
|
||||
endpoint = obj.EndPoint
|
||||
else:
|
||||
endpoint = None
|
||||
if obj.UseComp:
|
||||
if obj.Side == 'Right':
|
||||
profileparams['Offset'] = 0 - self.radius+obj.OffsetExtra.Value
|
||||
else:
|
||||
profileparams['Offset'] = self.radius+obj.OffsetExtra.Value
|
||||
|
||||
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)
|
||||
|
||||
'''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle
|
||||
print("x = " + str(point.x))
|
||||
print("y - " + str(point.y))
|
||||
holding tags
|
||||
start location
|
||||
CRC
|
||||
or probably other features in heekscnc'''
|
||||
# output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)
|
||||
|
||||
'''The following calls the original procedure from h
|
||||
toolLoad = obj.activeTCeekscnc profile function. This, in turn, calls many other procedures to modify the profile.
|
||||
This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be
|
||||
thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16'''
|
||||
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
|
||||
profile.setParams(**profileparams)
|
||||
# PathLog.debug("About to profile with params: {}".format(profileparams))
|
||||
PathLog.debug("About to profile with params: {}".format(profile.getParams()))
|
||||
|
||||
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)
|
||||
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': False,
|
||||
'resume_height': obj.StepDown.Value,
|
||||
'retraction': obj.ClearanceHeight.Value}
|
||||
|
||||
# Reverse the direction for holes
|
||||
# if isHole:
|
||||
# direction = "CW" if obj.Direction == "CCW" else "CCW"
|
||||
# else:
|
||||
# direction = obj.Direction
|
||||
|
||||
if obj.Direction == 'CCW':
|
||||
params['orientation'] = 0
|
||||
else:
|
||||
params['orientation'] = 1
|
||||
|
||||
if obj.UseStartPoint is True and obj.StartPoint is not None:
|
||||
params['start'] = obj.StartPoint
|
||||
|
||||
pp = Path.fromShapes(**params)
|
||||
PathLog.debug("Generating Path with params: {}".format(params))
|
||||
PathLog.debug(pp)
|
||||
|
||||
return pp
|
||||
|
||||
output += PathKurveUtils.retrieve_gcode()
|
||||
return output
|
||||
|
||||
def execute(self, obj):
|
||||
import Part # math #DraftGeomUtils
|
||||
output = ""
|
||||
# import Part # math #DraftGeomUtils
|
||||
commandlist = []
|
||||
|
||||
if not obj.Active:
|
||||
path = Path.Path("(inactive operation)")
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = False
|
||||
return
|
||||
|
||||
|
||||
toolLoad = obj.ToolController
|
||||
if toolLoad is None or toolLoad.ToolNumber == 0:
|
||||
@@ -214,12 +218,13 @@ print("y - " + str(point.y))
|
||||
else:
|
||||
self.radius = tool.Diameter/2
|
||||
|
||||
output += "(" + obj.Label + ")"
|
||||
commandlist.append(Path.Command("(" + obj.Label + ")"))
|
||||
|
||||
if obj.UseComp:
|
||||
output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"
|
||||
commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"))
|
||||
else:
|
||||
output += "(Uncompensated Tool Path)"
|
||||
|
||||
commandlist.append(Path.Command("(Uncompensated Tool Path)"))
|
||||
|
||||
if obj.Base:
|
||||
wires = []
|
||||
|
||||
@@ -230,19 +235,26 @@ print("y - " + str(point.y))
|
||||
wires.extend(findWires(edgelist))
|
||||
|
||||
for wire in wires:
|
||||
edgelist = wire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
output += self._buildPathLibarea(obj, edgelist)
|
||||
f = Part.makeFace(wire, 'Part::FaceMakerSimple')
|
||||
|
||||
if obj.Active:
|
||||
path = Path.Path(output)
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = True
|
||||
# shift the compound to the bottom of the base object for
|
||||
# proper sectioning
|
||||
zShift = b[0].Shape.BoundBox.ZMin - f.BoundBox.ZMin
|
||||
newPlace = FreeCAD.Placement(FreeCAD.Vector(0, 0, zShift), f.Placement.Rotation)
|
||||
f.Placement = newPlace
|
||||
env = PathUtils.getEnvelope(f, obj.StartDepth)
|
||||
|
||||
else:
|
||||
path = Path.Path("(inactive operation)")
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = False
|
||||
try:
|
||||
# commandlist.extend(self._buildPathArea(obj, wire).Commands)
|
||||
commandlist.extend(self._buildPathArea(obj, baseobject=env, start=None).Commands)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
|
||||
path = Path.Path(commandlist)
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = True
|
||||
|
||||
|
||||
class _ViewProviderProfile:
|
||||
@@ -342,7 +354,7 @@ class CommandPathProfileEdges:
|
||||
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
|
||||
|
||||
FreeCADGui.doCommand('obj.SafeHeight = ' + str(ztop + 2.0))
|
||||
FreeCADGui.doCommand('obj.Side = "On"')
|
||||
FreeCADGui.doCommand('obj.Side = "Right"')
|
||||
FreeCADGui.doCommand('obj.OffsetExtra = 0.0')
|
||||
FreeCADGui.doCommand('obj.Direction = "CW"')
|
||||
FreeCADGui.doCommand('obj.UseComp = True')
|
||||
@@ -390,14 +402,8 @@ 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, "Side"):
|
||||
self.obj.Side = str(self.form.cutSide.currentText())
|
||||
if hasattr(self.obj, "Direction"):
|
||||
@@ -416,10 +422,7 @@ 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)
|
||||
|
||||
controllers = PathUtils.getToolControllers(self.obj)
|
||||
labels = [c.Label for c in controllers]
|
||||
@@ -549,10 +552,7 @@ class TaskPanel:
|
||||
self.form.cutSide.currentIndexChanged.connect(self.getFields)
|
||||
self.form.direction.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()
|
||||
|
||||
sel = FreeCADGui.Selection.getSelectionEx()
|
||||
@@ -577,7 +577,5 @@ class SelObserver:
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Profile_Edges', CommandPathProfileEdges())
|
||||
FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint())
|
||||
FreeCADGui.addCommand('Set_EndPoint', _CommandSetEndPoint())
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathProfileEdges... done\n")
|
||||
|
||||
@@ -38,10 +38,9 @@ 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:
|
||||
@@ -253,10 +252,16 @@ def getEnvelope(partshape, stockheight=None):
|
||||
# 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))
|
||||
eLength = float(stockheight)-partshape.BoundBox.ZMin
|
||||
envelopeshape = sec.extrude(FreeCAD.Vector(0, 0, eLength))
|
||||
else:
|
||||
return sec.extrude(FreeCAD.Vector(0, 0, partshape.BoundBox.ZLength))
|
||||
envelopeshape = sec.extrude(FreeCAD.Vector(0, 0, partshape.BoundBox.ZLength))
|
||||
if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG:
|
||||
removalshape=FreeCAD.ActiveDocument.addObject("Part::Feature","RemovedMaterial")
|
||||
removalshape.Shape = envelopeshape
|
||||
return envelopeshape
|
||||
|
||||
|
||||
def reverseEdge(e):
|
||||
|
||||
Reference in New Issue
Block a user