Merge branch 'master' into path_helix

This commit is contained in:
lorenz
2017-01-15 13:52:27 +01:00
committed by GitHub
285 changed files with 18520 additions and 31835 deletions

View File

@@ -121,12 +121,12 @@ int ToolPy::PyInit(PyObject* args, PyObject* kwd)
else
getToolPtr()->Material = Tool::MATUNDEFINED;
getToolPtr()->Diameter = PyFloat_AsDouble(dia);
getToolPtr()->LengthOffset = PyFloat_AsDouble(len);
getToolPtr()->FlatRadius = PyFloat_AsDouble(fla);
getToolPtr()->CornerRadius = PyFloat_AsDouble(cor);
getToolPtr()->CuttingEdgeAngle = PyFloat_AsDouble(ang);
getToolPtr()->CuttingEdgeHeight = PyFloat_AsDouble(hei);
getToolPtr()->Diameter = dia ? PyFloat_AsDouble(dia) : 0.0;
getToolPtr()->LengthOffset = len ? PyFloat_AsDouble(len) : 0.0;
getToolPtr()->FlatRadius = fla ? PyFloat_AsDouble(fla) : 0.0;
getToolPtr()->CornerRadius = cor ? PyFloat_AsDouble(cor) : 0.0;
getToolPtr()->CuttingEdgeAngle = ang ? PyFloat_AsDouble(ang) : 0.0;
getToolPtr()->CuttingEdgeHeight = hei ? PyFloat_AsDouble(hei) : 0.0;
return 0;
}

View File

@@ -26,6 +26,7 @@ SET(PathScripts_SRCS
PathScripts/PathDressup.py
PathScripts/PathDressupDogbone.py
PathScripts/PathDressupDragknife.py
PathScripts/PathDressupHoldingTags.py
PathScripts/PathDrilling.py
PathScripts/PathEngrave.py
PathScripts/PathFacePocket.py
@@ -44,6 +45,7 @@ SET(PathScripts_SRCS
PathScripts/PathPost.py
PathScripts/PathPostProcessor.py
PathScripts/PathPreferences.py
PathScripts/PathPreferencesPathDressup.py
PathScripts/PathPreferencesPathJob.py
PathScripts/PathProfile.py
PathScripts/PathProfileEdges.py
@@ -75,6 +77,7 @@ SET(PathScripts_SRCS
PathScripts/slic3r_pre.py
PathTests/PathTestUtils.py
PathTests/TestPathDepthParams.py
PathTests/TestPathDressupHoldingTags.py
PathTests/TestPathGeom.py
PathTests/TestPathPost.py
PathTests/__init__.py

View File

@@ -54,9 +54,11 @@
<file>panels/DogboneEdit.ui</file>
<file>panels/DrillingEdit.ui</file>
<file>panels/EngraveEdit.ui</file>
<file>panels/HoldingTagsEdit.ui</file>
<file>panels/JobEdit.ui</file>
<file>panels/MillFaceEdit.ui</file>
<file>panels/PocketEdit.ui</file>
<file>panels/PointEdit.ui</file>
<file>panels/ProfileEdgesEdit.ui</file>
<file>panels/ProfileEdit.ui</file>
<file>panels/RemoteEdit.ui</file>
@@ -64,6 +66,7 @@
<file>panels/ToolControl.ui</file>
<file>panels/ToolEdit.ui</file>
<file>panels/ToolLibraryEditor.ui</file>
<file>preferences/PathDressupHoldingTags.ui</file>
<file>preferences/PathJob.ui</file>
<file>translations/Path_af.qm</file>
<file>translations/Path_cs.qm</file>

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -23,7 +23,7 @@
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>3</number>
<number>2</number>
</property>
<widget class="QWidget" name="Depths">
<property name="geometry">
@@ -31,7 +31,7 @@
<x>0</x>
<y>0</y>
<width>334</width>
<height>313</height>
<height>347</height>
</rect>
</property>
<attribute name="icon">
@@ -98,7 +98,7 @@
<x>0</x>
<y>0</y>
<width>334</width>
<height>313</height>
<height>347</height>
</rect>
</property>
<attribute name="icon">
@@ -142,71 +142,13 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="Holding">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>313</height>
</rect>
</property>
<attribute name="label">
<string>Holding</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QPushButton" name="addTag">
<property name="text">
<string>Add New</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="deleteTag">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QTreeWidget" name="tagTree">
<column>
<property name="text">
<string>Tag</string>
</property>
</column>
<column>
<property name="text">
<string>Location</string>
</property>
</column>
<column>
<property name="text">
<string>Height</string>
</property>
</column>
<column>
<property name="text">
<string>Length</string>
</property>
</column>
<column>
<property name="text">
<string>Angle</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_3">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>313</height>
<height>347</height>
</rect>
</property>
<attribute name="icon">
@@ -277,30 +219,6 @@
<item row="3" column="1">
<widget class="QWidget" name="widget_4" native="true">
<layout class="QGridLayout" name="gridLayout_6">
<item row="3" column="2">
<widget class="QDoubleSpinBox" name="plungeAngle"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Plunge Angle</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Roll Radius</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Segment Length</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
@@ -309,7 +227,14 @@
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="segLen"/>
<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">
@@ -321,13 +246,10 @@
</property>
</widget>
</item>
<item row="2" 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>
<item row="1" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Roll Radius</string>
</property>
</widget>
</item>

View File

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>352</width>
<width>376</width>
<height>387</height>
</rect>
</property>
@@ -27,8 +27,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>340</height>
<width>358</width>
<height>333</height>
</rect>
</property>
<attribute name="label">

View File

@@ -34,7 +34,7 @@
<x>0</x>
<y>0</y>
<width>304</width>
<height>367</height>
<height>375</height>
</rect>
</property>
<attribute name="icon">
@@ -111,8 +111,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>367</height>
<width>109</width>
<height>82</height>
</rect>
</property>
<attribute name="icon">
@@ -172,8 +172,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>367</height>
<width>144</width>
<height>82</height>
</rect>
</property>
<attribute name="icon">
@@ -233,8 +233,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>367</height>
<width>223</width>
<height>31</height>
</rect>
</property>
<attribute name="icon">

View File

@@ -34,7 +34,7 @@
<x>0</x>
<y>0</y>
<width>303</width>
<height>366</height>
<height>374</height>
</rect>
</property>
<attribute name="icon">
@@ -111,8 +111,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>303</width>
<height>366</height>
<width>109</width>
<height>56</height>
</rect>
</property>
<attribute name="icon">
@@ -158,8 +158,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>303</width>
<height>366</height>
<width>144</width>
<height>56</height>
</rect>
</property>
<attribute name="icon">
@@ -205,8 +205,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>303</width>
<height>366</height>
<width>223</width>
<height>31</height>
</rect>
</property>
<attribute name="icon">

View File

@@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskPanel</class>
<widget class="QWidget" name="TaskPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>399</width>
<height>564</height>
</rect>
</property>
<property name="windowTitle">
<string>Holding Tags</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QToolBox" name="toolBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tbpTags">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>510</height>
</rect>
</property>
<attribute name="label">
<string>Tags</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QFormLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Width</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Height</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Angle </string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::InputField" name="ifWidth">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width of the resulting holding tag.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::InputField" name="ifHeight">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height of holding tag.&lt;/p&gt;&lt;p&gt;Note that resulting tag might be smaller if the tag's width and angle result in a triangular shape.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="dsbAngle">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Plunge angle for ascent and descent of holding tag.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<double>5.000000000000000</double>
</property>
<property name="maximum">
<double>90.000000000000000</double>
</property>
<property name="singleStep">
<double>15.000000000000000</double>
</property>
<property name="value">
<double>45.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Radius</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::InputField" name="ifRadius">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Radius of the fillet at the top.&lt;/p&gt;&lt;p&gt;If the radius is too big for the tag shape it gets reduced to the maximum possible radius - resulting in a spherical shape.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QListWidget" name="lwTags">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;List of current tags. Edit coordinates by double click or Edit button.&lt;/p&gt;&lt;p&gt;Tags are automatically disabled if they overlap with the previous tag, or don't lie on the base wire.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QPushButton" name="pbDelete">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pbAdd">
<property name="text">
<string>Add...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pbEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Edit...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Auto Generate</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="1">
<widget class="QSpinBox" name="sbCount">
<property name="minimum">
<number>2</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pbGenerate">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Replace All</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Number of Tags</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>374</width>
<width>340</width>
<height>453</height>
</rect>
</property>
@@ -33,8 +33,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>340</width>
<height>277</height>
<width>322</width>
<height>259</height>
</rect>
</property>
<attribute name="icon">
@@ -111,8 +111,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>356</width>
<height>124</height>
<width>322</width>
<height>108</height>
</rect>
</property>
<attribute name="icon">
@@ -123,6 +123,9 @@
<string>Depths</string>
</attribute>
<layout class="QFormLayout" name="formLayout_3">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="Gui::InputField" name="startDepth">
<property name="unit" stdset="0">
@@ -165,19 +168,6 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="stepDown">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
@@ -185,6 +175,16 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="Gui::InputField" name="stepDown">
<property name="text">
<string>0 mm</string>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="Heights">
@@ -192,8 +192,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>356</width>
<height>95</height>
<width>144</width>
<height>56</height>
</rect>
</property>
<attribute name="icon">
@@ -242,8 +242,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>356</width>
<height>296</height>
<width>261</width>
<height>191</height>
</rect>
</property>
<attribute name="icon">
@@ -309,6 +309,13 @@
<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">
@@ -316,16 +323,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_10">
<property name="text">
<string>ZigZag Angle</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QSpinBox" name="zigZagAngle"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="zigZagUnidirectional">
<property name="text">
@@ -333,6 +330,13 @@
</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>
@@ -409,6 +413,11 @@
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
<customwidget>
<class>Gui::QuantitySpinBox</class>
<extends>QWidget</extends>
<header>Gui/QuantitySpinBox.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../Path.qrc"/>

View File

@@ -29,7 +29,7 @@
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>5</number>
<number>0</number>
</property>
<widget class="QWidget" name="Geometry">
<property name="enabled">
@@ -40,7 +40,7 @@
<x>0</x>
<y>0</y>
<width>334</width>
<height>321</height>
<height>343</height>
</rect>
</property>
<attribute name="icon">
@@ -117,8 +117,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>321</height>
<width>114</width>
<height>108</height>
</rect>
</property>
<attribute name="icon">
@@ -195,8 +195,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>321</height>
<width>144</width>
<height>56</height>
</rect>
</property>
<attribute name="icon">
@@ -245,8 +245,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>321</height>
<width>94</width>
<height>24</height>
</rect>
</property>
<attribute name="label">
@@ -259,8 +259,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>321</height>
<width>178</width>
<height>120</height>
</rect>
</property>
<attribute name="label">
@@ -299,6 +299,9 @@
<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">
@@ -313,9 +316,6 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="zigZagAngle"/>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_10">
<property name="text">
@@ -323,6 +323,13 @@
</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>
@@ -334,7 +341,7 @@
<x>0</x>
<y>0</y>
<width>334</width>
<height>321</height>
<height>343</height>
</rect>
</property>
<attribute name="icon">

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>362</width>
<height>182</height>
</rect>
</property>
<property name="windowTitle">
<string>Point Edit</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="wPoint" native="true">
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="lValueX">
<property name="text">
<string>Global X</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::InputField" name="ifValueX"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lValueY">
<property name="text">
<string>Global Y</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::InputField" name="ifValueY"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lValueZ">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Global Z</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::InputField" name="ifValueZ">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -23,7 +23,7 @@
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>4</number>
<number>0</number>
</property>
<widget class="QWidget" name="Geometry">
<property name="enabled">
@@ -34,7 +34,7 @@
<x>0</x>
<y>0</y>
<width>334</width>
<height>313</height>
<height>348</height>
</rect>
</property>
<attribute name="icon">
@@ -112,7 +112,7 @@
<x>0</x>
<y>0</y>
<width>334</width>
<height>313</height>
<height>348</height>
</rect>
</property>
<attribute name="icon">
@@ -182,7 +182,7 @@
<x>0</x>
<y>0</y>
<width>334</width>
<height>313</height>
<height>348</height>
</rect>
</property>
<attribute name="icon">
@@ -226,71 +226,13 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="Holding">
<widget class="QWidget" name="page_3">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>313</height>
</rect>
</property>
<attribute name="label">
<string>Holding</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QPushButton" name="addTag">
<property name="text">
<string>Add New</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="deleteTag">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QTreeWidget" name="tagTree">
<column>
<property name="text">
<string>Tag</string>
</property>
</column>
<column>
<property name="text">
<string>Location</string>
</property>
</column>
<column>
<property name="text">
<string>Height</string>
</property>
</column>
<column>
<property name="text">
<string>Length</string>
</property>
</column>
<column>
<property name="text">
<string>Angle</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_3">
<property name="geometry">
<rect>
<x>0</x>
<y>-15</y>
<width>320</width>
<height>338</height>
<height>348</height>
</rect>
</property>
<attribute name="icon">
@@ -304,93 +246,6 @@
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="2" column="1">
<widget class="QWidget" name="widget_2" native="true">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="useStartPoint">
<property name="text">
<string>Use Start Point</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="useCompensation">
<property name="text">
<string>Use Compensation</string>
</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>
<item row="3" column="1">
<widget class="QWidget" name="widget_4" native="true">
<layout class="QGridLayout" name="gridLayout_6">
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="segLen"/>
</item>
<item row="0" column="2">
<widget class="Gui::InputField" name="extraOffset">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Segment Length</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Roll Radius</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Plunge Angle</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QDoubleSpinBox" name="plungeAngle"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Extra Offset</string>
</property>
</widget>
</item>
<item row="2" 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>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QWidget" name="widget_3" native="true">
<layout class="QGridLayout" name="gridLayout_5">
@@ -447,6 +302,46 @@
</layout>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="widget_2" native="true">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="useStartPoint">
<property name="text">
<string>Use Start Point</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="useCompensation">
<property name="text">
<string>Use Compensation</string>
</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>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>

View File

@@ -23,7 +23,7 @@
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>4</number>
<number>0</number>
</property>
<widget class="QWidget" name="Geometry">
<property name="enabled">
@@ -34,7 +34,7 @@
<x>0</x>
<y>0</y>
<width>381</width>
<height>346</height>
<height>381</height>
</rect>
</property>
<attribute name="icon">
@@ -112,7 +112,7 @@
<x>0</x>
<y>0</y>
<width>381</width>
<height>346</height>
<height>381</height>
</rect>
</property>
<attribute name="icon">
@@ -179,7 +179,7 @@
<x>0</x>
<y>0</y>
<width>381</width>
<height>346</height>
<height>381</height>
</rect>
</property>
<attribute name="icon">
@@ -223,71 +223,13 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="Holding">
<widget class="QWidget" name="page_3">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>346</height>
</rect>
</property>
<attribute name="label">
<string>Holding</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QPushButton" name="addTag">
<property name="text">
<string>Add New</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="deleteTag">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QTreeWidget" name="tagTree">
<column>
<property name="text">
<string>Tag</string>
</property>
</column>
<column>
<property name="text">
<string>Location</string>
</property>
</column>
<column>
<property name="text">
<string>Height</string>
</property>
</column>
<column>
<property name="text">
<string>Length</string>
</property>
</column>
<column>
<property name="text">
<string>Angle</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_3">
<property name="geometry">
<rect>
<x>0</x>
<y>-28</y>
<width>367</width>
<height>384</height>
<height>381</height>
</rect>
</property>
<attribute name="icon">
@@ -345,13 +287,6 @@
<item row="5" column="0" colspan="2">
<widget class="QWidget" name="widget_4" native="true">
<layout class="QGridLayout" name="gridLayout_6">
<item row="3" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Plunge Angle</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
@@ -360,22 +295,12 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Segment Length</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Roll Radius</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QDoubleSpinBox" name="plungeAngle"/>
</item>
<item row="0" column="2">
<widget class="Gui::InputField" name="extraOffset">
<property name="minimum">
@@ -387,9 +312,6 @@
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="segLen"/>
</item>
<item row="2" column="2">
<widget class="Gui::InputField" name="rollRadius">
<property name="minimum">
<double>0.000000000000000</double>

View File

@@ -34,7 +34,7 @@
<x>0</x>
<y>0</y>
<width>334</width>
<height>387</height>
<height>395</height>
</rect>
</property>
<attribute name="icon">
@@ -112,7 +112,7 @@
<x>0</x>
<y>0</y>
<width>334</width>
<height>387</height>
<height>395</height>
</rect>
</property>
<attribute name="icon">
@@ -165,19 +165,6 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="stepDown">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
@@ -185,6 +172,13 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="Gui::InputField" name="stepDown">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="Heights">
@@ -192,8 +186,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>387</height>
<width>144</width>
<height>56</height>
</rect>
</property>
<attribute name="icon">
@@ -242,8 +236,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>387</height>
<width>203</width>
<height>31</height>
</rect>
</property>
<attribute name="icon">

View File

@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>477</width>
<height>478</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Tag Parameters</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="Gui::InputField" name="ifWidth">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the default width of holding tags.&lt;/p&gt;&lt;p&gt;If the width is set to 0 the dressup will try to guess a reasonable value based on the path itself.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Default Width</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="dsbAngle">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Plunge angle for the holding tags ascent and descent.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<double>5.000000000000000</double>
</property>
<property name="maximum">
<double>90.000000000000000</double>
</property>
<property name="singleStep">
<double>15.000000000000000</double>
</property>
<property name="value">
<double>45.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::InputField" name="ifHeight">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Default height of holding tags.&lt;/p&gt;&lt;p&gt;If the specified height is 0 the dressup will use half the height of the part. Should the height be bigger than the height of the part the dressup will reduce the height to the height of the part.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Default Angle</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Default Height</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::InputField" name="ifRadius">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Radius of the fillet on the tag's top edge.&lt;/p&gt;&lt;p&gt;If the radius is bigger than than the tag shape itself supports the resulting shape will be that of a dome.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Default Radius</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Tag Generation</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Initial # Tags </string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="sbCount">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Specify the number of tags generated when a new dressup is created.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>2</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -52,6 +52,9 @@
#include <Gui/BitmapFactory.h>
#include <Gui/SoFCBoundingBox.h>
#define ARC_MIN_SEGMENTS 20.0 // minimum # segements to interpolate an arc
#ifndef M_PI
#define M_PI 3.14159265358979323846
#define M_PI 3.14159265358979323846 /* pi */
@@ -306,8 +309,9 @@ void ViewProviderPath::updateData(const App::Property* prop)
angle = M_PI * 2 - angle;
if (angle == 0)
angle = M_PI * 2;
int segments = 3/(deviation/angle); //we use a rather simple rule here, provisorily
int segments = std::max(ARC_MIN_SEGMENTS, 3.0/(deviation/angle)); //we use a rather simple rule here, provisorily
double dZ = (next.z - last.z)/segments; //How far each segment will helix in Z
for (int j = 1; j < segments; j++) {
//std::cout << "vector " << j << std::endl;
Base::Vector3d inter;

View File

@@ -31,8 +31,9 @@ class PathWorkbench (Workbench):
def Initialize(self):
# Add preferences pages - before loading PathGui to properly order pages of Path group
from PathScripts import PathPreferencesPathJob
FreeCADGui.addPreferencePage(PathPreferencesPathJob.Page, "Path")
from PathScripts import PathPreferencesPathJob, PathPreferencesPathDressup
FreeCADGui.addPreferencePage(PathPreferencesPathJob.JobPreferencesPage, "Path")
FreeCADGui.addPreferencePage(PathPreferencesPathDressup.DressupPreferencesPage, "Path")
# load the builtin modules
import Path
@@ -74,6 +75,7 @@ class PathWorkbench (Workbench):
from PathScripts import PathProfileEdges
from PathScripts import PathDressupDogbone
from PathScripts import PathMillFace
from PathScripts import PathDressupHoldingTags
import PathCommands
# build commands list
@@ -83,7 +85,7 @@ class PathWorkbench (Workbench):
twodopcmdlist = ["Path_Contour", "Path_Profile", "Path_Profile_Edges", "Path_Pocket", "Path_Drilling", "Path_Engrave", "Path_MillFace", "Path_Helix"]
threedopcmdlist = ["Path_Surfacing"]
modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", "Path_SimpleCopy" ]
dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife"]
dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_HoldingTags"]
extracmdlist = ["Path_SelectLoop"]
#modcmdmore = ["Path_Hop",]
#remotecmdlist = ["Path_Remote"]
@@ -135,8 +137,8 @@ class PathWorkbench (Workbench):
if len(FreeCADGui.Selection.getSelection()) == 1:
if FreeCADGui.Selection.getSelection()[0].isDerivedFrom("Path::Feature"):
self.appendContextMenu("", ["Path_Inspect"])
if FreeCADGui.Selection.getSelection()[0].Name in ["Profile", "Contour"]:
self.appendContextMenu("", ["Add_Tag"])
if "Profile" or "Contour" in FreeCADGui.Selection.getSelection()[0].Name:
#self.appendContextMenu("", ["Add_Tag"])
self.appendContextMenu("", ["Set_StartPoint"])
self.appendContextMenu("", ["Set_EndPoint"])
if "Remote" in FreeCADGui.Selection.getSelection()[0].Name:

View File

@@ -36,6 +36,7 @@ if FreeCAD.GuiUp:
# Qt tanslation handling
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
@@ -51,66 +52,49 @@ __url__ = "http://www.freecadweb.org"
"""Path Contour object and FreeCAD command"""
class ObjectContour:
def __init__(self, obj):
obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyString", "Comment", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "An optional comment for this Contour"))
obj.addProperty("App::PropertyString", "UserLabel", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property","User Assigned Label"))
obj.addProperty("App::PropertyString", "UserLabel", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "User Assigned Label"))
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property","The tool number in use"))
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool number in use"))
obj.ToolNumber = (0, 0, 1000, 1)
obj.setEditorMode('ToolNumber', 1) # make this read only
obj.addProperty("App::PropertyString", "ToolDescription", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property","The description of the tool "))
obj.setEditorMode('ToolDescription', 1) # make this read only
obj.addProperty("App::PropertyString", "ToolDescription", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property", "The description of the tool "))
obj.setEditorMode('ToolDescription', 1) # make this read only
# Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Incremental Step Down of Tool"))
#obj.StepDown = (1, 0.01, 1000, 0.5)
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Rapid Safety Height between locations."))
obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Incremental Step Down of Tool"))
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Final Depth of Tool- lowest value in Z"))
# 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"))
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"))
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"))
obj.addProperty("App::PropertyEnumeration", "Direction", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
obj.Direction = ['CW', 'CCW'] # this is the direction that the Contour runs
obj.addProperty("App::PropertyBool", "UseComp", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property","make True, if using Cutter Radius Compensation"))
obj.addProperty("App::PropertyBool", "UseComp", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if using Cutter Radius Compensation"))
obj.addProperty("App::PropertyEnumeration", "Side", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "Side of edge that tool should cut"))
obj.Side = ['Left', 'Right', 'On'] # side of profile that cutter is on in relation to direction of profile
obj.setEditorMode('Side', 2) # hide
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.addProperty("App::PropertyLength", "SegLen", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property","Tesselation value for tool paths made from beziers, bsplines, and ellipses"))
obj.addProperty("App::PropertyAngle", "PlungeAngle", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property","Plunge angle with which the tool enters the work piece. Straight down is 90 degrees, if set small enough or zero the tool will descent exactly one layer depth down per turn"))
obj.addProperty("App::PropertyVectorList", "locs", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of holding tag locations"))
obj.addProperty("App::PropertyFloatList", "angles", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList", "heights", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList", "lengths", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of angles for the holding tags"))
locations = []
angles = []
lengths = []
heights = []
obj.locs = locations
obj.angles = angles
obj.lengths = lengths
obj.heights = heights
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
@@ -151,8 +135,8 @@ class ObjectContour:
def _buildPathLibarea(self, obj, edgelist):
import PathScripts.PathKurveUtils as PathKurveUtils
import math
import area
# import math
# import area
output = ""
if obj.Comment != "":
output += '(' + str(obj.Comment)+')\n'
@@ -188,14 +172,6 @@ class ObjectContour:
else:
obj.Side = 'Right'
PathKurveUtils.clear_tags()
for i in range(len(obj.locs)):
tag = obj.locs[i]
h = obj.heights[i]
l = obj.lengths[i]
a = math.radians(obj.angles[i])
PathKurveUtils.add_tag(area.Point(tag.x, tag.y), l, a, h)
depthparams = depth_params(
obj.ClearanceHeight.Value,
obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0,
@@ -251,7 +227,7 @@ class ObjectContour:
baseobject = parentJob.Base
if baseobject is None:
return
contourwire = TechDraw.findShapeOutline(baseobject.Shape,1, Vector(0,0,1))
contourwire = TechDraw.findShapeOutline(baseobject.Shape, 1, Vector(0, 0, 1))
edgelist = contourwire.Edges
edgelist = Part.__sortEdges__(edgelist)
@@ -298,45 +274,9 @@ class _ViewProviderContour:
return None
class _CommandAddTag:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Add Holding Tag"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Add Holding Tag")}
def IsActive(self):
return FreeCAD.ActiveDocument is not None
def setpoint(self, point, o):
obj = FreeCADGui.Selection.getSelection()[0]
obj.StartPoint.x = point.x
obj.StartPoint.y = point.y
loc = obj.locs
h = obj.heights
l = obj.lengths
a = obj.angles
x = point.x
y = point.y
z = float(0.0)
loc.append(Vector(x, y, z))
h.append(4.0)
l.append(5.0)
a.append(45.0)
obj.locs = loc
obj.heights = h
obj.lengths = l
obj.angles = a
def Activated(self):
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
class _CommandSetStartPoint:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
return {'Pixmap': 'Path-StartPoint',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick Start Point"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick Start Point")}
@@ -355,7 +295,7 @@ class _CommandSetStartPoint:
class _CommandSetEndPoint:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
return {'Pixmap': 'Path-EndPoint',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick End Point"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick End Point")}
@@ -407,7 +347,6 @@ class CommandPathContour:
FreeCADGui.doCommand('obj.OffsetExtra = 0.0')
FreeCADGui.doCommand('obj.Direction = "CW"')
FreeCADGui.doCommand('obj.UseComp = True')
FreeCADGui.doCommand('obj.PlungeAngle = 90.0')
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
FreeCADGui.doCommand('PathScripts.PathContour.ObjectContour.setDepths(obj.Proxy, obj)')
@@ -420,7 +359,7 @@ class CommandPathContour:
class TaskPanel:
def __init__(self):
self.form = FreeCADGui.PySideUic.loadUi(":/panels/ContourEdit.ui")
#self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/ContourEdit.ui")
# self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/ContourEdit.ui")
self.updating = False
def accept(self):
@@ -439,23 +378,19 @@ class TaskPanel:
def getFields(self):
if self.obj:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
self.obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value
if hasattr(self.obj, "StepDown"):
self.obj.StepDown = self.form.stepDown.text()
self.obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value
if hasattr(self.obj, "OffsetExtra"):
self.obj.OffsetExtra = self.form.extraOffset.text()
if hasattr(self.obj, "SegLen"):
self.obj.SegLen = self.form.segLen.value()
self.obj.OffsetExtra = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value
if hasattr(self.obj, "RollRadius"):
self.obj.RollRadius = self.form.rollRadius.text()
if hasattr(self.obj, "PlungeAngle"):
self.obj.PlungeAngle = str(self.form.plungeAngle.value())
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"):
@@ -467,15 +402,13 @@ class TaskPanel:
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.stepDown.setText(str(self.obj.StepDown.Value))
self.form.extraOffset.setText(str(self.obj.OffsetExtra.Value))
self.form.segLen.setValue(self.obj.SegLen.Value)
self.form.rollRadius.setText(str(self.obj.RollRadius.Value))
self.form.plungeAngle.setValue(self.obj.PlungeAngle.Value)
self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
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)
@@ -485,112 +418,14 @@ class TaskPanel:
if index >= 0:
self.form.direction.setCurrentIndex(index)
self.form.tagTree.blockSignals(True)
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(i+1))
l = self.obj.locs[i]
item.setText(1, str(l.x)+", " + str(l.y) + ", " + str(l.z))
item.setText(2, str(self.obj.heights[i]))
item.setText(3, str(self.obj.lengths[i]))
item.setText(4, str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0, QtCore.Qt.AlignLeft)
self.form.tagTree.blockSignals(False)
def open(self):
self.s = SelObserver()
# install the function mode resident
FreeCADGui.Selection.addObserver(self.s)
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok)
def edit(self, item, column):
if not self.updating:
self.resetObject()
def resetObject(self, remove=None):
"transfers the values from the widget to the object"
loc = []
h = []
l = []
a = []
for i in range(self.form.tagTree.topLevelItemCount()):
it = self.form.tagTree.findItems(
str(i+1), QtCore.Qt.MatchExactly, 0)[0]
if (remove is None) or (remove != i):
if it.text(1):
x = float(it.text(1).split()[0].rstrip(","))
y = float(it.text(1).split()[1].rstrip(","))
z = float(it.text(1).split()[2].rstrip(","))
loc.append(Vector(x, y, z))
else:
loc.append(0.0)
if it.text(2):
h.append(float(it.text(2)))
else:
h.append(4.0)
if it.text(3):
l.append(float(it.text(3)))
else:
l.append(5.0)
if it.text(4):
a.append(float(it.text(4)))
else:
a.append(45.0)
self.obj.locs = loc
self.obj.heights = h
self.obj.lengths = l
self.obj.angles = a
self.obj.touch()
FreeCAD.ActiveDocument.recompute()
def addElement(self):
self.updating = True
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(self.form.tagTree.topLevelItemCount()))
item.setText(1, "0.0, 0.0, 0.0")
item.setText(2, str(float(4.0)))
item.setText(3, str(float(10.0)))
item.setText(4, str(float(45.0)))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
self.updating = False
self.resetObject()
def removeElement(self):
it = self.form.tagTree.currentItem()
if it:
nr = int(it.text(0))-1
self.resetObject(remove=nr)
self.update()
def update(self):
'fills the treewidget'
self.updating = True
self.form.tagTree.clear()
if self.obj:
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(i+1))
l = self.obj.locs[i]
item.setText(1, str(l.x) + ", " + str(l.y) + ", " + str(l.z))
item.setText(2, str(self.obj.heights[i]))
item.setText(3, str(self.obj.lengths[i]))
item.setText(4, str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0, QtCore.Qt.AlignLeft)
self.updating = False
return
def setupUi(self):
# Connect Signals and Slots
@@ -609,17 +444,8 @@ class TaskPanel:
self.form.useStartPoint.clicked.connect(self.getFields)
self.form.useEndPoint.clicked.connect(self.getFields)
self.form.extraOffset.editingFinished.connect(self.getFields)
self.form.segLen.editingFinished.connect(self.getFields)
self.form.rollRadius.editingFinished.connect(self.getFields)
# Tag Form
QtCore.QObject.connect(
self.form.tagTree,
QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"),
self.edit)
self.form.addTag.clicked.connect(self.addElement)
self.form.deleteTag.clicked.connect(self.removeElement)
self.setFields()
@@ -640,7 +466,6 @@ class SelObserver:
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Contour', CommandPathContour())
FreeCADGui.addCommand('Add_Tag', _CommandAddTag())
FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint())
FreeCADGui.addCommand('Set_EndPoint', _CommandSetEndPoint())

View File

@@ -275,7 +275,7 @@ class Chord (object):
return dir == 'Back' or dir == side
def connectsTo(self, chord):
return PathGeom.isRoughly(self.End, chord.Start)
return PathGeom.pointsCoincide(self.End, chord.Start)
class Bone:
def __init__(self, boneId, obj, lastCommand, inChord, outChord, smooth):

File diff suppressed because it is too large Load Diff

View File

@@ -400,27 +400,27 @@ class TaskPanel:
def getFields(self):
if self.obj:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
self.obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
if hasattr(self.obj, "PeckDepth"):
self.obj.PeckDepth = self.form.peckDepth.text()
self.obj.PeckDepth = FreeCAD.Units.Quantity(self.form.peckDepth.text()).Value
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value
if hasattr(self.obj, "RetractHeight"):
self.obj.RetractHeight = self.form.retractHeight.text()
self.obj.RetractHeight = FreeCAD.Units.Quantity(self.form.retractHeight.text()).Value
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.peckDepth.setText(str(self.obj.PeckDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.retractHeight.setText(str(self.obj.RetractHeight.Value))
self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.peckDepth.setText(FreeCAD.Units.Quantity(self.obj.PeckDepth.Value, FreeCAD.Units.Length).UserString)
self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value, FreeCAD.Units.Length).UserString)
self.form.retractHeight.setText(FreeCAD.Units.Quantity(self.obj.RetractHeight.Value, FreeCAD.Units.Length).UserString)
self.form.baseList.clear()
for i in self.obj.Base:

View File

@@ -320,18 +320,18 @@ class TaskPanel:
def getFields(self):
if self.obj:
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value, FreeCAD.Units.Length).UserString)
self.form.baseList.clear()
for i in self.obj.Base:

View File

@@ -29,6 +29,8 @@ import Path
from FreeCAD import Vector
PathGeomTolerance = 0.000001
class Side:
"""Class to determine and define the side a Path is on, or Vectors are in relation to each other."""
Left = +1
@@ -63,39 +65,53 @@ class Side:
class PathGeom:
"""Class to transform Path Commands into Edges and Wire and back again.
The interface might eventuallly become part of Path itself."""
CmdMoveFast = ['G0', 'G00']
CmdMoveRapid = ['G0', 'G00']
CmdMoveStraight = ['G1', 'G01']
CmdMoveCW = ['G2', 'G02']
CmdMoveCCW = ['G3', 'G03']
CmdMoveArc = CmdMoveCW + CmdMoveCCW
CmdMove = CmdMoveStraight + CmdMoveArc
Tolerance = PathGeomTolerance
@classmethod
def isRoughly(cls, float1, float2, error=0.0000001):
"""(float1, float2, [error=0.0000001])
Returns true if the two values are the same within a given error."""
def isRoughly(cls, float1, float2, error=PathGeomTolerance):
"""(float1, float2, [error=%s])
Returns true if the two values are the same within a given error.""" % PathGeomTolerance
return math.fabs(float1 - float2) <= error
@classmethod
def pointsCoincide(cls, p1, p2, error=0.0000001):
"""(p1, p2, [error=0.0000001])
Return True if two points are roughly identical (see also isRoughly)."""
def pointsCoincide(cls, p1, p2, error=PathGeomTolerance):
"""(p1, p2, [error=%s])
Return True if two points are roughly identical (see also isRoughly).""" % PathGeomTolerance
return cls.isRoughly(p1.x, p2.x, error) and cls.isRoughly(p1.y, p2.y, error) and cls.isRoughly(p1.z, p2.z, error)
@classmethod
def edgeConnectsTo(cls, edge, vector):
"""(edge, vector)
Returns True if edge connects to given vector."""
def edgesMatch(cls, e0, e1, error=PathGeomTolerance):
"""(e0, e1, [error=%s]
Return true if the edges start and end at the same point and have the same type of curve.""" % PathGeomTolerance
if type(e0.Curve) != type(e1.Curve):
return False
if not cls.pointsCoincide(e0.valueAt(e0.FirstParameter), e1.valueAt(e1.FirstParameter)):
return False
if not cls.pointsCoincide(e0.valueAt(e0.LastParameter), e1.valueAt(e1.LastParameter)):
return False
return True
@classmethod
def edgeConnectsTo(cls, edge, vector, error=PathGeomTolerance):
"""(edge, vector, error=%f)
Returns True if edge connects to given vector.""" % PathGeomTolerance
return cls.pointsCoincide(edge.valueAt(edge.FirstParameter), vector) or cls.pointsCoincide(edge.valueAt(edge.LastParameter), vector)
@classmethod
def getAngle(cls, vertex):
"""(vertex)
Returns the angle [-pi,pi] of a vertex using the X-axis as the reference.
def getAngle(cls, vector):
"""(vector)
Returns the angle [-pi,pi] of a vector using the X-axis as the reference.
Positive angles for vertexes in the upper hemishpere (positive y values)
and negative angles for the lower hemishpere."""
a = vertex.getAngle(FreeCAD.Vector(1,0,0))
if vertex.y < 0:
a = vector.getAngle(Vector(1,0,0))
if vector.y < 0:
return -a
return a
@@ -120,7 +136,7 @@ class PathGeom:
x = cmd.Parameters.get(X, defaultPoint.x)
y = cmd.Parameters.get(Y, defaultPoint.y)
z = cmd.Parameters.get(Z, defaultPoint.z)
return FreeCAD.Vector(x, y, z)
return Vector(x, y, z)
@classmethod
def xy(cls, point):
@@ -128,13 +144,76 @@ class PathGeom:
Convenience function to return the projection of the Vector in the XY-plane."""
return Vector(point.x, point.y, 0)
@classmethod
def cmdsForEdge(cls, edge, flip = False, useHelixForBSpline = True, segm = 50):
"""(edge, flip=False, useHelixForBSpline=True, segm=50) -> List(Path.Command)
Returns a list of Path.Command representing the given edge.
If flip is True the edge is considered to be backwards.
If useHelixForBSpline is True an Edge based on a BSplineCurve is considered
to represent a helix and results in G2 or G3 command. Otherwise edge has
no direct Path.Command mapping and will be approximated by straight segments.
segm is a factor for the segmentation of arbitrary curves not mapped to G1/2/3
commands. The higher the value the more segments will be used."""
pt = edge.valueAt(edge.LastParameter) if not flip else edge.valueAt(edge.FirstParameter)
params = {'X': pt.x, 'Y': pt.y, 'Z': pt.z}
if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment:
commands = [Path.Command('G1', params)]
else:
if not flip:
p1 = edge.valueAt(edge.FirstParameter)
p3 = pt
else:
p1 = pt
p3 = edge.valueAt(edge.LastParameter)
p2 = edge.valueAt((edge.FirstParameter + edge.LastParameter)/2)
if (type(edge.Curve) == Part.Circle and cls.isRoughly(edge.Curve.Axis.x, 0) and cls.isRoughly(edge.Curve.Axis.y, 0)) or (useHelixForBSpline and type(edge.Curve) == Part.BSplineCurve):
if Side.Left == Side.of(p2 - p1, p3 - p2):
cmd = 'G3'
else:
cmd = 'G2'
#print("**** (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, p3.x, p3.y, p3.z))
pd = Part.Circle(PathGeom.xy(p1), PathGeom.xy(p2), PathGeom.xy(p3)).Center
pa = PathGeom.xy(p1)
pb = PathGeom.xy(p2)
pc = PathGeom.xy(p3)
#print("**** (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (pa.x, pa.y, pa.z, pc.x, pc.y, pc.z))
#print("**** (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (pb.x, pb.y, pb.z, pd.x, pd.y, pd.z))
offset = Part.Circle(PathGeom.xy(p1), PathGeom.xy(p2), PathGeom.xy(p3)).Center - p1
#print("**** (%.2f, %.2f, %.2f)" % (offset.x, offset.y, offset.z))
params.update({'I': offset.x, 'J': offset.y, 'K': (p3.z - p1.z)/2})
commands = [ Path.Command(cmd, params) ]
else:
eStraight = Part.Edge(Part.LineSegment(p1, p3))
esP2 = eStraight.valueAt((eStraight.FirstParameter + eStraight.LastParameter)/2)
deviation = (p2 - esP2).Length
if cls.isRoughly(deviation, 0):
return [ Path.Command('G1', {'X': p3.x, 'Y': p3.y, 'Z': p3.z}) ]
# at this point pixellation is all we can do
commands = []
segments = int(math.ceil((deviation / eStraight.Length) * segm))
#print("**** pixellation with %d segments" % segments)
dParameter = (edge.LastParameter - edge.FirstParameter) / segments
for i in range(0, segments):
if flip:
p = edge.valueAt(edge.LastParameter - (i + 1) * dParameter)
else:
p = edge.valueAt(edge.FirstParameter + (i + 1) * dParameter)
cmd = Path.Command('G1', {'X': p.x, 'Y': p.y, 'Z': p.z})
#print("***** %s" % cmd)
commands.append(cmd)
#print commands
return commands
@classmethod
def edgeForCmd(cls, cmd, startPoint):
"""(cmd, startPoint).
Returns an Edge representing the given command, assuming a given startPoint."""
endPoint = cls.commandEndPoint(cmd, startPoint)
if (cmd.Name in cls.CmdMoveStraight) or (cmd.Name in cls.CmdMoveFast):
if (cmd.Name in cls.CmdMoveStraight) or (cmd.Name in cls.CmdMoveRapid):
if cls.pointsCoincide(startPoint, endPoint):
return None
return Part.Edge(Part.LineSegment(startPoint, endPoint))
if cmd.Name in cls.CmdMoveArc:
@@ -157,7 +236,7 @@ class PathGeom:
#print("arc: A=(%.2f, %.2f) B=(%.2f, %.2f) -> d=%.2f" % (A.x, A.y, B.x, B.y, d))
#print("arc: R=%.2f angle=%.2f" % (R, angle/math.pi))
if startPoint.z == endPoint.z:
midPoint = center + FreeCAD.Vector(math.cos(angle), math.sin(angle), 0) * R
midPoint = center + Vector(math.cos(angle), math.sin(angle), 0) * R
return Part.Edge(Part.Arc(startPoint, midPoint, endPoint))
# It's a Helix
@@ -180,20 +259,23 @@ class PathGeom:
return None
@classmethod
def wireForPath(cls, path, startPoint = FreeCAD.Vector(0, 0, 0)):
def wireForPath(cls, path, startPoint = Vector(0, 0, 0)):
"""(path, [startPoint=Vector(0,0,0)])
Returns a wire representing all move commands found in the given path."""
edges = []
rapid = []
if hasattr(path, "Commands"):
for cmd in path.Commands:
edge = cls.edgeForCmd(cmd, startPoint)
if edge:
if cmd.Name in cls.CmdMoveRapid:
rapid.append(edge)
edges.append(edge)
startPoint = cls.commandEndPoint(cmd, startPoint)
return Part.Wire(edges)
return (Part.Wire(edges), rapid)
@classmethod
def wiresForPath(cls, path, startPoint = FreeCAD.Vector(0, 0, 0)):
def wiresForPath(cls, path, startPoint = Vector(0, 0, 0)):
"""(path, [startPoint=Vector(0,0,0)])
Returns a collection of wires, each representing a continuous cutting Path in path."""
wires = []
@@ -203,7 +285,7 @@ class PathGeom:
if cmd.Name in cls.CmdMove:
edges.append(cls.edgeForCmd(cmd, startPoint))
startPoint = cls.commandEndPoint(cmd, startPoint)
elif cmd.Name in cls.CmdMoveFast:
elif cmd.Name in cls.CmdMoveRapid:
wires.append(Part.Wire(edges))
edges = []
startPoint = cls.commandEndPoint(cmd, startPoint)
@@ -211,3 +293,81 @@ class PathGeom:
wires.append(Part.Wire(edges))
return wires
@classmethod
def arcToHelix(cls, edge, z0, z1):
"""(edge, z0, z1)
Assuming edge is an arc it'll return a helix matching the arc starting at z0 and rising/falling to z1."""
p1 = edge.valueAt(edge.FirstParameter)
p2 = edge.valueAt(edge.LastParameter)
cmd = cls.cmdsForEdge(edge)[0]
params = cmd.Parameters
params.update({'Z': z1, 'K': (z1 - z0)/2})
command = Path.Command(cmd.Name, params)
#print("- (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f): %.2f:%.2f" % (edge.Vertexes[0].X, edge.Vertexes[0].Y, edge.Vertexes[0].Z, edge.Vertexes[1].X, edge.Vertexes[1].Y, edge.Vertexes[1].Z, z0, z1))
#print("- %s -> %s" % (cmd, command))
return cls.edgeForCmd(command, Vector(p1.x, p1.y, z0))
@classmethod
def helixToArc(cls, edge, z = 0):
"""(edge, z=0)
Returns the projection of the helix onto the XY-plane with a given offset."""
p1 = edge.valueAt(edge.FirstParameter)
p2 = edge.valueAt((edge.FirstParameter + edge.LastParameter)/2)
p3 = edge.valueAt(edge.LastParameter)
p01 = Vector(p1.x, p1.y, z)
p02 = Vector(p2.x, p2.y, z)
p03 = Vector(p3.x, p3.y, z)
return Part.Edge(Part.Arc(p01, p02, p03))
@classmethod
def splitArcAt(cls, edge, pt):
"""(edge, pt)
Returns a list of 2 edges which together form the original arc split at the given point.
The Vector pt has to represnt a point on the given arc."""
p1 = edge.valueAt(edge.FirstParameter)
p2 = pt
p3 = edge.valueAt(edge.LastParameter)
edges = []
p = edge.Curve.parameter(p2)
#print("splitArcAt(%.2f, %.2f, %.2f): %.2f - %.2f - %.2f" % (pt.x, pt.y, pt.z, edge.FirstParameter, p, edge.LastParameter))
p12 = edge.Curve.value((edge.FirstParameter + p)/2)
p23 = edge.Curve.value((p + edge.LastParameter)/2)
#print("splitArcAt: p12=(%.2f, %.2f, %.2f) p23=(%.2f, %.2f, %.2f)" % (p12.x, p12.y, p12.z, p23.x, p23.y, p23.z))
edges.append(Part.Edge(Part.Arc(p1, p12, p2)))
edges.append(Part.Edge(Part.Arc(p2, p23, p3)))
return edges
@classmethod
def splitEdgeAt(cls, edge, pt):
"""(edge, pt)
Returns a list of 2 edges, forming the original edge split at the given point.
The results are undefined if the Vector representing the point is not part of the edge."""
# I could not get the OCC parameterAt and split to work ...
# pt HAS to be on the edge, otherwise the results are undefined
p1 = edge.valueAt(edge.FirstParameter)
p2 = pt
p3 = edge.valueAt(edge.LastParameter)
edges = []
if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment:
# it's a line
return [Part.Edge(Part.LineSegment(p1, p2)), Part.Edge(Part.LineSegment(p2, p3))]
elif type(edge.Curve) == Part.Circle:
# it's an arc
return cls.splitArcAt(edge, pt)
else:
# it's a helix
arc = cls.helixToArc(edge, 0)
aes = cls.splitArcAt(arc, Vector(pt.x, pt.y, 0))
return [cls.arcToHelix(aes[0], p1.z, p2.z), cls.arcToHelix(aes[1], p2.z, p3.z)]

View File

@@ -420,19 +420,20 @@ class TaskPanel:
def getFields(self):
if self.obj:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
self.obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
if hasattr(self.obj, "FinishDepth"):
self.obj.FinishDepth = self.form.finishDepth.text()
self.obj.FinishDepth = FreeCAD.Units.Quantity(self.form.finishDepth.text()).Value
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value
if hasattr(self.obj, "StepDown"):
self.obj.StepDown = self.form.stepDown.value()
self.obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value
if hasattr(self.obj, "PassExtension"):
self.obj.PassExtension = self.form.extraOffset.value()
self.obj.PassExtension = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value
# if hasattr(self.obj, "UseStartPoint"):
# self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
if hasattr(self.obj, "CutMode"):
@@ -442,7 +443,9 @@ class TaskPanel:
if hasattr(self.obj, "ZigUnidirectional"):
self.obj.ZigUnidirectional = self.form.zigZagUnidirectional.isChecked()
if hasattr(self.obj, "ZigZagAngle"):
self.obj.ZigZagAngle = self.form.zigZagAngle.value()
self.obj.ZigZagAngle = FreeCAD.Units.Quantity(self.form.zigZagAngle.text()).Value
# if hasattr(self.obj, "ZigZagAngle"):
# self.obj.ZigZagAngle = self.form.zigZagAngle.value()
if hasattr(self.obj, "StepOver"):
self.obj.StepOver = self.form.stepOverPercent.value()
if hasattr(self.obj, "BoundaryShape"):
@@ -451,16 +454,18 @@ class TaskPanel:
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.finishDepth.setText(str(self.obj.FinishDepth.Value))
self.form.stepDown.setValue(self.obj.StepDown)
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finishDepth.setText(FreeCAD.Units.Quantity(self.obj.FinishDepth.Value, FreeCAD.Units.Length).UserString)
self.form.stepDown.setText(FreeCAD.Units.Quantity(self.obj.StepDown, FreeCAD.Units.Length).UserString)
self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
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(self.obj.ZigZagAngle)
self.form.zigZagAngle.setValue(FreeCAD.Units.Quantity(self.obj.ZigZagAngle, FreeCAD.Units.Angle))
# self.form.zigZagAngle.setValue(self.obj.ZigZagAngle)
#self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
self.form.extraOffset.setValue(self.obj.PassExtension.Value)

View File

@@ -338,7 +338,7 @@ class ObjectPocket:
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 += " I" + fmt(relcenter.x) + " J" + fmt(relcenter.y) + " K" + fmt(relcenter.z) + " F" + fmt(self.horizFeed)
output += "\n"
last = point
else:
@@ -545,17 +545,17 @@ class TaskPanel:
def getFields(self):
if self.obj:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
self.obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value
if hasattr(self.obj, "StepDown"):
self.obj.StepDown = self.form.stepDown.text()
self.obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value
if hasattr(self.obj, "MaterialAllowance"):
self.obj.MaterialAllowance = self.form.extraOffset.text()
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"):
@@ -567,23 +567,23 @@ class TaskPanel:
if hasattr(self.obj, "ZigUnidirectional"):
self.obj.ZigUnidirectional = self.form.zigZagUnidirectional.isChecked()
if hasattr(self.obj, "ZigZagAngle"):
self.obj.ZigZagAngle = self.form.zigZagAngle.value()
self.obj.ZigZagAngle = FreeCAD.Units.Quantity(self.form.zigZagAngle.text()).Value
if hasattr(self.obj, "StepOver"):
self.obj.StepOver = self.form.stepOverPercent.value()
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.stepDown.setText(str(self.obj.StepDown))
self.form.extraOffset.setText(str(self.obj.MaterialAllowance.Value))
self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
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.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.setValue(self.obj.ZigZagAngle)
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)

View File

@@ -31,6 +31,10 @@ class PathPreferences:
PostProcessorDefaultArgs = "PostProcessorDefaultArgs"
PostProcessorBlacklist = "PostProcessorBlacklist"
@classmethod
def preferences(cls):
return FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
@classmethod
def allAvailablePostProcessors(cls):
path = FreeCAD.getHomePath() + ("Mod/Path/PathScripts/")
@@ -58,28 +62,28 @@ class PathPreferences:
@classmethod
def defaultPostProcessor(cls):
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
return preferences.GetString(cls.PostProcessorDefault, "")
pref = cls.preferences()
return pref.GetString(cls.PostProcessorDefault, "")
@classmethod
def defaultPostProcessorArgs(cls):
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
return preferences.GetString(cls.PostProcessorDefaultArgs, "")
pref = cls.preferences()
return pref.GetString(cls.PostProcessorDefaultArgs, "")
@classmethod
def postProcessorBlacklist(cls):
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
blacklist = preferences.GetString(cls.PostProcessorBlacklist, "")
pref = cls.preferences()
blacklist = pref.GetString(cls.PostProcessorBlacklist, "")
if not blacklist:
return []
return eval(blacklist)
@classmethod
def savePostProcessorDefaults(cls, processor, args, blacklist):
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
preferences.SetString(cls.PostProcessorDefault, processor)
preferences.SetString(cls.PostProcessorDefaultArgs, args)
preferences.SetString(cls.PostProcessorBlacklist, "%s" % (blacklist))
pref = cls.preferences()
pref.SetString(cls.PostProcessorDefault, processor)
pref.SetString(cls.PostProcessorDefaultArgs, args)
pref.SetString(cls.PostProcessorBlacklist, "%s" % (blacklist))
DefaultOutputFile = "DefaultOutputFile"
@@ -87,16 +91,16 @@ class PathPreferences:
@classmethod
def saveOutputFileDefaults(cls, file, policy):
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
preferences.SetString(cls.DefaultOutputFile, file)
preferences.SetString(cls.DefaultOutputPolicy, policy)
pref = cls.preferences()
pref.SetString(cls.DefaultOutputFile, file)
pref.SetString(cls.DefaultOutputPolicy, policy)
@classmethod
def defaultOutputFile(cls):
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
return preferences.GetString(cls.DefaultOutputFile, "")
pref = cls.preferences()
return pref.GetString(cls.DefaultOutputFile, "")
@classmethod
def defaultOutputPolicy(cls):
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
return preferences.GetString(cls.DefaultOutputPolicy, "")
pref = cls.preferences()
return pref.GetString(cls.DefaultOutputPolicy, "")

View File

@@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * *
# * Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
import FreeCAD
import FreeCADGui
from PySide import QtCore, QtGui
from PathScripts.PathPreferences import PathPreferences
# Qt tanslation handling
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig)
_dressups = []
def RegisterDressup(dressup):
_dressups.append(dressup)
class DressupPreferencesPage:
def __init__(self, parent=None):
self.form = QtGui.QToolBox()
self.form.setWindowTitle(translate('PathPreferencesPathDressup', 'Dressups'))
pages = []
for dressup in _dressups:
page = dressup.preferencesPage()
if hasattr(page, 'icon') and page.icon:
self.form.addItem(page.form, page.icon, page.label)
else:
self.form.addItem(page.form, page.label)
pages.append(page)
self.pages = pages
def saveSettings(self):
for page in self.pages:
page.saveSettings()
def loadSettings(self):
for page in self.pages:
page.loadSettings()

View File

@@ -29,7 +29,7 @@ from PathScripts.PathPreferences import PathPreferences
from PathScripts.PathPostProcessor import PostProcessor
class Page:
class JobPreferencesPage:
def __init__(self, parent=None):
self.form = FreeCADGui.PySideUic.loadUi(":preferences/PathJob.ui")

View File

@@ -36,6 +36,7 @@ if FreeCAD.GuiUp:
# Qt tanslation handling
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
@@ -51,68 +52,51 @@ __url__ = "http://www.freecadweb.org"
"""Path Profile object and FreeCAD command"""
class ObjectProfile:
def __init__(self, obj):
obj.addProperty("App::PropertyLinkSubList", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property","The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property","Make False, to prevent operation from generating code"))
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::PropertyLinkSubList", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Make False, to prevent operation from generating code"))
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::PropertyIntegerConstraint", "ToolNumber", "Tool", "The tool number in use")
obj.ToolNumber = (0, 0, 1000, 1)
obj.setEditorMode('ToolNumber', 1) # make this read only
obj.addProperty("App::PropertyString", "ToolDescription", "Tool", "The description of the tool ")
obj.setEditorMode('ToolDescription', 1) # make this read only
obj.setEditorMode('ToolDescription', 1) # make this read only
# Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Incremental Step Down of Tool"))
#obj.StepDown = (1, 0.01, 1000, 0.5)
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Rapid Safety Height between locations."))
obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Incremental Step Down of Tool"))
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Final Depth of Tool- lowest value in Z"))
# 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"))
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"))
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.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.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.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::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::PropertyLength", "SegLen", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property","Tesselation value for tool paths made from beziers, bsplines, and ellipses"))
obj.addProperty("App::PropertyAngle", "PlungeAngle", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property","Plunge angle with which the tool enters the work piece. Straight down is 90 degrees, if set small enough or zero the tool will descent exactly one layer depth down per turn"))
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"))
obj.addProperty("App::PropertyVectorList", "locs", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of holding tag locations"))
obj.addProperty("App::PropertyFloatList", "angles", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList", "heights", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList", "lengths", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of angles for the holding tags"))
locations = []
angles = []
lengths = []
heights = []
obj.locs = locations
obj.angles = angles
obj.lengths = lengths
obj.heights = heights
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"))
obj.Proxy = self
@@ -145,7 +129,7 @@ class ObjectProfile:
obj.FinalDepth = fbb.ZMin
elif fbb.ZMax == fbb.ZMin and fbb.ZMax > bb.ZMin: # face/shelf
obj.FinalDepth = fbb.ZMin
else: #catch all
else: # catch all
obj.FinalDepth = bb.ZMin
except:
obj.StartDepth = 5.0
@@ -167,8 +151,8 @@ class ObjectProfile:
def _buildPathLibarea(self, obj, edgelist, isHole):
import PathScripts.PathKurveUtils as PathKurveUtils
import math
import area
# import math
# import area
output = ""
if obj.Comment != "":
output += '(' + str(obj.Comment)+')\n'
@@ -220,14 +204,6 @@ print "y - " + str(point.y)
I need to access the location vector, length, angle in radians and height.
'''
PathKurveUtils.clear_tags()
for i in range(len(obj.locs)):
tag = obj.locs[i]
h = obj.heights[i]
l = obj.lengths[i]
a = math.radians(obj.angles[i])
PathKurveUtils.add_tag(area.Point(tag.x, tag.y), l, a, h)
depthparams = depth_params(
obj.ClearanceHeight.Value,
obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0,
@@ -286,7 +262,7 @@ print "y - " + str(point.y)
for b in obj.Base:
for sub in b[1]:
shape = getattr(b[0].Shape, sub)
if isinstance (shape, Part.Face):
if isinstance(shape, Part.Face):
faces.append(shape)
if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face
holes += shape.Wires[1:]
@@ -295,7 +271,7 @@ print "y - " + str(point.y)
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))
profilewire = TechDraw.findShapeOutline(profileshape, 1, Vector(0, 0, 1))
if obj.processHoles:
for wire in holes:
@@ -346,45 +322,9 @@ class _ViewProviderProfile:
return None
class _CommandAddTag:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Add Holding Tag"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Add Holding Tag")}
def IsActive(self):
return FreeCAD.ActiveDocument is not None
def setpoint(self, point, o):
obj = FreeCADGui.Selection.getSelection()[0]
obj.StartPoint.x = point.x
obj.StartPoint.y = point.y
loc = obj.locs
h = obj.heights
l = obj.lengths
a = obj.angles
x = point.x
y = point.y
z = float(0.0)
loc.append(Vector(x, y, z))
h.append(4.0)
l.append(5.0)
a.append(45.0)
obj.locs = loc
obj.heights = h
obj.lengths = l
obj.angles = a
def Activated(self):
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
class _CommandSetStartPoint:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
return {'Pixmap': 'Path-StartPoint',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick Start Point"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick Start Point")}
@@ -403,7 +343,7 @@ class _CommandSetStartPoint:
class _CommandSetEndPoint:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
return {'Pixmap': 'Path-EndPoint',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick End Point"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick End Point")}
@@ -457,7 +397,6 @@ class CommandPathProfile:
FreeCADGui.doCommand('obj.UseComp = False')
FreeCADGui.doCommand('obj.processHoles = False')
FreeCADGui.doCommand('obj.processPerimeter = True')
FreeCADGui.doCommand('obj.PlungeAngle = 90.0')
FreeCADGui.doCommand('PathScripts.PathProfile._ViewProviderProfile(obj.ViewObject)')
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
@@ -486,24 +425,21 @@ class TaskPanel:
def getFields(self):
if self.obj:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
self.obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value
if hasattr(self.obj, "StepDown"):
self.obj.StepDown = self.form.stepDown.text()
self.obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value
if hasattr(self.obj, "OffsetExtra"):
self.obj.OffsetExtra = self.form.extraOffset.text()
if hasattr(self.obj, "SegLen"):
self.obj.SegLen = self.form.segLen.value()
self.obj.OffsetExtra = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value
if hasattr(self.obj, "RollRadius"):
self.obj.RollRadius = self.form.rollRadius.text()
if hasattr(self.obj, "PlungeAngle"):
self.obj.PlungeAngle = str(self.form.plungeAngle.value())
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"):
@@ -521,15 +457,13 @@ class TaskPanel:
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.stepDown.setText(str(self.obj.StepDown))
self.form.extraOffset.setText(str(self.obj.OffsetExtra.Value))
self.form.segLen.setValue(self.obj.SegLen.Value)
self.form.rollRadius.setText(str(self.obj.RollRadius.Value))
self.form.plungeAngle.setValue(self.obj.PlungeAngle.Value)
self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
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)
@@ -556,21 +490,8 @@ class TaskPanel:
self.form.baseList.addItem(i[0].Name + "." + sub)
self.form.baseList.blockSignals(False)
self.form.tagTree.blockSignals(True)
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(i+1))
l = self.obj.locs[i]
item.setText(1, str(l.x)+", " + str(l.y) + ", " + str(l.z))
item.setText(2, str(self.obj.heights[i]))
item.setText(3, str(self.obj.lengths[i]))
item.setText(4, str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0, QtCore.Qt.AlignLeft)
self.form.tagTree.blockSignals(False)
self.form.update()
def open(self):
self.s = SelObserver()
# install the function mode resident
@@ -601,7 +522,6 @@ class TaskPanel:
for sub in i[1]:
self.form.baseList.addItem(i[0].Name + "." + sub)
def deleteBase(self):
dlist = self.form.baseList.selectedItems()
newlist = []
@@ -644,90 +564,6 @@ class TaskPanel:
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok)
def edit(self, item, column):
if not self.updating:
self.resetObject()
def resetObject(self, remove=None):
"transfers the values from the widget to the object"
loc = []
h = []
l = []
a = []
for i in range(self.form.tagTree.topLevelItemCount()):
it = self.form.tagTree.findItems(
str(i+1), QtCore.Qt.MatchExactly, 0)[0]
if (remove is None) or (remove != i):
if it.text(1):
x = float(it.text(1).split()[0].rstrip(","))
y = float(it.text(1).split()[1].rstrip(","))
z = float(it.text(1).split()[2].rstrip(","))
loc.append(Vector(x, y, z))
else:
loc.append(0.0)
if it.text(2):
h.append(float(it.text(2)))
else:
h.append(4.0)
if it.text(3):
l.append(float(it.text(3)))
else:
l.append(5.0)
if it.text(4):
a.append(float(it.text(4)))
else:
a.append(45.0)
self.obj.locs = loc
self.obj.heights = h
self.obj.lengths = l
self.obj.angles = a
self.obj.touch()
FreeCAD.ActiveDocument.recompute()
def addElement(self):
self.updating = True
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(self.form.tagTree.topLevelItemCount()))
item.setText(1, "0.0, 0.0, 0.0")
item.setText(2, str(float(4.0)))
item.setText(3, str(float(10.0)))
item.setText(4, str(float(45.0)))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
self.updating = False
self.resetObject()
def removeElement(self):
it = self.form.tagTree.currentItem()
if it:
nr = int(it.text(0))-1
self.resetObject(remove=nr)
self.update()
def update(self):
'fills the treewidget'
self.updating = True
self.form.tagTree.clear()
if self.obj:
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(i+1))
l = self.obj.locs[i]
item.setText(1, str(l.x) + ", " + str(l.y) + ", " + str(l.z))
item.setText(2, str(self.obj.heights[i]))
item.setText(3, str(self.obj.lengths[i]))
item.setText(4, str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0, QtCore.Qt.AlignLeft)
self.updating = False
return
def setupUi(self):
# Connect Signals and Slots
@@ -753,19 +589,10 @@ class TaskPanel:
self.form.useStartPoint.clicked.connect(self.getFields)
self.form.useEndPoint.clicked.connect(self.getFields)
self.form.extraOffset.editingFinished.connect(self.getFields)
self.form.segLen.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)
# Tag Form
QtCore.QObject.connect(
self.form.tagTree,
QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"),
self.edit)
self.form.addTag.clicked.connect(self.addElement)
self.form.deleteTag.clicked.connect(self.removeElement)
self.setFields()
sel = FreeCADGui.Selection.getSelectionEx()
@@ -790,7 +617,6 @@ class SelObserver:
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Profile', CommandPathProfile())
FreeCADGui.addCommand('Add_Tag', _CommandAddTag())
FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint())
FreeCADGui.addCommand('Set_EndPoint', _CommandSetEndPoint())

View File

@@ -24,7 +24,6 @@
import FreeCAD
import Path
from FreeCAD import Vector
from PathScripts import PathUtils
from PathScripts.PathUtils import depth_params
from DraftGeomUtils import findWires
@@ -50,70 +49,49 @@ __url__ = "http://www.freecadweb.org"
"""Path Profile object and FreeCAD command for operating on sets of edges"""
class ObjectProfile:
def __init__(self, obj):
obj.addProperty("App::PropertyLinkSubList", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property","The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property","Make False, to prevent operation from generating code"))
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::PropertyLinkSubList", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Make False, to prevent operation from generating code"))
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", "The library or algorithm used to generate the path")
# obj.Algorithm = ['OCC Native', 'libarea']
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property","The tool number in use"))
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool number in use"))
obj.ToolNumber = (0, 0, 1000, 1)
obj.setEditorMode('ToolNumber', 1) # make this read only
obj.addProperty("App::PropertyString", "ToolDescription", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property","The description of the tool"))
obj.setEditorMode('ToolDescription', 1) # make this read onlyt
obj.addProperty("App::PropertyString", "ToolDescription", "Tool", QtCore.QT_TRANSLATE_NOOP("App::Property", "The description of the tool"))
obj.setEditorMode('ToolDescription', 1) # make this read onlyt
# Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Rapid Safety Height between locations"))
obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Incremental Step Down of Tool"))
#obj.StepDown = (1, 0.01, 1000, 0.5)
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Rapid Safety Height between locations"))
obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Incremental Step Down of Tool"))
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Final Depth of Tool- lowest value in Z"))
# 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"))
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"))
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.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.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.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::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::PropertyLength", "SegLen", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property","Tesselation value for tool paths made from beziers, bsplines, and ellipses"))
obj.addProperty("App::PropertyAngle", "PlungeAngle", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property","Plunge angle with which the tool enters the work piece. Straight down is 90 degrees, if set small enough or zero the tool will descent exactly one layer depth down per turn"))
obj.addProperty("App::PropertyVectorList", "locs", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of holding tag locations"))
obj.addProperty("App::PropertyFloatList", "angles", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList", "heights", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList", "lengths", "Tags", QtCore.QT_TRANSLATE_NOOP("App::Property","List of angles for the holding tags"))
locations = []
angles = []
lengths = []
heights = []
obj.locs = locations
obj.angles = angles
obj.lengths = lengths
obj.heights = heights
#obj.ToolDescription = "UNDEFINED"
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
@@ -146,18 +124,13 @@ class ObjectProfile:
obj.FinalDepth = fbb.ZMin
elif fbb.ZMax == fbb.ZMin and fbb.ZMax > bb.ZMin: # face/shelf
obj.FinalDepth = fbb.ZMin
else: #catch all
else: # catch all
obj.FinalDepth = bb.ZMin
except:
obj.StartDepth = 5.0
obj.ClearanceHeight = 10.0
obj.SafeHeight = 8.0
# if bb.XLength == fbb.XLength and bb.YLength == fbb.YLength:
# obj.Side = "Left"
# else:
# obj.Side = "Right"
item = (ss, sub)
if item in baselist:
FreeCAD.Console.PrintWarning("this object already in the list" + "\n")
@@ -168,8 +141,8 @@ class ObjectProfile:
def _buildPathLibarea(self, obj, edgelist):
import PathScripts.PathKurveUtils as PathKurveUtils
import math
import area
# import math
# import area
output = ""
if obj.Comment != "":
output += '(' + str(obj.Comment)+')\n'
@@ -216,14 +189,6 @@ print "y - " + str(point.y)
I need to access the location vector, length, angle in radians and height.
'''
PathKurveUtils.clear_tags()
for i in range(len(obj.locs)):
tag = obj.locs[i]
h = obj.heights[i]
l = obj.lengths[i]
a = math.radians(obj.angles[i])
PathKurveUtils.add_tag(area.Point(tag.x, tag.y), l, a, h)
depthparams = depth_params(
obj.ClearanceHeight.Value,
obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0,
@@ -243,8 +208,6 @@ print "y - " + str(point.y)
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
# obj.ToolController = PathUtils.getToolControllers(obj)
# toolLoad = PathUtils.getToolLoad(obj, obj.ToolController)
if toolLoad is None or toolLoad.ToolNumber == 0:
self.vertFeed = 100
@@ -279,8 +242,6 @@ print "y - " + str(point.y)
output += "(Uncompensated Tool Path)"
if obj.Base:
# hfaces = []
# vfaces = []
wires = []
for b in obj.Base:
@@ -332,45 +293,9 @@ class _ViewProviderProfile:
return None
class _CommandAddTag:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Add Holding Tag"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Add Holding Tag")}
def IsActive(self):
return FreeCAD.ActiveDocument is not None
def setpoint(self, point, o):
obj = FreeCADGui.Selection.getSelection()[0]
obj.StartPoint.x = point.x
obj.StartPoint.y = point.y
loc = obj.locs
h = obj.heights
l = obj.lengths
a = obj.angles
x = point.x
y = point.y
z = float(0.0)
loc.append(Vector(x, y, z))
h.append(4.0)
l.append(5.0)
a.append(45.0)
obj.locs = loc
obj.heights = h
obj.lengths = l
obj.angles = a
def Activated(self):
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
class _CommandSetStartPoint:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
return {'Pixmap': 'Path-StartPoint',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick Start Point"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick Start Point")}
@@ -389,7 +314,7 @@ class _CommandSetStartPoint:
class _CommandSetEndPoint:
def GetResources(self):
return {'Pixmap': 'Path-Holding',
return {'Pixmap': 'Path-EndPoint',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick End Point"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile", "Pick End Point")}
@@ -442,8 +367,6 @@ class CommandPathProfileEdges:
FreeCADGui.doCommand('obj.OffsetExtra = 0.0')
FreeCADGui.doCommand('obj.Direction = "CW"')
FreeCADGui.doCommand('obj.UseComp = False')
FreeCADGui.doCommand('obj.PlungeAngle = 90.0')
#FreeCADGui.doCommand('obj.ActiveTC = None')
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
FreeCAD.ActiveDocument.commitTransaction()
@@ -454,7 +377,7 @@ class CommandPathProfileEdges:
class TaskPanel:
def __init__(self):
self.form = FreeCADGui.PySideUic.loadUi(":/panels/ProfileEdgesEdit.ui")
#self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/ProfileEdgesEdit.ui")
# self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/ProfileEdgesEdit.ui")
self.updating = False
@@ -473,32 +396,27 @@ class TaskPanel:
def getFields(self):
if self.obj:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
self.obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value
if hasattr(self.obj, "StepDown"):
self.obj.StepDown = self.form.stepDown.text()
self.obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value
if hasattr(self.obj, "OffsetExtra"):
self.obj.OffsetExtra = self.form.extraOffset.text()
if hasattr(self.obj, "SegLen"):
self.obj.SegLen = self.form.segLen.value()
self.obj.OffsetExtra = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value
if hasattr(self.obj, "RollRadius"):
self.obj.RollRadius = self.form.rollRadius.text()
if hasattr(self.obj, "PlungeAngle"):
self.obj.PlungeAngle = str(self.form.plungeAngle.value())
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, "Algorithm"):
# self.obj.Algorithm = str(self.form.algorithmSelect.currentText())
if hasattr(self.obj, "Side"):
self.obj.Side = str(self.form.cutSide.currentText())
if hasattr(self.obj, "Direction"):
@@ -506,15 +424,13 @@ class TaskPanel:
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.stepDown.setText(str(self.obj.StepDown.Value))
self.form.extraOffset.setText(str(self.obj.OffsetExtra.Value))
self.form.segLen.setValue(self.obj.SegLen.Value)
self.form.rollRadius.setText(str(self.obj.RollRadius.Value))
self.form.plungeAngle.setValue(self.obj.PlungeAngle.Value)
self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
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)
@@ -534,20 +450,6 @@ class TaskPanel:
self.form.baseList.addItem(i[0].Name + "." + sub)
self.form.baseList.blockSignals(False)
self.form.tagTree.blockSignals(True)
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(i+1))
l = self.obj.locs[i]
item.setText(1, str(l.x)+", " + str(l.y) + ", " + str(l.z))
item.setText(2, str(self.obj.heights[i]))
item.setText(3, str(self.obj.lengths[i]))
item.setText(4, str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0, QtCore.Qt.AlignLeft)
self.form.tagTree.blockSignals(False)
def open(self):
self.s = SelObserver()
# install the function mode resident
@@ -620,90 +522,6 @@ class TaskPanel:
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok)
def edit(self, item, column):
if not self.updating:
self.resetObject()
def resetObject(self, remove=None):
"transfers the values from the widget to the object"
loc = []
h = []
l = []
a = []
for i in range(self.form.tagTree.topLevelItemCount()):
it = self.form.tagTree.findItems(
str(i+1), QtCore.Qt.MatchExactly, 0)[0]
if (remove is None) or (remove != i):
if it.text(1):
x = float(it.text(1).split()[0].rstrip(","))
y = float(it.text(1).split()[1].rstrip(","))
z = float(it.text(1).split()[2].rstrip(","))
loc.append(Vector(x, y, z))
else:
loc.append(0.0)
if it.text(2):
h.append(float(it.text(2)))
else:
h.append(4.0)
if it.text(3):
l.append(float(it.text(3)))
else:
l.append(5.0)
if it.text(4):
a.append(float(it.text(4)))
else:
a.append(45.0)
self.obj.locs = loc
self.obj.heights = h
self.obj.lengths = l
self.obj.angles = a
self.obj.touch()
FreeCAD.ActiveDocument.recompute()
def addElement(self):
self.updating = True
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(self.form.tagTree.topLevelItemCount()))
item.setText(1, "0.0, 0.0, 0.0")
item.setText(2, str(float(4.0)))
item.setText(3, str(float(10.0)))
item.setText(4, str(float(45.0)))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
self.updating = False
self.resetObject()
def removeElement(self):
it = self.form.tagTree.currentItem()
if it:
nr = int(it.text(0))-1
self.resetObject(remove=nr)
self.update()
def update(self):
'fills the treewidget'
self.updating = True
self.form.tagTree.clear()
if self.obj:
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0, str(i+1))
l = self.obj.locs[i]
item.setText(1, str(l.x) + ", " + str(l.y) + ", " + str(l.z))
item.setText(2, str(self.obj.heights[i]))
item.setText(3, str(self.obj.lengths[i]))
item.setText(4, str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0, QtCore.Qt.AlignLeft)
self.updating = False
return
def setupUi(self):
# Connect Signals and Slots
@@ -729,17 +547,7 @@ class TaskPanel:
self.form.useStartPoint.clicked.connect(self.getFields)
self.form.useEndPoint.clicked.connect(self.getFields)
self.form.extraOffset.editingFinished.connect(self.getFields)
self.form.segLen.editingFinished.connect(self.getFields)
self.form.rollRadius.editingFinished.connect(self.getFields)
# Tag Form
QtCore.QObject.connect(
self.form.tagTree,
QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"),
self.edit)
self.form.addTag.clicked.connect(self.addElement)
self.form.deleteTag.clicked.connect(self.removeElement)
self.setFields()
sel = FreeCADGui.Selection.getSelectionEx()
@@ -764,8 +572,7 @@ class SelObserver:
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Profile_Edges', CommandPathProfileEdges())
# FreeCADGui.addCommand('Add_Tag', _CommandAddTag())
# FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint())
# FreeCADGui.addCommand('Set_EndPoint', _CommandSetEndPoint())
FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint())
FreeCADGui.addCommand('Set_EndPoint', _CommandSetEndPoint())
FreeCAD.Console.PrintLog("Loading PathProfileEdges... done\n")

View File

@@ -442,19 +442,19 @@ class TaskPanel:
def getFields(self):
if self.obj:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = self.form.startDepth.text()
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = self.form.finalDepth.text()
if hasattr(self.obj, "FinishDepth"):
self.obj.FinishDepth = self.form.finishDepth.text()
if hasattr(self.obj, "StepDown"):
self.obj.StepDown = self.form.stepDown.value()
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
if hasattr(self.obj, "FinishDepth"):
self.obj.FinishDepth = FreeCAD.Units.Quantity(self.form.finishDepth.text()).Value
if hasattr(self.obj, "StepDown"):
self.obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value
if hasattr(self.obj, "Algorithm"):
self.obj.Algorithm = str(
self.form.algorithmSelect.currentText())
@@ -462,13 +462,12 @@ class TaskPanel:
self.obj.Proxy.execute(self.obj)
def setFields(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.finishDepth.setText(str(self.obj.FinishDepth.Value))
self.form.stepDown.setValue(self.obj.StepDown)
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finishDepth.setText(FreeCAD.Units.Quantity(self.obj.FinishDepth.Value, FreeCAD.Units.Length).UserString)
self.form.stepDown.setText(FreeCAD.Units.Quantity(self.obj.StepDown, FreeCAD.Units.Length).UserString)
self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value, FreeCAD.Units.Length).UserString)
for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name)

View File

@@ -35,6 +35,7 @@ from DraftGeomUtils import geomType
import PathScripts
from PathScripts import PathJob
# import itertools
import numpy
def cleanedges(splines, precision):
'''cleanedges([splines],precision). Convert BSpline curves, Beziers, to arcs that can be used for cnc paths.
@@ -840,27 +841,53 @@ class depth_params:
'''returns a list of depths to be used in order from first to last.
equalstep=True: all steps down before the finish pass will be equalized.'''
depths = []
if self.user_depths is not None:
depths = self.user_depths
else:
total_depth = self.start_depth - self.final_depth
if total_depth <= 0:
return depths
layers_required = int((total_depth - self.z_finish_step) / self.step_down)
partial_steplayer = (total_depth - self.z_finish_step) % self.step_down
if equalstep is True and partial_steplayer > 0:
layerstep = float((total_depth - self.z_finish_step) / (layers_required + 1))
return self.user_depths
total_depth = self.start_depth - self.final_depth
if total_depth < 0:
return []
depths = [self.final_depth]
# apply finish step if necessary
if self.z_finish_step > 0:
if self.z_finish_step < total_depth:
depths.append(self.z_finish_step + self.final_depth)
else:
layerstep = self.step_down
return depths
for step in range(layers_required):
d = self.start_depth - ((step +1) * layerstep)
depths.append(d)
if self.z_finish_step != 0 and depths[-1] != self.final_depth + self.z_finish_step:
depths.append(self.final_depth + self.z_finish_step)
if depths[-1] != self.final_depth:
depths.append(self.final_depth)
if equalstep:
depths += self.__equal_steps(self.start_depth, depths[-1], self.step_down)[1:]
else:
depths += self.__fixed_steps(self.start_depth, depths[-1], self.step_down)[1:]
depths.reverse()
return depths
def __equal_steps(self, start, stop, max_size):
'''returns a list of depths beginning with the bottom (included), ending
with the top (not included).
all steps are of equal size, which is as big as possible but not bigger
than max_size.'''
steps_needed = math.ceil((start - stop) / max_size)
depths = numpy.linspace(stop, start, steps_needed, endpoint=False)
return depths.tolist()
def __fixed_steps(self, start, stop, size):
'''returns a list of depths beginning with the bottom (included), ending
with the top (not included).
all steps are of size 'size' except the one at the bottom wich can be
smaller.'''
fullsteps = int((start - stop) / size)
last_step = start - (fullsteps * size)
depths = numpy.linspace(last_step, start, fullsteps, endpoint=False)
if last_step == stop:
return depths.tolist()
else:
return [stop] + depths.tolist()

View File

@@ -27,6 +27,7 @@ import Part
import math
import unittest
from FreeCAD import Vector
from PathScripts.PathGeom import Side
class PathTestBase(unittest.TestCase):
@@ -44,28 +45,39 @@ class PathTestBase(unittest.TestCase):
def assertLine(self, edge, pt1, pt2):
"""Verify that edge is a line from pt1 to pt2."""
self.assertIs(type(edge.Curve), Part.LineSegment)
self.assertCoincide(edge.Curve.StartPoint, pt1)
self.assertCoincide(edge.Curve.EndPoint, pt2)
self.assertIs(type(edge.Curve), Part.Line)
self.assertCoincide(edge.valueAt(edge.FirstParameter), pt1)
self.assertCoincide(edge.valueAt(edge.LastParameter), pt2)
def assertLines(self, edgs, tail, points):
"""Verify that the edges match the polygon resulting from points."""
edges = list(edgs)
if tail:
edges.append(tail)
self.assertEqual(len(edges), len(points) - 1)
for i in range(0, len(edges)):
self.assertLine(edges[i], points[i], points[i+1])
def assertArc(self, edge, pt1, pt2, direction = 'CW'):
"""Verify that edge is an arc between pt1 and pt2 with the given direction."""
# If an Arc is wrapped into edge, then it's curve is represented as a circle
# and not as an Arc (GeomTrimmedCurve)
#self.assertIs(type(edge.Curve), Part.Arc)
self.assertIs(type(edge.Curve), Part.Circle)
self.assertCoincide(edge.valueAt(edge.FirstParameter), pt1)
self.assertCoincide(edge.valueAt(edge.LastParameter), pt2)
ptm = edge.valueAt((edge.LastParameter + edge.FirstParameter)/2)
side = Side.of(pt2 - pt1, ptm - pt1)
#print("(%.2f, %.2f) (%.2f, %.2f) (%.2f, %.2f)" % (pt1.x, pt1.y, ptm.x, ptm.y, pt2.x, pt2.y))
#print(" (%.2f, %.2f) (%.2f, %.2f) -> %s" % ((pt2-pt1).x, (pt2-pt1).y, (ptm-pt1).x, (ptm-pt1).y, Side.toString(side)))
#print(" (%.2f, %.2f) (%.2f, %.2f) -> (%.2f, %.2f)" % (pf.x,pf.y, pl.x,pl.y, pm.x, pmy))
if 'CW' == direction:
self.assertEqual(side, Side.Left)
else:
self.assertEqual(side, Side.Right)
def assertCircle(self, edge, pt, r):
"""Verivy that edge is a circle at given location."""
curve = edge.Curve
self.assertIs(type(curve), Part.Circle)
self.assertCoincide(curve.Center, Vector(pt.x, pt.y, pt.z))
self.assertRoughly(curve.Radius, r)
def assertCurve(self, edge, p1, p2, p3):
"""Verify that the edge goes through the given 3 points, representing start, mid and end point respectively."""
@@ -73,3 +85,27 @@ class PathTestBase(unittest.TestCase):
self.assertCoincide(edge.valueAt(edge.LastParameter), p3)
self.assertCoincide(edge.valueAt((edge.FirstParameter + edge.LastParameter)/2), p2)
def assertCylinderAt(self, solid, pt, r, h):
"""Verify that solid is a cylinder at the specified location."""
self.assertEqual(len(solid.Edges), 3)
lid = solid.Edges[0]
hull = solid.Edges[1]
base = solid.Edges[2]
self.assertCircle(lid, Vector(pt.x, pt.y, pt.z+h), r)
self.assertLine(hull, Vector(pt.x+r, pt.y, pt.z), Vector(pt.x+r, pt.y, pt.z+h))
self.assertCircle(base, Vector(pt.x, pt.y, pt.z), r)
def assertConeAt(self, solid, pt, r1, r2, h):
"""Verify that solid is a cone at the specified location."""
self.assertEqual(len(solid.Edges), 3)
lid = solid.Edges[0]
hull = solid.Edges[1]
base = solid.Edges[2]
self.assertCircle(lid, Vector(pt.x, pt.y, pt.z+h), r2)
self.assertLine(hull, Vector(pt.x+r1, pt.y, pt.z), Vector(pt.x+r2, pt.y, pt.z+h))
self.assertCircle(base, Vector(pt.x, pt.y, pt.z), r1)

View File

@@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * *
# * Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
import FreeCAD
import Path
from PathTests.PathTestUtils import PathTestBase
class TestPathCore(PathTestBase):
def test00(self):
"""Test Path command core functionality"""
#create empty command
c=Path.Command()
self.assertIsInstance(c, Path.Command)
#change name
c.Name = "G1"
self.assertEqual(c.Name, "G1")
#Assign Parameters
c.Parameters= {"X":1,"Y":0}
self.assertEqual(c.Parameters, {'Y': 0.0, 'X': 1.0})
#change parameters
c.Parameters= {"X":1,"Y":0.5}
self.assertEqual(c.Parameters, {'Y': 0.5, 'X': 1})
#output gcode
self.assertEqual(c.toGCode(), 'G1 X1.000000 Y0.500000')
#create and assign name in one
c2=Path.Command("G2")
self.assertEqual(c2.Name, "G2")
#Create Path and parameters in one
c3=Path.Command("G1",{"X":34,"Y":1.2})
self.assertEqual(str(c3), 'Command G1 [ X:34 Y:1.2 ]')
c4 = Path.Command("G1X4Y5")
self.assertEqual(str(c4), 'Command G1 [ X:4 Y:5 ]')
#use placement
self.assertEqual( str(c3.Placement), 'Placement [Pos=(34,1.2,0), Yaw-Pitch-Roll=(0,0,0)]')
self.assertEqual( c3.toGCode(), 'G1 X34.000000 Y1.200000')
p1 = FreeCAD.Placement()
p1.Base = FreeCAD.Vector(3,2,1)
self.assertEqual(str(p1), 'Placement [Pos=(3,2,1), Yaw-Pitch-Roll=(0,0,0)]')
c5=Path.Command("g1",p1)
self.assertEqual(str(c5), 'Command G1 [ X:3 Y:2 Z:1 ]')
p2=FreeCAD.Placement()
p2.Base = FreeCAD.Vector(5,0,0)
#overwrite placement
c5.Placement=p2
self.assertEqual(str(c5), 'Command G1 [ X:5 ]')
self.assertEqual(c5.x, 5.0)
#overwrite individual parameters
c5.x=10
self.assertEqual(c5.x, 10.0)
c5.y=2
self.assertEqual (str(c5), 'Command G1 [ X:10 Y:2 ]')
#set from gcode
c3.setFromGCode("G1X1Y0")
self.assertEqual(str(c3), 'Command G1 [ X:1 Y:0 ]')
def test10(self):
"""Test Path Object core functionality"""
c1=Path.Command("g1",{"x":1,"y":0})
c2=Path.Command("g1",{"x":0,"y":2})
p=Path.Path([c1,c2])
self.assertAlmostEqual(str(p), 'Path [ size:2 length:3.2361 ]', places=4)
self.assertEqual(str(p.Commands), '[Command G1 [ X:1 Y:0 ], Command G1 [ X:0 Y:2 ]]')
self.assertAlmostEqual( p.Length, 3.2361, places=4)
p.addCommands(c1)
self.assertEqual(p.toGCode(), 'G1 X1.000000 Y0.000000\nG1 X0.000000 Y2.000000\nG1 X1.000000 Y0.000000\n')
lines = '''
G0X-0.5905Y-0.3937S3000M03
G0Z0.125
G1Z-0.004F3
G1X0.9842Y-0.3937F14.17
G1X0.9842Y0.433
G1X-0.5905Y0.433
G1X-0.5905Y-0.3937
G0Z0.5
'''
output = '''G0 S3000.000000 X-0.590500 Y-0.393700
M03
G0 Z0.125000
G1 F3.000000 Z-0.004000
G1 F14.170000 X0.984200 Y-0.393700
G1 X0.984200 Y0.433000
G1 X-0.590500 Y0.433000
G1 X-0.590500 Y-0.393700
G0 Z0.500000
'''
#create a path directly form a piece of gcode.
p = Path.Path()
p.setFromGCode(lines)
self.assertEqual (p.toGCode(), output)
def test20(self):
"""Test Path Tool and ToolTable object core functionality"""
t1=Path.Tool()
self.assertIsInstance(t1, Path.Tool)
t1.Name = "12.7mm Drill Bit"
self.assertEqual(t1.Name, "12.7mm Drill Bit")
self.assertEqual(t1.ToolType, "Undefined")
t1.ToolType = "Drill"
self.assertEqual(t1.ToolType, "Drill")
t1.Diameter= 12.7
t1.LengthOffset = 127
t1.CuttingEdgeAngle = 59
t1.CuttingEdgeHeight = 50.8
self.assertEqual(t1.Diameter, 12.7)
self.assertEqual(t1.LengthOffset, 127)
self.assertEqual(t1.CuttingEdgeAngle, 59)
self.assertEqual(t1.CuttingEdgeHeight, 50.8)
t2 = Path.Tool("my other tool",tooltype="EndMill",diameter=10)
table = Path.Tooltable()
self.assertIsInstance(table, Path.Tooltable)
table.addTools(t1)
table.addTools(t2)
self.assertEqual(len(table.Tools), 2)
self.assertEqual(str(table.Tools), '{1: Tool 12.7mm Drill Bit, 2: Tool my other tool}' )

View File

@@ -73,7 +73,7 @@ class depthTestCases(unittest.TestCase):
final_depth = 10
user_depths = None
expected =[]
expected =[10]
d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths)
r = d.get_depths()
@@ -109,7 +109,7 @@ class depthTestCases(unittest.TestCase):
self.assertListEqual (r, expected)
def test40(self):
'''Finish depth passed in.'''
'''z_finish_step passed in.'''
clearance_height= 10
rapid_safety_space = 5
@@ -161,3 +161,23 @@ class depthTestCases(unittest.TestCase):
r = d.get_depths(equalstep=True)
self.assertListEqual (r, expected)
def test70(self):
'''stepping down with stepdown greater than total depth'''
clearance_height= 10
rapid_safety_space = 5
start_depth = 10
step_down = 20
z_finish_step = 1
final_depth = 0
user_depths = None
expected =[1.0, 0]
d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths)
r = d.get_depths(equalstep=True)
self.assertListEqual (r, expected)
d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths)
r = d.get_depths()
self.assertListEqual (r, expected)

View File

@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * *
# * Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
import FreeCAD
import Part
import Path
import PathScripts
import math
import unittest
from FreeCAD import Vector
from PathScripts.PathDressupHoldingTags import *
from PathTests.PathTestUtils import PathTestBase
class TestHoldingTags(PathTestBase):
"""Unit tests for the HoldingTags dressup."""
def test00(self):
"""Check Tag origin, serialization and de-serialization."""
tag = Tag(77, 13, 4, 5, 90, True)
self.assertCoincide(tag.originAt(3), Vector(77, 13, 3))
s = tag.toString()
tagCopy = Tag.FromString(s)
self.assertEqual(tag.x, tagCopy.x)
self.assertEqual(tag.y, tagCopy.y)
self.assertEqual(tag.height, tagCopy.height)
self.assertEqual(tag.width, tagCopy.width)
self.assertEqual(tag.enabled, tagCopy.enabled)
def test01(self):
"""Verify solid for a 90 degree tag is a cylinder."""
tag = Tag(100, 200, 4, 5, 90, True)
tag.createSolidsAt(17, 0)
self.assertIsNotNone(tag.solid)
self.assertCylinderAt(tag.solid, Vector(100, 200, 17), 2, 5)
def test02(self):
"""Verify trapezoidal tag has a cone shape with a lid."""
tag = Tag(0, 0, 18, 5, 45, True)
tag.createSolidsAt(0, 0)
self.assertIsNotNone(tag.solid)
self.assertConeAt(tag.solid, Vector(0,0,0), 9, 4, 5)
def test03(self):
"""Verify pointy cone shape of tag with pointy end if width, angle and height match up."""
tag = Tag(0, 0, 10, 5, 45, True)
tag.createSolidsAt(0, 0)
self.assertIsNotNone(tag.solid)
self.assertConeAt(tag.solid, Vector(0,0,0), 5, 0, 5)
def test04(self):
"""Verify height adjustment if tag isn't wide eough for angle."""
tag = Tag(0, 0, 5, 17, 60, True)
tag.createSolidsAt(0, 0)
self.assertIsNotNone(tag.solid)
self.assertConeAt(tag.solid, Vector(0,0,0), 2.5, 0, 2.5 * math.tan((60/180.0)*math.pi))

View File

@@ -130,12 +130,14 @@ class TestPathGeom(PathTestBase):
commands.append(Path.Command('G0', {'X': 0}))
commands.append(Path.Command('G1', {'Y': 0}))
wire = PathGeom.wireForPath(Path.Path(commands))
wire,rapid = PathGeom.wireForPath(Path.Path(commands))
self.assertEqual(len(wire.Edges), 4)
self.assertLine(wire.Edges[0], Vector(0,0,0), Vector(1,0,0))
self.assertLine(wire.Edges[1], Vector(1,0,0), Vector(1,1,0))
self.assertLine(wire.Edges[2], Vector(1,1,0), Vector(0,1,0))
self.assertLine(wire.Edges[3], Vector(0,1,0), Vector(0,0,0))
self.assertEqual(len(rapid), 1)
self.assertTrue(PathGeom.edgesMatch(rapid[0], wire.Edges[2]))
wires = PathGeom.wiresForPath(Path.Path(commands))
self.assertEqual(len(wires), 2)
@@ -145,3 +147,96 @@ class TestPathGeom(PathTestBase):
self.assertEqual(len(wires[1].Edges), 1)
self.assertLine(wires[1].Edges[0], Vector(0,1,0), Vector(0,0,0))
def test60(self):
"""Verify arcToHelix returns proper helix."""
p1 = Vector(10,-10,0)
p2 = Vector(0,0,0)
p3 = Vector(10,10,0)
e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p1, p2, p3)), 0, 2)
self.assertCurve(e, p1, p2 + Vector(0,0,1), p3 + Vector(0,0,2))
e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p1, p2, p3)), 3, 7)
self.assertCurve(e, p1 + Vector(0,0,3), p2 + Vector(0,0,5), p3 + Vector(0,0,7))
e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p1, p2, p3)), 9, 1)
self.assertCurve(e, p1 + Vector(0,0,9), p2 + Vector(0,0,5), p3 + Vector(0,0,1))
dz = Vector(0,0,3)
p11 = p1 + dz
p12 = p2 + dz
p13 = p3 + dz
e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p11, p12, p13)), 0, 8)
self.assertCurve(e, p1, p2 + Vector(0,0,4), p3 + Vector(0,0,8))
e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p11, p12, p13)), 2, -2)
self.assertCurve(e, p1 + Vector(0,0,2), p2, p3 + Vector(0,0,-2))
o = 10*math.sin(math.pi/4)
p1 = Vector(10, -10, 1)
p2 = Vector(10 - 10*math.sin(math.pi/4), -10*math.cos(math.pi/4), 1)
p3 = Vector(0, 0, 1)
e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p1, p2, p3)), 0, 5)
self.assertCurve(e, Vector(10,-10,0), Vector(p2.x,p2.y,2.5), Vector(0, 0, 5))
def test62(self):
"""Verify splitArcAt returns proper subarcs."""
p1 = Vector(10,-10,0)
p2 = Vector(0,0,0)
p3 = Vector(10,10,0)
arc = Part.Edge(Part.Arc(p1, p2, p3))
o = 10*math.sin(math.pi/4)
p12 = Vector(10 - o, -o, 0)
p23 = Vector(10 - o, +o, 0)
e = PathGeom.splitArcAt(arc, p2)
self.assertCurve(e[0], p1, p12, p2)
self.assertCurve(e[1], p2, p23, p3)
p34 = Vector(10 - 10*math.sin(1*math.pi/8), -10*math.cos(1*math.pi/8), 0)
p45 = Vector(10 - 10*math.sin(5*math.pi/8), -10*math.cos(5*math.pi/8), 0)
e = PathGeom.splitArcAt(arc, p12)
self.assertCurve(e[0], p1, p34, p12)
self.assertCurve(e[1], p12, p45, p3)
def test65(self):
"""Verify splitEdgeAt."""
e = PathGeom.splitEdgeAt(Part.Edge(Part.LineSegment(Vector(), Vector(2, 4, 6))), Vector(1, 2, 3))
self.assertLine(e[0], Vector(), Vector(1,2,3))
self.assertLine(e[1], Vector(1,2,3), Vector(2,4,6))
# split an arc
p1 = Vector(10,-10,1)
p2 = Vector(0,0,1)
p3 = Vector(10,10,1)
arc = Part.Edge(Part.Arc(p1, p2, p3))
e = PathGeom.splitEdgeAt(arc, p2)
o = 10*math.sin(math.pi/4)
p12 = Vector(10 - o, -o, 1)
p23 = Vector(10 - o, +o, 1)
self.assertCurve(e[0], p1, p12, p2)
self.assertCurve(e[1], p2, p23, p3)
# split a helix
p1 = Vector(10,-10,0)
p2 = Vector(0,0,5)
p3 = Vector(10,10,10)
h = PathGeom.arcToHelix(arc, 0, 10)
self.assertCurve(h, p1, p2, p3)
e = PathGeom.splitEdgeAt(h, p2)
o = 10*math.sin(math.pi/4)
p12 = Vector(10 - o, -o, 2.5)
p23 = Vector(10 - o, +o, 7.5)
pf = e[0].valueAt((e[0].FirstParameter + e[0].LastParameter)/2)
pl = e[1].valueAt((e[1].FirstParameter + e[1].LastParameter)/2)
self.assertCurve(e[0], p1, p12, p2)
self.assertCurve(e[1], p2, p23, p3)

View File

@@ -24,8 +24,10 @@
import TestApp
from PathTests.TestPathCore import TestPathCore
from PathTests.TestPathPost import PathPostTestCases
from PathTests.TestPathGeom import TestPathGeom
from PathTests.TestPathDepthParams import depthTestCases
from PathTests.TestPathDressupHoldingTags import TestHoldingTags