@@ -47,7 +47,6 @@ SET(PathScripts_SRCS
|
||||
PathScripts/PathPreferencesPathJob.py
|
||||
PathScripts/PathProfile.py
|
||||
PathScripts/PathProfileEdges.py
|
||||
PathScripts/PathRemote.py
|
||||
PathScripts/PathSanity.py
|
||||
PathScripts/PathSelection.py
|
||||
PathScripts/PathSimpleCopy.py
|
||||
@@ -73,6 +72,7 @@ SET(PathScripts_SRCS
|
||||
PathScripts/rml_post.py
|
||||
PathScripts/slic3r_pre.py
|
||||
PathTests/PathTestUtils.py
|
||||
PathTests/TestPathDepthParams.py
|
||||
PathTests/TestPathGeom.py
|
||||
PathTests/TestPathPost.py
|
||||
PathTests/__init__.py
|
||||
|
||||
@@ -33,8 +33,8 @@ using namespace PathGui;
|
||||
/* TRANSLATOR PathGui::DlgSettingsPathColor */
|
||||
|
||||
/**
|
||||
* Constructs a DlgSettingsObjectColor which is a child of 'parent', with the
|
||||
* name 'name' and widget flags set to 'f'
|
||||
* Constructs a DlgSettingsObjectColor which is a child of 'parent', with the
|
||||
* name 'name' and widget flags set to 'f'
|
||||
*/
|
||||
DlgSettingsPathColor::DlgSettingsPathColor(QWidget* parent)
|
||||
: PreferencePage(parent)
|
||||
@@ -42,7 +42,7 @@ DlgSettingsPathColor::DlgSettingsPathColor(QWidget* parent)
|
||||
this->setupUi(this);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Destroys the object and frees any allocated resources
|
||||
*/
|
||||
DlgSettingsPathColor::~DlgSettingsPathColor()
|
||||
@@ -58,6 +58,8 @@ void DlgSettingsPathColor::saveSettings()
|
||||
DefaultPathLineWidth->onSave();
|
||||
DefaultPathMarkerColor->onSave();
|
||||
DefaultExtentsColor->onSave();
|
||||
DefaultProbePathColor->onSave();
|
||||
DefaultHighlightPathColor->onSave();
|
||||
}
|
||||
|
||||
void DlgSettingsPathColor::loadSettings()
|
||||
@@ -68,6 +70,8 @@ void DlgSettingsPathColor::loadSettings()
|
||||
DefaultPathLineWidth->onRestore();
|
||||
DefaultPathMarkerColor->onRestore();
|
||||
DefaultExtentsColor->onRestore();
|
||||
DefaultProbePathColor->onRestore();
|
||||
DefaultHighlightPathColor->onRestore();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,192 +6,255 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>359</width>
|
||||
<height>282</height>
|
||||
<width>310</width>
|
||||
<height>304</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Path colors</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBoxDefaultColors">
|
||||
<property name="title">
|
||||
<string>Default Path colors</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default normal path color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultNormalPathColor">
|
||||
<property name="toolTip">
|
||||
<string>The default color for new shapes</string>
|
||||
</property>
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>0</red>
|
||||
<green>170</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultNormalPathColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default pathline width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::PrefSpinBox" name="DefaultPathLineWidth">
|
||||
<property name="toolTip">
|
||||
<string>The default line thickness for new shapes</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultPathLineWidth</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default path marker color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultPathMarkerColor">
|
||||
<property name="toolTip">
|
||||
<string>The default line color for new shapes</string>
|
||||
</property>
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>85</red>
|
||||
<green>255</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultPathMarkerColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rapid path color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultRapidPathColor">
|
||||
<property name="toolTip">
|
||||
<string>The default line color for new shapes</string>
|
||||
</property>
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>170</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultRapidPathColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Machine extents color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultExtentsColor">
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultExtentsColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>20</height>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
<property name="text">
|
||||
<string>Default normal path color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultNormalPathColor">
|
||||
<property name="toolTip">
|
||||
<string>The default color for new shapes</string>
|
||||
</property>
|
||||
<property name="color" stdset="0">
|
||||
<color>
|
||||
<red>0</red>
|
||||
<green>170</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultNormalPathColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default pathline width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::PrefSpinBox" name="DefaultPathLineWidth">
|
||||
<property name="toolTip">
|
||||
<string>The default line thickness for new shapes</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultPathLineWidth</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default path marker color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultPathMarkerColor">
|
||||
<property name="toolTip">
|
||||
<string>The default line color for new shapes</string>
|
||||
</property>
|
||||
<property name="color" stdset="0">
|
||||
<color>
|
||||
<red>85</red>
|
||||
<green>255</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultPathMarkerColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rapid path color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultRapidPathColor">
|
||||
<property name="toolTip">
|
||||
<string>The default line color for new shapes</string>
|
||||
</property>
|
||||
<property name="color" stdset="0">
|
||||
<color>
|
||||
<red>170</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultRapidPathColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Probe Path color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultProbePathColor">
|
||||
<property name="toolTip">
|
||||
<string>The default line color for new shapes</string>
|
||||
</property>
|
||||
<property name="color" stdset="0">
|
||||
<color>
|
||||
<red>255</red>
|
||||
<green>255</green>
|
||||
<blue>5</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultProbePathColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Machine extents color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultExtentsColor">
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultExtentsColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Path Highlight Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DefaultHighlightPathColor">
|
||||
<property name="toolTip">
|
||||
<string>The default line color for new shapes</string>
|
||||
</property>
|
||||
<property name="color" stdset="0">
|
||||
<color>
|
||||
<red>255</red>
|
||||
<green>125</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DefaultHighlightPathColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>label_6</zorder>
|
||||
<zorder>DefaultNormalPathColor</zorder>
|
||||
<zorder>label_9</zorder>
|
||||
<zorder>DefaultPathLineWidth</zorder>
|
||||
<zorder>label_10</zorder>
|
||||
<zorder>DefaultPathMarkerColor</zorder>
|
||||
<zorder>label_7</zorder>
|
||||
<zorder>DefaultRapidPathColor</zorder>
|
||||
<zorder>label</zorder>
|
||||
<zorder>DefaultExtentsColor</zorder>
|
||||
<zorder>label_8</zorder>
|
||||
<zorder>DefaultProbePathColor</zorder>
|
||||
<zorder>label_11</zorder>
|
||||
<zorder>DefaultHighlightPathColor</zorder>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -204,6 +267,19 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>7</width>
|
||||
<height>220</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
||||
210
src/Mod/Path/Gui/Resources/panels/ProbeGridEdit.ui
Normal file
210
src/Mod/Path/Gui/Resources/panels/ProbeGridEdit.ui
Normal file
@@ -0,0 +1,210 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>273</width>
|
||||
<height>287</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>240</y>
|
||||
<width>231</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>261</width>
|
||||
<height>231</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Probe Area Shape</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cboProbeAreaShape">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BoundBox</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Perimeter</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_4" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Probe Distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="probeFeedDistance">
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_5" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Probe Feed Rate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="probeFeedRate">
|
||||
<property name="value">
|
||||
<double>50.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Probe Points:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>X:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="xpoints">
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>77</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Y:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="ypoints">
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>423</width>
|
||||
<height>435</height>
|
||||
<width>361</width>
|
||||
<height>418</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -31,7 +31,14 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="NameField"/>
|
||||
<widget class="QLineEdit" name="NameField">
|
||||
<property name="maxLength">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Display Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
@@ -42,6 +49,9 @@
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="TypeField">
|
||||
<property name="currentIndex">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Drill</string>
|
||||
@@ -162,6 +172,12 @@
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
@@ -232,6 +248,12 @@
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -83,14 +83,14 @@ ViewProviderPath::ViewProviderPath()
|
||||
ADD_PROPERTY_TYPE(LineWidth,(lwidth),"Path",App::Prop_None,"The line width of this path");
|
||||
ADD_PROPERTY_TYPE(ShowFirstRapid,(true),"Path",App::Prop_None,"Turns the display of the first rapid move on/off");
|
||||
ADD_PROPERTY_TYPE(ShowNodes,(false),"Path",App::Prop_None,"Turns the display of nodes on/off");
|
||||
|
||||
|
||||
pcPathRoot = new Gui::SoFCSelection();
|
||||
|
||||
pcPathRoot->style = Gui::SoFCSelection::EMISSIVE;
|
||||
pcPathRoot->highlightMode = Gui::SoFCSelection::AUTO;
|
||||
pcPathRoot->selectionMode = Gui::SoFCSelection::SEL_ON;
|
||||
pcPathRoot->ref();
|
||||
|
||||
|
||||
pcTransform = new SoTransform();
|
||||
pcTransform->ref();
|
||||
|
||||
@@ -99,7 +99,7 @@ ViewProviderPath::ViewProviderPath()
|
||||
|
||||
pcMarkerCoords = new SoCoordinate3();
|
||||
pcMarkerCoords->ref();
|
||||
|
||||
|
||||
pcDrawStyle = new SoDrawStyle();
|
||||
pcDrawStyle->ref();
|
||||
pcDrawStyle->style = SoDrawStyle::LINES;
|
||||
@@ -108,17 +108,17 @@ ViewProviderPath::ViewProviderPath()
|
||||
pcLines = new PartGui::SoBrepEdgeSet();
|
||||
pcLines->ref();
|
||||
pcLines->coordIndex.setNum(0);
|
||||
|
||||
|
||||
pcLineColor = new SoMaterial;
|
||||
pcLineColor->ref();
|
||||
|
||||
|
||||
pcMatBind = new SoMaterialBinding;
|
||||
pcMatBind->ref();
|
||||
pcMatBind->value = SoMaterialBinding::OVERALL;
|
||||
|
||||
pcMarkerColor = new SoBaseColor;
|
||||
pcMarkerColor->ref();
|
||||
|
||||
|
||||
NormalColor.touch();
|
||||
MarkerColor.touch();
|
||||
}
|
||||
@@ -186,12 +186,16 @@ void ViewProviderPath::onChanged(const App::Property* prop)
|
||||
pcDrawStyle->lineWidth = LineWidth.getValue();
|
||||
} else if (prop == &NormalColor) {
|
||||
if (colorindex.size() > 0) {
|
||||
const App::Color& c = NormalColor.getValue();
|
||||
const App::Color& c = NormalColor.getValue();
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Path");
|
||||
unsigned long rcol = hGrp->GetUnsigned("DefaultRapidPathColor",2852126975UL); // dark red (170,0,0)
|
||||
float rr,rg,rb;
|
||||
rr = ((rcol >> 24) & 0xff) / 255.0; rg = ((rcol >> 16) & 0xff) / 255.0; rb = ((rcol >> 8) & 0xff) / 255.0;
|
||||
|
||||
|
||||
unsigned long pcol = hGrp->GetUnsigned("DefaultProbePathColor",4293591295UL); // yellow (255,255,5)
|
||||
float pr,pg,pb;
|
||||
pr = ((pcol >> 24) & 0xff) / 255.0; pg = ((pcol >> 16) & 0xff) / 255.0; pb = ((pcol >> 8) & 0xff) / 255.0;
|
||||
|
||||
pcMatBind->value = SoMaterialBinding::PER_PART;
|
||||
// resizing and writing the color vector:
|
||||
pcLineColor->diffuseColor.setNum(colorindex.size());
|
||||
@@ -199,8 +203,10 @@ void ViewProviderPath::onChanged(const App::Property* prop)
|
||||
for(unsigned int i=0;i<colorindex.size();i++) {
|
||||
if (colorindex[i] == 0)
|
||||
colors[i] = SbColor(rr,rg,rb);
|
||||
else
|
||||
else if (colorindex[i] == 1)
|
||||
colors[i] = SbColor(c.r,c.g,c.b);
|
||||
else
|
||||
colors[i] = SbColor(pr,pg,pb);
|
||||
}
|
||||
pcLineColor->diffuseColor.finishEditing();
|
||||
}
|
||||
@@ -220,14 +226,14 @@ void ViewProviderPath::updateData(const App::Property* prop)
|
||||
Path::Feature* pcPathObj = static_cast<Path::Feature*>(pcObject);
|
||||
|
||||
if (prop == &pcPathObj->Path) {
|
||||
|
||||
|
||||
const Toolpath &tp = pcPathObj->Path.getValue();
|
||||
if(tp.getSize()==0) {
|
||||
pcLineCoords->point.deleteValues(0);
|
||||
pcMarkerCoords->point.deleteValues(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Part");
|
||||
float deviation = hGrp->GetFloat("MeshDeviation",0.2);
|
||||
std::vector<Base::Vector3d> points;
|
||||
@@ -237,7 +243,7 @@ void ViewProviderPath::updateData(const App::Property* prop)
|
||||
bool absolute = true;
|
||||
bool absolutecenter = false;
|
||||
bool first = true;
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < tp.getSize(); i++) {
|
||||
Path::Command cmd = tp.getCommand(i);
|
||||
std::string name = cmd.Name;
|
||||
@@ -250,7 +256,7 @@ void ViewProviderPath::updateData(const App::Property* prop)
|
||||
next.y = last.y;
|
||||
if (!cmd.has("Z"))
|
||||
next.z = last.z;
|
||||
|
||||
|
||||
if ( (name == "G0") || (name == "G00") || (name == "G1") || (name == "G01") ) {
|
||||
// straight line
|
||||
if ( (!first) || (ShowFirstRapid.getValue() == true) || (name == "G1") || (name == "G01") ) {
|
||||
@@ -273,12 +279,12 @@ void ViewProviderPath::updateData(const App::Property* prop)
|
||||
markers.push_back(last); // startpoint of path
|
||||
}
|
||||
first = false;
|
||||
|
||||
|
||||
} else if ( (name == "G2") || (name == "G02") || (name == "G3") || (name == "G03") ) {
|
||||
// arc
|
||||
Base::Vector3d norm;
|
||||
Base::Vector3d center;
|
||||
|
||||
|
||||
if ( (name == "G2") || (name == "G02") )
|
||||
norm.Set(0,0,-1);
|
||||
else
|
||||
@@ -321,23 +327,23 @@ void ViewProviderPath::updateData(const App::Property* prop)
|
||||
}
|
||||
last = next;
|
||||
colorindex.push_back(1);
|
||||
|
||||
|
||||
} else if (name == "G90") {
|
||||
// absolute mode
|
||||
absolute = true;
|
||||
|
||||
|
||||
} else if (name == "G91") {
|
||||
// relative mode
|
||||
absolute = false;
|
||||
|
||||
|
||||
} else if (name == "G90.1") {
|
||||
// absolute mode
|
||||
absolutecenter = true;
|
||||
|
||||
|
||||
} else if (name == "G91.1") {
|
||||
// relative mode
|
||||
absolutecenter = false;
|
||||
|
||||
|
||||
} else if ((name=="G81")||(name=="G82")||(name=="G83")||(name=="G84")||(name=="G85")||(name=="G86")||(name=="G89")){
|
||||
// drill,tap,bore
|
||||
double r = 0;
|
||||
@@ -373,9 +379,19 @@ void ViewProviderPath::updateData(const App::Property* prop)
|
||||
if (ShowNodes.getValue() == true)
|
||||
markers.push_back(p2);
|
||||
colorindex.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else if ((name=="G38.2")||(name=="38.3")||(name=="G38.4")||(name=="G38.5")){
|
||||
// Straight probe
|
||||
Base::Vector3d p1(next.x,next.y,last.z);
|
||||
points.push_back(p1);
|
||||
colorindex.push_back(0);
|
||||
points.push_back(next);
|
||||
colorindex.push_back(2);
|
||||
Base::Vector3d p3(next.x,next.y,last.z);
|
||||
points.push_back(p3);
|
||||
colorindex.push_back(0);
|
||||
}}
|
||||
|
||||
if (!points.empty()) {
|
||||
pcLineCoords->point.deleteValues(0);
|
||||
pcLineCoords->point.setNum(points.size());
|
||||
@@ -387,20 +403,20 @@ void ViewProviderPath::updateData(const App::Property* prop)
|
||||
int* segs = &ei[0];
|
||||
pcLines->coordIndex.setNum(points.size());
|
||||
pcLines->coordIndex.setValues(0,points.size(),(const int32_t*)segs);
|
||||
|
||||
|
||||
pcMarkerCoords->point.deleteValues(0);
|
||||
|
||||
|
||||
pcMarkerCoords->point.setNum(markers.size());
|
||||
for(unsigned int i=0;i<markers.size();i++)
|
||||
pcMarkerCoords->point.set1Value(i,markers[i].x,markers[i].y,markers[i].z);
|
||||
|
||||
|
||||
// update the coloring after we changed the color vector
|
||||
NormalColor.touch();
|
||||
recomputeBoundingBox();
|
||||
}
|
||||
|
||||
|
||||
} else if ( prop == &pcPathObj->Placement) {
|
||||
|
||||
|
||||
Base::Placement pl = *(&pcPathObj->Placement.getValue());
|
||||
Base::Vector3d pos = pl.getPosition();
|
||||
double q1, q2, q3, q4;
|
||||
|
||||
@@ -67,7 +67,6 @@ class PathWorkbench (Workbench):
|
||||
from PathScripts import PathSimpleCopy
|
||||
from PathScripts import PathEngrave
|
||||
from PathScripts import PathSurface
|
||||
from PathScripts import PathRemote
|
||||
from PathScripts import PathSanity
|
||||
from PathScripts import DragknifeDressup
|
||||
from PathScripts import PathContour
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>614</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCommandLinkButton" name="cmdAddTools">
|
||||
<property name="text">
|
||||
<string>Add Selected Tools to Project</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Tool Library</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="4" column="2">
|
||||
<widget class="QPushButton" name="ButtonDelete">
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="ButtonImport">
|
||||
<property name="text">
|
||||
<string>Import...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QPushButton" name="ButtonUp">
|
||||
<property name="text">
|
||||
<string>Move up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QPushButton" name="ButtonAdd">
|
||||
<property name="text">
|
||||
<string>Add new List</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="4">
|
||||
<widget class="QPushButton" name="ButtonDown">
|
||||
<property name="text">
|
||||
<string>Move down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QPushButton" name="ButtonNewTool">
|
||||
<property name="text">
|
||||
<string>New Tool</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="ButtonExport">
|
||||
<property name="text">
|
||||
<string>Export...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="4">
|
||||
<widget class="QTableView" name="ToolsList"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,244 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>807</width>
|
||||
<height>555</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Tool Properties</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="NameField"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="TypeField"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Material</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="MaterialField"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Diameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QDoubleSpinBox" name="DiameterField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Length Offset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QDoubleSpinBox" name="LengthOffsetField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Flat Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QDoubleSpinBox" name="FlatRadiusField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Corner Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<widget class="QDoubleSpinBox" name="CornerRadiusField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Cutting Edge Angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<widget class="QDoubleSpinBox" name="CuttingEdgeAngleField">
|
||||
<property name="suffix">
|
||||
<string>°</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Cutting Edge Height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<widget class="QDoubleSpinBox" name="CuttingEdgeHeightField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Tool List</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="ButtonDelete">
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="ButtonUp">
|
||||
<property name="text">
|
||||
<string>Move up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="ButtonImport">
|
||||
<property name="text">
|
||||
<string>Import...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="ButtonExport">
|
||||
<property name="text">
|
||||
<string>Export...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="ButtonAdd">
|
||||
<property name="text">
|
||||
<string>Add new</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="4">
|
||||
<widget class="QTableView" name="ToolsList"/>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QPushButton" name="ButtonDown">
|
||||
<property name="text">
|
||||
<string>Move down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -195,7 +195,7 @@ class ObjectDrilling:
|
||||
if isinstance(subobj.Edges[0].Curve, Part.Circle):
|
||||
drillable = True
|
||||
if str(subobj.Surface) == "<Cylinder object>":
|
||||
drillable = True
|
||||
drillable = subobj.isClosed()
|
||||
if len(subobj.Edges) == 3:
|
||||
cedge = []
|
||||
ledge = []
|
||||
@@ -211,7 +211,7 @@ class ObjectDrilling:
|
||||
drillable = False
|
||||
if sub[0:4] == 'Edge':
|
||||
o = obj.getElement(sub)
|
||||
if isinstance(o.Curve, Part.Circle) and len(o.Vertexes) == 1:
|
||||
if isinstance(o.Curve, Part.Circle):
|
||||
drillable = True
|
||||
|
||||
return drillable
|
||||
@@ -266,9 +266,37 @@ class ObjectDrilling:
|
||||
FreeCAD.Console.PrintWarning("Drillable location already in the list" + "\n")
|
||||
else:
|
||||
baselist.append(item)
|
||||
print baselist
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
|
||||
if sub[0:4] == 'Edge':
|
||||
drillableEdges = []
|
||||
o = ss.Shape.getElement(sub)
|
||||
|
||||
for i in range(len(ss.Shape.Edges)):
|
||||
candidateedge = ss.Shape.getElement("Edge" + str(i+1))
|
||||
if self.checkdrillable(ss.Shape, "Edge" + str(i+1)):
|
||||
if candidateedge.Curve.Radius == o.Curve.Radius and candidateedge.Curve.Center.z == o.Curve.Center.z:
|
||||
drillableEdges.append("Edge" + str(i+1))
|
||||
if len(drillableEdges) > 1:
|
||||
reply = QtGui.QMessageBox.question(None,"","Multiple drillable faces found. Drill them all?",
|
||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
|
||||
if reply == QtGui.QMessageBox.Yes:
|
||||
for i in drillableEdges:
|
||||
if i in baselist:
|
||||
FreeCAD.Console.PrintWarning("Drillable location already in the list" + "\n")
|
||||
continue
|
||||
else:
|
||||
newitem = (ss, i)
|
||||
baselist.append(newitem)
|
||||
else:
|
||||
if item in baselist:
|
||||
FreeCAD.Console.PrintWarning("Drillable location already in the list" + "\n")
|
||||
else:
|
||||
baselist.append(item)
|
||||
|
||||
print baselist
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
|
||||
|
||||
class _ViewProviderDrill:
|
||||
def __init__(self, obj):
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
from PySide import QtCore, QtGui
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
|
||||
import Path
|
||||
# Qt tanslation handling
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
@@ -37,21 +37,21 @@ except AttributeError:
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
class OldHighlighter(QtGui.QSyntaxHighlighter):
|
||||
# class OldHighlighter(QtGui.QSyntaxHighlighter):
|
||||
|
||||
def highlightBlock(self, text):
|
||||
# def highlightBlock(self, text):
|
||||
|
||||
myClassFormat = QtGui.QTextCharFormat()
|
||||
myClassFormat.setFontWeight(QtGui.QFont.Bold)
|
||||
myClassFormat.setForeground(QtCore.Qt.green)
|
||||
# the regex pattern to be colored
|
||||
pattern = "(G.*?|M.*?)\\s"
|
||||
expression = QtCore.QRegExp(pattern)
|
||||
index = text.index(expression)
|
||||
while index >= 0:
|
||||
length = expression.matchedLength()
|
||||
setFormat(index, length, myClassFormat)
|
||||
index = text.index(expression, index + length)
|
||||
# myClassFormat = QtGui.QTextCharFormat()
|
||||
# myClassFormat.setFontWeight(QtGui.QFont.Bold)
|
||||
# myClassFormat.setForeground(QtCore.Qt.green)
|
||||
# # the regex pattern to be colored
|
||||
# pattern = "(G.*?|M.*?)\\s"
|
||||
# expression = QtCore.QRegExp(pattern)
|
||||
# index = text.index(expression)
|
||||
# while index >= 0:
|
||||
# length = expression.matchedLength()
|
||||
# setFormat(index, length, myClassFormat)
|
||||
# index = text.index(expression, index + length)
|
||||
|
||||
|
||||
class GCodeHighlighter(QtGui.QSyntaxHighlighter):
|
||||
@@ -110,11 +110,21 @@ class GCodeHighlighter(QtGui.QSyntaxHighlighter):
|
||||
|
||||
class GCodeEditorDialog(QtGui.QDialog):
|
||||
|
||||
def __init__(self, parent=FreeCADGui.getMainWindow()):
|
||||
|
||||
def __init__(self, PathObj, parent=FreeCADGui.getMainWindow()):
|
||||
self.PathObj = PathObj
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
layout = QtGui.QVBoxLayout(self)
|
||||
|
||||
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
|
||||
c = p.GetUnsigned("DefaultHighlightPathColor", 4286382335 )
|
||||
Q = QtGui.QColor(int((c >> 24) & 0xFF), int((c >> 16) & 0xFF), int((c >> 8) & 0xFF))
|
||||
highlightcolor = (Q.red()/255., Q.green()/255., Q.blue()/255., Q.alpha()/255.)
|
||||
|
||||
self.selectionobj = FreeCAD.ActiveDocument.addObject("Path::Feature","selection")
|
||||
self.selectionobj.ViewObject.LineWidth = 4
|
||||
self.selectionobj.ViewObject.NormalColor = highlightcolor
|
||||
self.selectionobj.ViewObject.ShowFirstRapid = False
|
||||
|
||||
# nice text editor widget for editing the gcode
|
||||
self.editor = QtGui.QTextEdit()
|
||||
font = QtGui.QFont()
|
||||
@@ -140,6 +150,53 @@ class GCodeEditorDialog(QtGui.QDialog):
|
||||
layout.addWidget(self.buttons)
|
||||
self.buttons.accepted.connect(self.accept)
|
||||
self.buttons.rejected.connect(self.reject)
|
||||
self.editor.selectionChanged.connect(self.hightlightpath)
|
||||
self.finished.connect(self.cleanup)
|
||||
|
||||
def cleanup(self):
|
||||
FreeCAD.ActiveDocument.removeObject(self.selectionobj.Name)
|
||||
|
||||
def hightlightpath(self):
|
||||
cursor = self.editor.textCursor()
|
||||
sp = cursor.selectionStart()
|
||||
ep = cursor.selectionEnd()
|
||||
cursor.setPosition(sp)
|
||||
startrow = cursor.blockNumber()
|
||||
cursor.setPosition(ep)
|
||||
endrow = cursor.blockNumber()
|
||||
|
||||
commands = self.PathObj.Commands
|
||||
|
||||
#Derive the starting position for the first selected command
|
||||
prevX = prevY = prevZ = None
|
||||
prevcommands = commands[:startrow]
|
||||
prevcommands.reverse()
|
||||
for c in prevcommands:
|
||||
if prevX is None:
|
||||
if c.Parameters.get("X") is not None:
|
||||
prevX = c.Parameters.get("X")
|
||||
if prevY is None:
|
||||
if c.Parameters.get("Y") is not None:
|
||||
prevY = c.Parameters.get("Y")
|
||||
if prevZ is None:
|
||||
if c.Parameters.get("Z") is not None:
|
||||
prevZ = c.Parameters.get("Z")
|
||||
if prevX is not None and prevY is not None and prevZ is not None:
|
||||
break
|
||||
if prevX is None:
|
||||
prevX = 0.0
|
||||
if prevY is None:
|
||||
prevY = 0.0
|
||||
if prevZ is None:
|
||||
prevZ = 0.0
|
||||
|
||||
#Build a new path with selection
|
||||
p = Path.Path()
|
||||
firstrapid = Path.Command("G0", {"X": prevX, "Y":prevY, "Z":prevZ})
|
||||
|
||||
selectionpath = [firstrapid] + commands[startrow:endrow +1]
|
||||
p.Commands = selectionpath
|
||||
self.selectionobj.Path = p
|
||||
|
||||
|
||||
def show(obj):
|
||||
@@ -147,7 +204,7 @@ def show(obj):
|
||||
|
||||
if hasattr(obj, "Path"):
|
||||
if obj.Path:
|
||||
dia = GCodeEditorDialog()
|
||||
dia = GCodeEditorDialog(obj.Path)
|
||||
dia.editor.setText(obj.Path.toGCode())
|
||||
result = dia.exec_()
|
||||
# exec_() returns 0 or 1 depending on the button pressed (Ok or
|
||||
|
||||
@@ -28,8 +28,6 @@ from PySide import QtCore, QtGui
|
||||
from PathScripts.PathPostProcessor import PostProcessor
|
||||
from PathScripts.PathPreferences import PathPreferences
|
||||
import Draft
|
||||
import os
|
||||
import glob
|
||||
|
||||
|
||||
FreeCADGui = None
|
||||
@@ -331,11 +329,8 @@ class TaskPanel:
|
||||
else:
|
||||
for o in FreeCADGui.Selection.getCompleteSelection():
|
||||
baseindex = self.form.cboBaseObject.findText(o.Name, QtCore.Qt.MatchFixedString)
|
||||
print baseindex
|
||||
if baseindex >= 0:
|
||||
self.form.cboBaseObject.blockSignals(True)
|
||||
self.form.cboBaseObject.setCurrentIndex(baseindex)
|
||||
self.form.cboBaseObject.blockSignals(False)
|
||||
|
||||
|
||||
def open(self):
|
||||
|
||||
@@ -22,16 +22,9 @@
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
'''PathKurveUtils - functions needed for using libarea (created by Dan Heeks) for making simple CNC profile paths '''
|
||||
import FreeCAD
|
||||
from FreeCAD import Vector
|
||||
import FreeCADGui as Gui
|
||||
import Part
|
||||
import DraftGeomUtils
|
||||
import DraftVecUtils
|
||||
from DraftGeomUtils import geomType
|
||||
import math
|
||||
import area
|
||||
import Path
|
||||
from PathScripts import PathUtils
|
||||
from nc.nc import *
|
||||
import PathScripts.nc.iso
|
||||
@@ -209,7 +202,7 @@ def profile(curve, side_of_line, radius=1.0, vertfeed=0.0, horizfeed=0.0, offset
|
||||
layer_count = int((start_depth - final_depth) / stepdown)
|
||||
if layer_count * stepdown + 0.00001 < start_depth - final_depth:
|
||||
layer_count += 1
|
||||
current_start_depth = start_depth
|
||||
# current_start_depth = start_depth
|
||||
prev_depth = start_depth
|
||||
for i in range(1, layer_count + 1):
|
||||
if i == layer_count:
|
||||
@@ -388,7 +381,7 @@ def profile2(curve, direction="on", radius=1.0, vertfeed=0.0,
|
||||
# do multiple depths
|
||||
depths = depthparams.get_depths()
|
||||
|
||||
current_start_depth = depthparams.start_depth
|
||||
# current_start_depth = depthparams.start_depth
|
||||
|
||||
# tags
|
||||
if len(tags) > 0:
|
||||
@@ -532,7 +525,7 @@ class Tag:
|
||||
|
||||
height_above_depth = tag_top_depth - depth
|
||||
ramp_width_at_depth = height_above_depth / math.tan(self.angle)
|
||||
cut_depth = start_depth - depth
|
||||
# cut_depth = start_depth - depth
|
||||
half_flat_top = radius + self.width / 2
|
||||
|
||||
d = curve.PointToPerim(self.p)
|
||||
@@ -574,7 +567,7 @@ class Tag:
|
||||
def get_z_at_perim(self, current_perim, curve, radius, start_depth, depth, final_depth):
|
||||
# return the z for this position on the kurve ( specified by current_perim ), for this tag
|
||||
# if the position is not within the tag, then depth is returned
|
||||
cut_depth = start_depth - depth
|
||||
# cut_depth = start_depth - depth
|
||||
half_flat_top = radius + self.width / 2
|
||||
|
||||
z = depth
|
||||
|
||||
@@ -114,12 +114,12 @@ class ObjectFace:
|
||||
bb = ss.Shape.BoundBox # parent boundbox
|
||||
subobj = ss.Shape.getElement(sub)
|
||||
fbb = subobj.BoundBox # feature boundbox
|
||||
obj.StartDepth = bb.ZMax
|
||||
obj.StartDepth = bb.ZMax + 1
|
||||
obj.ClearanceHeight = bb.ZMax + 5.0
|
||||
obj.SafeHeight = bb.ZMax + 3.0
|
||||
|
||||
if fbb.ZMax == fbb.ZMin and fbb.ZMax == bb.ZMax: # top face
|
||||
obj.FinalDepth = bb.ZMin
|
||||
obj.FinalDepth = fbb.ZMin
|
||||
elif fbb.ZMax > fbb.ZMin and fbb.ZMax == bb.ZMax: # vertical face, full cut
|
||||
obj.FinalDepth = fbb.ZMin
|
||||
elif fbb.ZMax > fbb.ZMin and fbb.ZMin > bb.ZMin: # internal vertical wall
|
||||
@@ -211,6 +211,7 @@ class ObjectFace:
|
||||
|
||||
# To reload this from FreeCAD, use: import PathScripts.PathFace; reload(PathScripts.PathFace)
|
||||
def execute(self, obj):
|
||||
print "in execute"
|
||||
|
||||
if not obj.Active:
|
||||
path = Path.Path("(inactive operation)")
|
||||
@@ -224,7 +225,7 @@ class ObjectFace:
|
||||
self.vertFeed = 100
|
||||
self.horizFeed = 100
|
||||
self.vertRapid = 100
|
||||
self.horiRrapid = 100
|
||||
self.horizRrapid = 100
|
||||
self.radius = 0.25
|
||||
obj.ToolNumber = 0
|
||||
obj.ToolDescription = "UNDEFINED"
|
||||
@@ -511,6 +512,8 @@ class TaskPanel:
|
||||
for i in self.obj.Base:
|
||||
for sub in i[1]:
|
||||
self.form.baseList.addItem(i[0].Name + "." + sub)
|
||||
#self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def deleteBase(self):
|
||||
dlist = self.form.baseList.selectedItems()
|
||||
@@ -533,11 +536,10 @@ class TaskPanel:
|
||||
newlist.append(i)
|
||||
self.form.baseList.takeItem(self.form.baseList.row(d))
|
||||
self.obj.Base = newlist
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
#self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def itemActivated(self):
|
||||
print self.form.baseList.selectedItems()[0].text()
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
slist = self.form.baseList.selectedItems()
|
||||
for i in slist:
|
||||
@@ -561,7 +563,7 @@ class TaskPanel:
|
||||
newlist.append(item)
|
||||
self.obj.Base = newlist
|
||||
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
#self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def getStandardButtons(self):
|
||||
|
||||
@@ -1,478 +0,0 @@
|
||||
# -*- 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 PathScripts import PathUtils
|
||||
import urllib2
|
||||
import json
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
__title__ = "Path Remote Operation"
|
||||
__author__ = "sliptonic (Brad Collette)"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
"""Path Remote processing object and FreeCAD command"""
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
class ObjectRemote:
|
||||
|
||||
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::PropertyString", "URL", "API", QtCore.QT_TRANSLATE_NOOP("App::Property","The Base URL of the remote path service"))
|
||||
obj.addProperty("App::PropertyStringList", "proplist", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property","list of remote properties"))
|
||||
obj.setEditorMode('proplist', 2) # make this hidden
|
||||
|
||||
# Tool Properties
|
||||
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool",QtCore.QT_TRANSLATE_NOOP("App::Property","The tool number in use"))
|
||||
obj.ToolNumber = (0, 0, 1000, 0)
|
||||
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
|
||||
|
||||
# Depth Properties
|
||||
obj.addProperty("App::PropertyFloat", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","The height needed to clear clamps and obstructions"))
|
||||
obj.addProperty("App::PropertyFloat", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Rapid Safety Height between locations."))
|
||||
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Step", QtCore.QT_TRANSLATE_NOOP("App::Property","Incremental Step Down of Tool"))
|
||||
obj.StepDown = (0.0, 0.01, 100.0, 0.5)
|
||||
obj.addProperty("App::PropertyFloat", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Starting Depth of Tool- first cut depth in Z"))
|
||||
obj.addProperty("App::PropertyFloat", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Final Depth of Tool- lowest value in Z"))
|
||||
obj.addProperty("App::PropertyFloat", "FinishDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property","Maximum material removed on final pass."))
|
||||
|
||||
obj.Proxy = self
|
||||
|
||||
def addbaseobject(self, obj, ss, sub=""):
|
||||
baselist = obj.Base
|
||||
if len(baselist) == 0: # When adding the first base object, guess at heights
|
||||
try:
|
||||
bb = ss.Shape.BoundBox # parent boundbox
|
||||
subobj = ss.Shape.getElement(sub)
|
||||
fbb = subobj.BoundBox # feature boundbox
|
||||
obj.StartDepth = bb.ZMax
|
||||
obj.ClearanceHeight = bb.ZMax + 5.0
|
||||
obj.SafeHeight = bb.ZMax + 3.0
|
||||
|
||||
if fbb.ZMax < bb.ZMax:
|
||||
obj.FinalDepth = fbb.ZMax
|
||||
else:
|
||||
obj.FinalDepth = bb.ZMin
|
||||
except:
|
||||
obj.StartDepth = 5.0
|
||||
obj.ClearanceHeight = 10.0
|
||||
obj.SafeHeight = 8.0
|
||||
|
||||
item = (ss, sub)
|
||||
if item in baselist:
|
||||
FreeCAD.Console.PrintWarning("this object already in the list" + "\n")
|
||||
else:
|
||||
baselist.append(item)
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
|
||||
"'''Do something when a property has changed'''"
|
||||
if prop == "URL":
|
||||
url = obj.URL + "/api/v1.0/properties"
|
||||
try:
|
||||
response = urllib2.urlopen(url)
|
||||
except:
|
||||
print "service not defined or not responding"
|
||||
print "len: " + str(len(obj.proplist))
|
||||
if len(obj.proplist) != 0:
|
||||
for prop in obj.proplist:
|
||||
print "removing: " + str(prop)
|
||||
obj.removeProperty(prop)
|
||||
pl = obj.proplist
|
||||
pl = []
|
||||
obj.proplist = pl
|
||||
return
|
||||
|
||||
data = json.load(response)
|
||||
|
||||
properties = data['properties']
|
||||
for prop in obj.proplist:
|
||||
print "removing: " + str(prop)
|
||||
obj.removeProperty(prop)
|
||||
|
||||
pl = obj.proplist
|
||||
pl = []
|
||||
for prop in properties:
|
||||
obj.addProperty(
|
||||
prop['type'],
|
||||
prop['propertyname'],
|
||||
"Remote",
|
||||
prop['description'])
|
||||
pl.append(prop['propertyname'])
|
||||
print "adding: " + str(prop)
|
||||
obj.proplist = pl
|
||||
|
||||
if prop == "UserLabel":
|
||||
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
|
||||
|
||||
def execute(self, obj):
|
||||
output = ""
|
||||
if obj.Comment != "":
|
||||
output += '(' + str(obj.Comment)+')\n'
|
||||
|
||||
toolLoad = PathUtils.getLastToolLoad(obj)
|
||||
if toolLoad is None or toolLoad.ToolNumber == 0:
|
||||
self.vertFeed = 100
|
||||
self.horizFeed = 100
|
||||
self.radius = 0.25
|
||||
obj.ToolNumber = 0
|
||||
obj.ToolDescription = "UNDEFINED"
|
||||
else:
|
||||
self.vertFeed = toolLoad.VertFeed.Value
|
||||
self.horizFeed = toolLoad.HorizFeed.Value
|
||||
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
|
||||
self.radius = tool.Diameter/2
|
||||
obj.ToolNumber = toolLoad.ToolNumber
|
||||
obj.ToolDescription = toolLoad.Name
|
||||
|
||||
if obj.UserLabel == "":
|
||||
obj.Label = obj.Name + " :" + obj.ToolDescription
|
||||
else:
|
||||
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
|
||||
|
||||
output += "(remote gcode goes here)"
|
||||
|
||||
if obj.Active:
|
||||
path = Path.Path(output)
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = True
|
||||
|
||||
else:
|
||||
path = Path.Path("(inactive operation)")
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = False
|
||||
|
||||
|
||||
class ViewProviderRemote:
|
||||
def __init__(self, obj):
|
||||
obj.Proxy = self
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/Path-Remote.svg"
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
# this is executed when a property of the VIEW PROVIDER changes
|
||||
pass
|
||||
|
||||
def updateData(self, obj, prop): # optional
|
||||
# this is executed when a property of the APP OBJECT changes
|
||||
pass
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
taskd = TaskPanel()
|
||||
taskd.obj = vobj.Object
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
taskd.setupUi()
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode):
|
||||
# this is executed when the user cancels or terminates edit mode
|
||||
pass
|
||||
|
||||
|
||||
class _RefreshRemotePath:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Path-Refresh',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Remote", "Refresh Remote Path Data"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Remote", "Refresh Remote Path Data")}
|
||||
|
||||
def IsActive(self):
|
||||
return FreeCAD.ActiveDocument is not None
|
||||
|
||||
def refresh(self):
|
||||
obj = FreeCADGui.Selection.getSelection()[0]
|
||||
values = {}
|
||||
|
||||
for i in obj.PropertiesList:
|
||||
if obj.getGroupOfProperty(i) in ["Remote"]:
|
||||
values.update({i: obj.getPropertyByName(i)})
|
||||
|
||||
if obj.getGroupOfProperty(i) in ["Depth"]:
|
||||
print str(i)
|
||||
values.update({i: obj.getPropertyByName(i)})
|
||||
|
||||
if obj.getGroupOfProperty(i) in ["Step"]:
|
||||
values.update({i: obj.getPropertyByName(i)})
|
||||
|
||||
if obj.getGroupOfProperty(i) in ["Tool"]:
|
||||
tool = PathUtils.getTool(obj, obj.ToolNumber)
|
||||
if tool:
|
||||
tradius = tool.Diameter/2
|
||||
tlength = tool.LengthOffset
|
||||
ttype = tool.ToolType
|
||||
else:
|
||||
tradius = 0.25
|
||||
tlength = 1
|
||||
ttype = "undefined"
|
||||
|
||||
values.update({"tool_diameter": tradius})
|
||||
values.update({"tool_length": tlength})
|
||||
values.update({"tool_type": ttype})
|
||||
|
||||
payload = json.dumps(values)
|
||||
|
||||
url = obj.URL + "/api/v1.0/path"
|
||||
print url
|
||||
try:
|
||||
req = urllib2.Request(url)
|
||||
req.add_header('Content-Type', 'application/json')
|
||||
response = urllib2.urlopen(req, payload)
|
||||
data = json.load(response)
|
||||
except:
|
||||
print "service not defined or not responding"
|
||||
return
|
||||
|
||||
path = data['path']
|
||||
output = ""
|
||||
for command in path:
|
||||
output += command['command']
|
||||
path = Path.Path(output)
|
||||
obj.Path = path
|
||||
|
||||
def Activated(self):
|
||||
self.refresh()
|
||||
|
||||
|
||||
class CommandPathRemote:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Path-Remote',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Remote", "Remote"),
|
||||
'Accel': "P, R",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Remote", "Request a Path from a remote cloud service")}
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument is not None:
|
||||
for o in FreeCAD.ActiveDocument.Objects:
|
||||
if o.Name[:3] == "Job":
|
||||
return True
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
ztop = 10.0
|
||||
zbottom = 0.0
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Path_Remote", "Create remote path operation"))
|
||||
FreeCADGui.addModule("PathScripts.PathRemote")
|
||||
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "Remote")')
|
||||
FreeCADGui.doCommand('PathScripts.PathRemote.ObjectRemote(obj)')
|
||||
FreeCADGui.doCommand('obj.Active = True')
|
||||
FreeCADGui.doCommand('PathScripts.PathRemote.ViewProviderRemote(obj.ViewObject)')
|
||||
FreeCADGui.doCommand('from PathScripts import PathUtils')
|
||||
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop + 2))
|
||||
FreeCADGui.doCommand('obj.StartDepth = ' + str(ztop))
|
||||
FreeCADGui.doCommand('obj.SafeHeight = ' + str(ztop + 2))
|
||||
FreeCADGui.doCommand('obj.StepDown = ' + str((ztop-zbottom)/8))
|
||||
|
||||
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
|
||||
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
|
||||
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
|
||||
|
||||
|
||||
class TaskPanel:
|
||||
def __init__(self):
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/RemoteEdit.ui")
|
||||
|
||||
def accept(self):
|
||||
self.getFields()
|
||||
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.Selection.removeObserver(self.s)
|
||||
|
||||
def reject(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.Selection.removeObserver(self.s)
|
||||
|
||||
def getRemoteFields(self):
|
||||
self.getFields()
|
||||
self.obj.URL = self.form.remoteURL.text()
|
||||
print "getRemote:320"
|
||||
|
||||
def getFields(self):
|
||||
if self.obj:
|
||||
if hasattr(self.obj, "StartDepth"):
|
||||
self.obj.StartDepth = float(self.form.startDepth.text())
|
||||
if hasattr(self.obj, "FinalDepth"):
|
||||
self.obj.FinalDepth = float(self.form.finalDepth.text())
|
||||
if hasattr(self.obj, "SafeHeight"):
|
||||
self.obj.SafeHeight = float(self.form.safeHeight.text())
|
||||
if hasattr(self.obj, "ClearanceHeight"):
|
||||
self.obj.ClearanceHeight = float(self.form.clearanceHeight.text())
|
||||
if hasattr(self.obj, "StepDown"):
|
||||
self.obj.StepDown = float(self.form.stepDown.value())
|
||||
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
def open(self):
|
||||
self.s = SelObserver()
|
||||
FreeCADGui.Selection.addObserver(self.s)
|
||||
|
||||
def addBase(self):
|
||||
# check that the selection contains exactly what we want
|
||||
selection = FreeCADGui.Selection.getSelectionEx()
|
||||
|
||||
if not len(selection) >= 1:
|
||||
FreeCAD.Console.PrintError(translate("PathProject", "Please select at least one suitable object\n"))
|
||||
return
|
||||
for s in selection:
|
||||
if s.HasSubObjects:
|
||||
for i in s.SubElementNames:
|
||||
self.obj.Proxy.addbaseobject(self.obj, s.Object, i)
|
||||
else:
|
||||
self.obj.Proxy.addbaseobject(self.obj, s.Object)
|
||||
|
||||
self.setupUi() # defaults may have changed. Reload.
|
||||
self.form.baseList.clear()
|
||||
for i in self.obj.Base:
|
||||
self.form.baseList.addItem(i[0].Name + "." + i[1])
|
||||
|
||||
def deleteBase(self):
|
||||
dlist = self.form.baseList.selectedItems()
|
||||
for d in dlist:
|
||||
newlist = []
|
||||
for i in self.obj.Base:
|
||||
if not i[0].Name == d.text():
|
||||
newlist.append(i)
|
||||
self.obj.Base = newlist
|
||||
self.form.baseList.takeItem(self.form.baseList.row(d))
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def itemActivated(self):
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
slist = self.form.baseList.selectedItems()
|
||||
for i in slist:
|
||||
o = FreeCAD.ActiveDocument.getObject(i.text())
|
||||
FreeCADGui.Selection.addSelection(o)
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
def reorderBase(self):
|
||||
newlist = []
|
||||
for i in range(self.form.baseList.count()):
|
||||
s = self.form.baseList.item(i).text()
|
||||
obj = FreeCAD.ActiveDocument.getObject(s)
|
||||
newlist.append(obj)
|
||||
self.obj.Base = newlist
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def getStandardButtons(self):
|
||||
return int(QtGui.QDialogButtonBox.Ok)
|
||||
|
||||
def changeURL(self):
|
||||
from urlparse import urlparse
|
||||
t = self.form.remoteURL.text()
|
||||
if t == '' and self.obj.URL != '': # if the url was deleted, cleanup.
|
||||
self.obj.URL = ''
|
||||
|
||||
if urlparse(t).scheme != '' and t != self.obj.URL: # validate new url.
|
||||
self.obj.URL = t
|
||||
# next make sure the property fields reflect the current attached service
|
||||
for p in self.obj.proplist:
|
||||
print p
|
||||
|
||||
def setupUi(self):
|
||||
self.form.startDepth.setText(str(self.obj.StartDepth))
|
||||
self.form.finalDepth.setText(str(self.obj.FinalDepth))
|
||||
self.form.safeHeight.setText(str(self.obj.SafeHeight))
|
||||
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight))
|
||||
self.form.remoteURL.setText(str(self.obj.URL))
|
||||
|
||||
for i in self.obj.Base:
|
||||
self.form.baseList.addItem(i[0].Name)
|
||||
|
||||
# Connect Signals and Slots
|
||||
self.form.startDepth.editingFinished.connect(self.getFields)
|
||||
self.form.finalDepth.editingFinished.connect(self.getFields)
|
||||
self.form.safeHeight.editingFinished.connect(self.getFields)
|
||||
self.form.clearanceHeight.editingFinished.connect(self.getFields)
|
||||
|
||||
self.form.addBase.clicked.connect(self.addBase)
|
||||
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
|
||||
self.form.deleteBase.clicked.connect(self.deleteBase)
|
||||
self.form.reorderBase.clicked.connect(self.reorderBase)
|
||||
|
||||
self.form.remoteURL.editingFinished.connect(self.changeURL)
|
||||
|
||||
|
||||
class SelObserver:
|
||||
def __init__(self):
|
||||
import PathScripts.PathSelection as PST
|
||||
|
||||
def __del__(self):
|
||||
import PathScripts.PathSelection as PST
|
||||
PST.clear()
|
||||
|
||||
def addSelection(self, doc, obj, sub, pnt):
|
||||
FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')')
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Remote', CommandPathRemote())
|
||||
FreeCADGui.addCommand('Refresh_Path', _RefreshRemotePath())
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathRemote... done\n")
|
||||
@@ -25,44 +25,44 @@
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from FreeCAD import Vector
|
||||
#from FreeCAD import Vector
|
||||
|
||||
|
||||
def equals(p1, p2):
|
||||
'''returns True if vertexes have same coordinates within precision amount of digits '''
|
||||
precision = 12
|
||||
p = precision
|
||||
u = Vector(p1.X, p1.Y, p1.Z)
|
||||
v = Vector(p2.X, p2.Y, p2.Z)
|
||||
vector = (u.sub(v))
|
||||
isNull = (round(vector.x, p) == 0 and round(vector.y, p) == 0 and round(vector.z, p) == 0)
|
||||
return isNull
|
||||
# def equals(p1, p2):
|
||||
# '''returns True if vertexes have same coordinates within precision amount of digits '''
|
||||
# precision = 12
|
||||
# p = precision
|
||||
# u = Vector(p1.X, p1.Y, p1.Z)
|
||||
# v = Vector(p2.X, p2.Y, p2.Z)
|
||||
# vector = (u.sub(v))
|
||||
# isNull = (round(vector.x, p) == 0 and round(vector.y, p) == 0 and round(vector.z, p) == 0)
|
||||
# return isNull
|
||||
|
||||
|
||||
def segments(poly):
|
||||
''' A sequence of (x,y) numeric coordinates pairs '''
|
||||
return zip(poly, poly[1:] + [poly[0]])
|
||||
# def segments(poly):
|
||||
# ''' A sequence of (x,y) numeric coordinates pairs '''
|
||||
# return zip(poly, poly[1:] + [poly[0]])
|
||||
|
||||
|
||||
def check_clockwise(poly):
|
||||
'''
|
||||
check_clockwise(poly) a function for returning a boolean if the selected wire is clockwise or counter clockwise
|
||||
based on point order. poly = [(x1,y1),(x2,y2),(x3,y3)]
|
||||
'''
|
||||
clockwise = False
|
||||
if (sum(x0*y1 - x1*y0 for ((x0, y0), (x1, y1)) in segments(poly))) < 0:
|
||||
clockwise = not clockwise
|
||||
return clockwise
|
||||
# def check_clockwise(poly):
|
||||
# '''
|
||||
# check_clockwise(poly) a function for returning a boolean if the selected wire is clockwise or counter clockwise
|
||||
# based on point order. poly = [(x1,y1),(x2,y2),(x3,y3)]
|
||||
# '''
|
||||
# clockwise = False
|
||||
# if (sum(x0*y1 - x1*y0 for ((x0, y0), (x1, y1)) in segments(poly))) < 0:
|
||||
# clockwise = not clockwise
|
||||
# return clockwise
|
||||
|
||||
|
||||
class FGate:
|
||||
def allow(self, doc, obj, sub):
|
||||
return (sub[0:4] == 'Face')
|
||||
# class FGate:
|
||||
# def allow(self, doc, obj, sub):
|
||||
# return (sub[0:4] == 'Face')
|
||||
|
||||
|
||||
class VGate:
|
||||
def allow(self, doc, obj, sub):
|
||||
return (sub[0:6] == 'Vertex')
|
||||
# class VGate:
|
||||
# def allow(self, doc, obj, sub):
|
||||
# return (sub[0:6] == 'Vertex')
|
||||
|
||||
|
||||
class EGate:
|
||||
@@ -105,7 +105,7 @@ class DRILLGate:
|
||||
subobj = obj.getElement(sub)
|
||||
drillable = isinstance(subobj.Edges[0].Curve, Part.Circle)
|
||||
if str(subobj.Surface) == "<Cylinder object>":
|
||||
drillable = True
|
||||
drillable = subobj.isClosed()
|
||||
|
||||
if sub[0:4] == 'Edge':
|
||||
o = obj.getElement(sub)
|
||||
@@ -182,14 +182,14 @@ def contourselect():
|
||||
FreeCADGui.Selection.addSelectionGate(CONTOURGate())
|
||||
FreeCAD.Console.PrintWarning("Contour Select Mode\n")
|
||||
|
||||
def fselect():
|
||||
FreeCADGui.Selection.addSelectionGate(FGate())
|
||||
FreeCAD.Console.PrintWarning("Face Select Mode\n")
|
||||
# def fselect():
|
||||
# FreeCADGui.Selection.addSelectionGate(FGate())
|
||||
# FreeCAD.Console.PrintWarning("Face Select Mode\n")
|
||||
|
||||
|
||||
def vselect():
|
||||
FreeCADGui.Selection.addSelectionGate(VGate())
|
||||
FreeCAD.Console.PrintWarning("Vertex Select Mode\n")
|
||||
# def vselect():
|
||||
# FreeCADGui.Selection.addSelectionGate(VGate())
|
||||
# FreeCAD.Console.PrintWarning("Vertex Select Mode\n")
|
||||
|
||||
|
||||
def eselect():
|
||||
|
||||
@@ -1,401 +0,0 @@
|
||||
# -*- 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 PathScripts import PathUtils
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
__title__ = "Path Surface Operation"
|
||||
__author__ = "sliptonic (Brad Collette)"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
"""Path surface object and FreeCAD command"""
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
class ObjectStrategy:
|
||||
|
||||
def __init__(self, obj):
|
||||
obj.addProperty("App::PropertyLinkSubList", "Base", "Path", "The base geometry of this toolpath")
|
||||
obj.addProperty("App::PropertyBool", "Active", "Path", "Make False, to prevent operation from generating code")
|
||||
obj.addProperty("App::PropertyString", "Comment", "Path", "An optional comment for this profile")
|
||||
obj.addProperty("App::PropertyString", "UserLabel", "Path", "User Assigned Label")
|
||||
|
||||
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm", "The library to use to generate the path")
|
||||
obj.Algorithm = ['OCL Dropcutter', 'OCL Waterline']
|
||||
|
||||
# Tool Properties
|
||||
obj.addProperty("App::PropertyIntegerConstraint", "ToolNumber", "Tool", "The tool number in use")
|
||||
obj.ToolNumber = (0, 0, 1000, 0)
|
||||
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 onlyt
|
||||
|
||||
# Depth Properties
|
||||
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", "The height needed to clear clamps and obstructions")
|
||||
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", "Rapid Safety Height between locations.")
|
||||
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", "Incremental Step Down of Tool")
|
||||
obj.StepDown = (0.0, 0.01, 100.0, 0.5)
|
||||
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", "Starting Depth of Tool- first cut depth in Z")
|
||||
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", "Final Depth of Tool- lowest value in Z")
|
||||
obj.addProperty("App::PropertyDistance", "FinishDepth", "Depth", "Maximum material removed on final pass.")
|
||||
|
||||
obj.Proxy = self
|
||||
|
||||
def addbase(self, obj, ss, sub=""):
|
||||
baselist = obj.Base
|
||||
if len(baselist) == 0: # When adding the first base object, guess at heights
|
||||
try:
|
||||
bb = ss.Shape.BoundBox # parent boundbox
|
||||
subobj = ss.Shape.getElement(sub)
|
||||
fbb = subobj.BoundBox # feature boundbox
|
||||
obj.StartDepth = bb.ZMax
|
||||
obj.ClearanceHeight = bb.ZMax + 5.0
|
||||
obj.SafeHeight = bb.ZMax + 3.0
|
||||
|
||||
if fbb.ZMax < bb.ZMax:
|
||||
obj.FinalDepth = fbb.ZMax
|
||||
else:
|
||||
obj.FinalDepth = bb.ZMin
|
||||
except:
|
||||
obj.StartDepth = 5.0
|
||||
obj.ClearanceHeight = 10.0
|
||||
obj.SafeHeight = 8.0
|
||||
|
||||
item = (ss, sub)
|
||||
if item in baselist:
|
||||
FreeCAD.Console.PrintWarning(
|
||||
"this object already in the list" + "\n")
|
||||
else:
|
||||
baselist.append(item)
|
||||
obj.Base = baselist
|
||||
self.execute(obj)
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
return None
|
||||
|
||||
def execute(self, obj):
|
||||
output = ""
|
||||
|
||||
toolLoad = PathUtils.getLastToolLoad(obj)
|
||||
if toolLoad is None or toolLoad.ToolNumber == 0:
|
||||
self.vertFeed = 100
|
||||
self.horizFeed = 100
|
||||
self.vertRapid = 100
|
||||
self.horizRapid = 100
|
||||
self.radius = 0.25
|
||||
obj.ToolNumber = 0
|
||||
obj.ToolDescription = "UNDEFINED"
|
||||
else:
|
||||
self.vertFeed = toolLoad.VertFeed.Value
|
||||
self.horizFeed = toolLoad.HorizFeed.Value
|
||||
self.vertRapid = toolLoad.VertRapid.Value
|
||||
self.horizRapid = toolLoad.HorizRapid.Value
|
||||
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
|
||||
if tool.Diameter == 0:
|
||||
self.radius = 0.25
|
||||
else:
|
||||
self.radius = tool.Diameter/2
|
||||
obj.ToolNumber = toolLoad.ToolNumber
|
||||
obj.ToolDescription = toolLoad.Name
|
||||
|
||||
|
||||
output += "(" + obj.Label + ")"
|
||||
output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"
|
||||
|
||||
if obj.Active:
|
||||
path = Path.Path(output)
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = True
|
||||
|
||||
else:
|
||||
path = Path.Path("(inactive operation)")
|
||||
obj.Path = path
|
||||
obj.ViewObject.Visibility = False
|
||||
|
||||
class ViewProviderStrategy:
|
||||
|
||||
def __init__(self, obj): # mandatory
|
||||
# obj.addProperty("App::PropertyFloat","SomePropertyName","PropertyGroup","Description of this property")
|
||||
obj.Proxy = self
|
||||
|
||||
def __getstate__(self): # mandatory
|
||||
return None
|
||||
|
||||
def __setstate__(self, state): # mandatory
|
||||
return None
|
||||
|
||||
def getIcon(self): # optional
|
||||
return ":/icons/Path-Surfacing.svg"
|
||||
|
||||
def onChanged(self, obj, prop): # optional
|
||||
# this is executed when a property of the VIEW PROVIDER changes
|
||||
pass
|
||||
|
||||
def updateData(self, obj, prop): # optional
|
||||
# this is executed when a property of the APP OBJECT changes
|
||||
pass
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
taskd = TaskPanel()
|
||||
taskd.obj = vobj.Object
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
taskd.setupUi()
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode): # optional
|
||||
# this is executed when the user cancels or terminates edit mode
|
||||
pass
|
||||
|
||||
|
||||
class CommandPathStrategy:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Path-3DSurface',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Strategy", "Strategy"),
|
||||
'Accel': "P, D",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Strategy", "Creates a Path Strategy object")}
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument is not None:
|
||||
for o in FreeCAD.ActiveDocument.Objects:
|
||||
if o.Name[:3] == "Job":
|
||||
return True
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
|
||||
ztop = 10
|
||||
zbottom = 0
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Path_Strategy", "Create Strategy"))
|
||||
FreeCADGui.addModule("PathScripts.PathStrategy")
|
||||
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Strategy")')
|
||||
FreeCADGui.doCommand('PathScripts.PathStrategy.ObjectStrategy(obj)')
|
||||
FreeCADGui.doCommand('obj.Active = True')
|
||||
FreeCADGui.doCommand('PathScripts.PathStrategy.ViewProviderStrategy(obj.ViewObject)')
|
||||
FreeCADGui.doCommand('from PathScripts import PathUtils')
|
||||
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop + 2))
|
||||
FreeCADGui.doCommand('obj.StartDepth = ' + str(ztop))
|
||||
FreeCADGui.doCommand('obj.SafeHeight = ' + str(ztop + 2))
|
||||
FreeCADGui.doCommand('obj.StepDown = ' + str((ztop - zbottom) / 8))
|
||||
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
|
||||
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
|
||||
|
||||
|
||||
class TaskPanel:
|
||||
|
||||
def __init__(self):
|
||||
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/StrategyEdit.ui")
|
||||
#self.form = FreeCADGui.PySideUic.loadUi(":/panels/SurfaceEdit.ui")
|
||||
|
||||
def accept(self):
|
||||
self.getFields()
|
||||
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.Selection.removeObserver(self.s)
|
||||
|
||||
def reject(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.Selection.removeObserver(self.s)
|
||||
|
||||
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, "SafeHeight"):
|
||||
self.obj.SafeHeight = self.form.safeHeight.text()
|
||||
if hasattr(self.obj, "ClearanceHeight"):
|
||||
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
|
||||
|
||||
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))
|
||||
|
||||
for i in self.obj.Base:
|
||||
self.form.baseList.addItem(i[0].Name)
|
||||
|
||||
def open(self):
|
||||
self.s = SelObserver()
|
||||
# install the function mode resident
|
||||
FreeCADGui.Selection.addObserver(self.s)
|
||||
|
||||
def addBase(self):
|
||||
# check that the selection contains exactly what we want
|
||||
selection = FreeCADGui.Selection.getSelectionEx()
|
||||
if len(selection) != 1:
|
||||
FreeCAD.Console.PrintError(translate(
|
||||
"PathSurface", "Please select a single solid object from the project tree\n"))
|
||||
return
|
||||
|
||||
if not len(selection[0].SubObjects) == 0:
|
||||
FreeCAD.Console.PrintError(translate(
|
||||
"PathSurface", "Please select a single solid object from the project tree\n"))
|
||||
return
|
||||
|
||||
sel = selection[0].Object
|
||||
# get type of object
|
||||
# if sel.TypeId.startswith('Mesh'):
|
||||
# # it is a mesh already
|
||||
# print 'was already mesh'
|
||||
|
||||
# elif sel.TypeId.startswith('Part') and \
|
||||
# (sel.Shape.BoundBox.XLength > 0) and \
|
||||
# (sel.Shape.BoundBox.YLength > 0) and \
|
||||
# (sel.Shape.BoundBox.ZLength > 0):
|
||||
# print 'this is a solid Part object'
|
||||
|
||||
# else:
|
||||
# FreeCAD.Console.PrintError(
|
||||
# translate("PathSurface", "Cannot work with this object\n"))
|
||||
# return
|
||||
|
||||
self.obj.Proxy.addbase(self.obj, sel)
|
||||
|
||||
self.setFields() # defaults may have changed. Reload.
|
||||
self.form.baseList.clear()
|
||||
for i in self.obj.Base:
|
||||
self.form.baseList.addItem(i[0].Name)
|
||||
|
||||
def deleteBase(self):
|
||||
dlist = self.form.baseList.selectedItems()
|
||||
for d in dlist:
|
||||
newlist = []
|
||||
for i in self.obj.Base:
|
||||
if not i[0].Name == d.text():
|
||||
newlist.append(i)
|
||||
self.obj.Base = newlist
|
||||
self.form.baseList.takeItem(self.form.baseList.row(d))
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def itemActivated(self):
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
slist = self.form.baseList.selectedItems()
|
||||
for i in slist:
|
||||
o = FreeCAD.ActiveDocument.getObject(i.text())
|
||||
FreeCADGui.Selection.addSelection(o)
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
def reorderBase(self):
|
||||
newlist = []
|
||||
for i in range(self.form.baseList.count()):
|
||||
s = self.form.baseList.item(i).text()
|
||||
obj = FreeCAD.ActiveDocument.getObject(s)
|
||||
newlist.append(obj)
|
||||
self.obj.Base = newlist
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def getStandardButtons(self):
|
||||
return int(QtGui.QDialogButtonBox.Ok)
|
||||
|
||||
def setupUi(self):
|
||||
|
||||
# Connect Signals and Slots
|
||||
|
||||
#Base Geometry
|
||||
self.form.addBase.clicked.connect(self.addBase)
|
||||
self.form.deleteBase.clicked.connect(self.deleteBase)
|
||||
self.form.reorderBase.clicked.connect(self.reorderBase)
|
||||
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
|
||||
|
||||
# Depths
|
||||
self.form.startDepth.editingFinished.connect(self.getFields)
|
||||
self.form.finalDepth.editingFinished.connect(self.getFields)
|
||||
self.form.finishDepth.editingFinished.connect(self.getFields)
|
||||
self.form.stepDown.editingFinished.connect(self.getFields)
|
||||
|
||||
# Heights
|
||||
self.form.safeHeight.editingFinished.connect(self.getFields)
|
||||
self.form.clearanceHeight.editingFinished.connect(self.getFields)
|
||||
|
||||
sel = FreeCADGui.Selection.getSelectionEx()
|
||||
self.setFields()
|
||||
|
||||
if len(sel) != 0:
|
||||
self.addBase()
|
||||
|
||||
|
||||
class SelObserver:
|
||||
|
||||
def __init__(self):
|
||||
import PathScripts.PathSelection as PST
|
||||
PST.surfaceselect()
|
||||
|
||||
def __del__(self):
|
||||
import PathScripts.PathSelection as PST
|
||||
PST.clear()
|
||||
|
||||
def addSelection(self, doc, obj, sub, pnt): # Selection object
|
||||
FreeCADGui.doCommand(
|
||||
'Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')')
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Strategy', CommandPathStrategy())
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathStrategy... done\n")
|
||||
@@ -139,7 +139,7 @@ class ToolLibraryManager():
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
self.ToolLibrary = []
|
||||
# self.ToolLibrary = []
|
||||
self.prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path")
|
||||
return
|
||||
|
||||
@@ -311,20 +311,20 @@ class ToolLibraryManager():
|
||||
self.saveMainLibrary(tt)
|
||||
return True
|
||||
|
||||
def createToolController(self, job, tool):
|
||||
pass
|
||||
# def createToolController(self, job, tool):
|
||||
# pass
|
||||
|
||||
def exportListHeeks(self, tooltable):
|
||||
'''exports one or more Lists as a HeeksCNC tooltable'''
|
||||
pass
|
||||
# def exportListHeeks(self, tooltable):
|
||||
# '''exports one or more Lists as a HeeksCNC tooltable'''
|
||||
# pass
|
||||
|
||||
def exportListLinuxCNC(self, tooltable):
|
||||
'''exports one or more Lists as a LinuxCNC tooltable'''
|
||||
pass
|
||||
# def exportListLinuxCNC(self, tooltable):
|
||||
# '''exports one or more Lists as a LinuxCNC tooltable'''
|
||||
# pass
|
||||
|
||||
def exportListXML(self, tooltable):
|
||||
'''exports one or more Lists as an XML file'''
|
||||
pass
|
||||
# def exportListXML(self, tooltable):
|
||||
# '''exports one or more Lists as an XML file'''
|
||||
# pass
|
||||
|
||||
class EditorPanel():
|
||||
def __init__(self):
|
||||
@@ -356,7 +356,6 @@ class EditorPanel():
|
||||
pass
|
||||
|
||||
def getType(self, tooltype):
|
||||
print("tooltype: ", tooltype)
|
||||
"gets a combobox index number for a given type or viceversa"
|
||||
toolslist = ["Drill", "CenterDrill", "CounterSink", "CounterBore",
|
||||
"Reamer", "Tap", "EndMill", "SlotCutter", "BallEndMill",
|
||||
@@ -389,8 +388,9 @@ class EditorPanel():
|
||||
|
||||
def addTool(self):
|
||||
t = Path.Tool()
|
||||
print (t)
|
||||
print ("adding a new tool")
|
||||
editform = FreeCADGui.PySideUic.loadUi(":/panels/ToolEdit.ui")
|
||||
|
||||
r = editform.exec_()
|
||||
if r:
|
||||
if editform.NameField.text():
|
||||
|
||||
@@ -26,15 +26,15 @@ import FreeCAD
|
||||
import FreeCADGui
|
||||
import Part
|
||||
import math
|
||||
import Draft
|
||||
import Path
|
||||
import TechDraw
|
||||
# import Draft
|
||||
# import Path
|
||||
# import TechDraw
|
||||
from DraftGeomUtils import geomType
|
||||
from DraftGeomUtils import findWires
|
||||
import DraftVecUtils
|
||||
# from DraftGeomUtils import findWires
|
||||
# import DraftVecUtils
|
||||
import PathScripts
|
||||
from PathScripts import PathJob
|
||||
import itertools
|
||||
# import itertools
|
||||
|
||||
def cleanedges(splines, precision):
|
||||
'''cleanedges([splines],precision). Convert BSpline curves, Beziers, to arcs that can be used for cnc paths.
|
||||
@@ -88,89 +88,88 @@ def curvetowire(obj, steps):
|
||||
def fmt(val): return format(val, '.4f')
|
||||
|
||||
|
||||
def getProjected(shape,direction):
|
||||
"returns projected edges from a shape and a direction"
|
||||
import Part,Drawing
|
||||
edges = []
|
||||
groups = Drawing.projectEx(shape,direction)
|
||||
for g in groups[0:5]:
|
||||
if g:
|
||||
edges.append(g)
|
||||
# if hasattr(obj,"Tessellation") and obj.Tessellation:
|
||||
# return DraftGeomUtils.cleanProjection(Part.makeCompound(edges),obj.Tessellation,obj.SegmentLength)
|
||||
# else:
|
||||
return Part.makeCompound(edges)
|
||||
# def getProjected(shape,direction):
|
||||
# "returns projected edges from a shape and a direction"
|
||||
# import Part,Drawing
|
||||
# edges = []
|
||||
# groups = Drawing.projectEx(shape,direction)
|
||||
# for g in groups[0:5]:
|
||||
# if g:
|
||||
# edges.append(g)
|
||||
# # if hasattr(obj,"Tessellation") and obj.Tessellation:
|
||||
# # return DraftGeomUtils.cleanProjection(Part.makeCompound(edges),obj.Tessellation,obj.SegmentLength)
|
||||
# # else:
|
||||
# return Part.makeCompound(edges)
|
||||
|
||||
|
||||
def silhouette(obj):
|
||||
from FreeCAD import Vector
|
||||
s = getProjected(obj.Shape, Vector(0,0,1))
|
||||
print s
|
||||
w = TechDraw.findOuterWire(s.Edges)
|
||||
return w
|
||||
# def silhouette(obj):
|
||||
# from FreeCAD import Vector
|
||||
# s = getProjected(obj.Shape, Vector(0,0,1))
|
||||
# w = TechDraw.findOuterWire(s.Edges)
|
||||
# return w
|
||||
|
||||
def isSameEdge(e1, e2):
|
||||
"""isSameEdge(e1,e2): return True if the 2 edges are both lines or arcs/circles and have the same
|
||||
points - inspired by Yorik's function isSameLine"""
|
||||
if not (isinstance(e1.Curve, Part.LineSegment) or isinstance(e1.Curve, Part.Circle)):
|
||||
return False
|
||||
if not (isinstance(e2.Curve, Part.LineSegment) or isinstance(e2.Curve, Part.Circle)):
|
||||
return False
|
||||
if type(e1.Curve) != type(e2.Curve):
|
||||
return False
|
||||
if isinstance(e1.Curve, Part.LineSegment):
|
||||
if (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point)):
|
||||
return True
|
||||
elif (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point)):
|
||||
return True
|
||||
if isinstance(e1.Curve, Part.Circle):
|
||||
center = False
|
||||
radius = False
|
||||
endpts = False
|
||||
if e1.Curve.Center == e2.Curve.Center:
|
||||
center = True
|
||||
if e1.Curve.Radius == e2.Curve.Radius:
|
||||
radius = True
|
||||
if (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point)):
|
||||
endpts = True
|
||||
elif (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point)) and \
|
||||
(DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point)):
|
||||
endpts = True
|
||||
if (center and radius and endpts):
|
||||
return True
|
||||
return False
|
||||
# def isSameEdge(e1, e2):
|
||||
# """isSameEdge(e1,e2): return True if the 2 edges are both lines or arcs/circles and have the same
|
||||
# points - inspired by Yorik's function isSameLine"""
|
||||
# if not (isinstance(e1.Curve, Part.Line) or isinstance(e1.Curve, Part.Circle)):
|
||||
# return False
|
||||
# if not (isinstance(e2.Curve, Part.Line) or isinstance(e2.Curve, Part.Circle)):
|
||||
# return False
|
||||
# if type(e1.Curve) != type(e2.Curve):
|
||||
# return False
|
||||
# if isinstance(e1.Curve, Part.Line):
|
||||
# if (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point)) and \
|
||||
# (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point)):
|
||||
# return True
|
||||
# elif (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point)) and \
|
||||
# (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point)):
|
||||
# return True
|
||||
# if isinstance(e1.Curve, Part.Circle):
|
||||
# center = False
|
||||
# radius = False
|
||||
# endpts = False
|
||||
# if e1.Curve.Center == e2.Curve.Center:
|
||||
# center = True
|
||||
# if e1.Curve.Radius == e2.Curve.Radius:
|
||||
# radius = True
|
||||
# if (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point)) and \
|
||||
# (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point)):
|
||||
# endpts = True
|
||||
# elif (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point)) and \
|
||||
# (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point)):
|
||||
# endpts = True
|
||||
# if (center and radius and endpts):
|
||||
# return True
|
||||
# return False
|
||||
|
||||
|
||||
def segments(poly):
|
||||
''' A sequence of (x,y) numeric coordinates pairs '''
|
||||
return zip(poly, poly[1:] + [poly[0]])
|
||||
|
||||
def is_clockwise(obj):
|
||||
'''tests if a wire or Path is clockwise'''
|
||||
sum = 0
|
||||
if isinstance(obj, Part.Wire):
|
||||
for first, second in itertools.izip(obj.Edges, obj.Edges[1:]):
|
||||
sum = (second.Vertexes[0].X - first.Vertexes[0].X) * (second.Vertexes[0].Y + first.Vertexes[0].Y)
|
||||
sum += (obj.Edges[0].Vertexes[0].X - obj.Edges[-1].Vertexes[0].X) * (obj.Edges[0].Vertexes[0].Y + obj.Edges[-1].Vertexes[0].Y)
|
||||
elif isinstance(obj, Path.Path):
|
||||
movecommands = ['G1', 'G01', 'G2', 'G02', 'G3', 'G03']
|
||||
# def is_clockwise(obj):
|
||||
# '''tests if a wire or Path is clockwise'''
|
||||
# sum = 0
|
||||
# if isinstance(obj, Part.Wire):
|
||||
# for first, second in itertools.izip(obj.Edges, obj.Edges[1:]):
|
||||
# sum = (second.Vertexes[0].X - first.Vertexes[0].X) * (second.Vertexes[0].Y + first.Vertexes[0].Y)
|
||||
# sum += (obj.Edges[0].Vertexes[0].X - obj.Edges[-1].Vertexes[0].X) * (obj.Edges[0].Vertexes[0].Y + obj.Edges[-1].Vertexes[0].Y)
|
||||
# elif isinstance(obj, Path.Path):
|
||||
# movecommands = ['G1', 'G01', 'G2', 'G02', 'G3', 'G03']
|
||||
|
||||
lastLocation = {'Y': 0, 'X': 0, 'Z': 0.0}
|
||||
currLocation = {'Y': 0, 'X': 0, 'Z': 0.0}
|
||||
sum = 0
|
||||
# lastLocation = {'Y': 0, 'X': 0, 'Z': 0.0}
|
||||
# currLocation = {'Y': 0, 'X': 0, 'Z': 0.0}
|
||||
# sum = 0
|
||||
|
||||
for curCommand in obj.Commands:
|
||||
# for curCommand in obj.Commands:
|
||||
|
||||
if curCommand.Name in movecommands:
|
||||
lastLocation.update(currLocation)
|
||||
currLocation.update(curCommand.Parameters)
|
||||
sum += (currLocation["X"] - lastLocation["X"]) * (currLocation["Y"] + lastLocation["Y"])
|
||||
sum += (0 - lastLocation["X"]) * (0 + lastLocation["Y"])
|
||||
# if curCommand.Name in movecommands:
|
||||
# lastLocation.update(currLocation)
|
||||
# currLocation.update(curCommand.Parameters)
|
||||
# sum += (currLocation["X"] - lastLocation["X"]) * (currLocation["Y"] + lastLocation["Y"])
|
||||
# sum += (0 - lastLocation["X"]) * (0 + lastLocation["Y"])
|
||||
|
||||
return sum >= 0
|
||||
# return sum >= 0
|
||||
|
||||
def loopdetect(obj, edge1, edge2):
|
||||
'''
|
||||
@@ -192,15 +191,15 @@ def loopdetect(obj, edge1, edge2):
|
||||
return loopwire
|
||||
|
||||
|
||||
def check_clockwise(poly):
|
||||
'''
|
||||
check_clockwise(poly) a function for returning a boolean if the selected wire is clockwise or counter clockwise
|
||||
based on point order. poly = [(x1,y1),(x2,y2),(x3,y3)]
|
||||
'''
|
||||
clockwise = False
|
||||
if (sum(x0 * y1 - x1 * y0 for ((x0, y0), (x1, y1)) in segments(poly))) < 0:
|
||||
clockwise = not clockwise
|
||||
return clockwise
|
||||
# def check_clockwise(poly):
|
||||
# '''
|
||||
# check_clockwise(poly) a function for returning a boolean if the selected wire is clockwise or counter clockwise
|
||||
# based on point order. poly = [(x1,y1),(x2,y2),(x3,y3)]
|
||||
# '''
|
||||
# clockwise = False
|
||||
# if (sum(x0 * y1 - x1 * y0 for ((x0, y0), (x1, y1)) in segments(poly))) < 0:
|
||||
# clockwise = not clockwise
|
||||
# return clockwise
|
||||
|
||||
|
||||
def filterArcs(arcEdge):
|
||||
@@ -254,235 +253,235 @@ def reverseEdge(e):
|
||||
|
||||
return newedge
|
||||
|
||||
def edge_to_path(lastpt, edge, Z, hf=2.0):
|
||||
if isinstance(edge.Curve, Part.Circle):
|
||||
# FreeCAD.Console.PrintMessage("arc\n")
|
||||
arcstartpt = edge.valueAt(edge.FirstParameter)
|
||||
midpt = edge.valueAt(
|
||||
(edge.FirstParameter + edge.LastParameter) * 0.5)
|
||||
arcendpt = edge.valueAt(edge.LastParameter)
|
||||
# arcchkpt = edge.valueAt(edge.LastParameter * .99)
|
||||
# def edge_to_path(lastpt, edge, Z, hf=2.0):
|
||||
# if isinstance(edge.Curve, Part.Circle):
|
||||
# # FreeCAD.Console.PrintMessage("arc\n")
|
||||
# arcstartpt = edge.valueAt(edge.FirstParameter)
|
||||
# midpt = edge.valueAt(
|
||||
# (edge.FirstParameter + edge.LastParameter) * 0.5)
|
||||
# arcendpt = edge.valueAt(edge.LastParameter)
|
||||
# # arcchkpt = edge.valueAt(edge.LastParameter * .99)
|
||||
|
||||
if DraftVecUtils.equals(lastpt, arcstartpt):
|
||||
startpt = arcstartpt
|
||||
endpt = arcendpt
|
||||
else:
|
||||
startpt = arcendpt
|
||||
endpt = arcstartpt
|
||||
center = edge.Curve.Center
|
||||
relcenter = center.sub(lastpt)
|
||||
# FreeCAD.Console.PrintMessage("arc startpt= " + str(startpt)+ "\n")
|
||||
# FreeCAD.Console.PrintMessage("arc midpt= " + str(midpt)+ "\n")
|
||||
# FreeCAD.Console.PrintMessage("arc endpt= " + str(endpt)+ "\n")
|
||||
arc_cw = check_clockwise(
|
||||
[(startpt.x, startpt.y), (midpt.x, midpt.y), (endpt.x, endpt.y)])
|
||||
# FreeCAD.Console.PrintMessage("arc_cw="+ str(arc_cw)+"\n")
|
||||
if arc_cw:
|
||||
output = "G2"
|
||||
else:
|
||||
output = "G3"
|
||||
output += " X" + str(fmt(endpt.x)) + " Y" + \
|
||||
str(fmt(endpt.y)) + " Z" + str(fmt(Z)) + " F" + str(hf)
|
||||
output += " I" + str(fmt(relcenter.x)) + " J" + \
|
||||
str(fmt(relcenter.y)) + " K" + str(fmt(relcenter.z))
|
||||
output += "\n"
|
||||
lastpt = endpt
|
||||
# FreeCAD.Console.PrintMessage("last pt arc= " + str(lastpt)+ "\n")
|
||||
else:
|
||||
point = edge.Vertexes[-1].Point
|
||||
if DraftVecUtils.equals(point, lastpt): # edges can come flipped
|
||||
point = edge.Vertexes[0].Point
|
||||
output = "G1 X" + str(fmt(point.x)) + " Y" + str(fmt(point.y)) + \
|
||||
" Z" + str(fmt(Z)) + " F" + str(hf) + "\n"
|
||||
lastpt = point
|
||||
# FreeCAD.Console.PrintMessage("line\n")
|
||||
# FreeCAD.Console.PrintMessage("last pt line= " + str(lastpt)+ "\n")
|
||||
return lastpt, output
|
||||
# if DraftVecUtils.equals(lastpt, arcstartpt):
|
||||
# startpt = arcstartpt
|
||||
# endpt = arcendpt
|
||||
# else:
|
||||
# startpt = arcendpt
|
||||
# endpt = arcstartpt
|
||||
# center = edge.Curve.Center
|
||||
# relcenter = center.sub(lastpt)
|
||||
# # FreeCAD.Console.PrintMessage("arc startpt= " + str(startpt)+ "\n")
|
||||
# # FreeCAD.Console.PrintMessage("arc midpt= " + str(midpt)+ "\n")
|
||||
# # FreeCAD.Console.PrintMessage("arc endpt= " + str(endpt)+ "\n")
|
||||
# arc_cw = check_clockwise(
|
||||
# [(startpt.x, startpt.y), (midpt.x, midpt.y), (endpt.x, endpt.y)])
|
||||
# # FreeCAD.Console.PrintMessage("arc_cw="+ str(arc_cw)+"\n")
|
||||
# if arc_cw:
|
||||
# output = "G2"
|
||||
# else:
|
||||
# output = "G3"
|
||||
# output += " X" + str(fmt(endpt.x)) + " Y" + \
|
||||
# str(fmt(endpt.y)) + " Z" + str(fmt(Z)) + " F" + str(hf)
|
||||
# output += " I" + str(fmt(relcenter.x)) + " J" + \
|
||||
# str(fmt(relcenter.y)) + " K" + str(fmt(relcenter.z))
|
||||
# output += "\n"
|
||||
# lastpt = endpt
|
||||
# # FreeCAD.Console.PrintMessage("last pt arc= " + str(lastpt)+ "\n")
|
||||
# else:
|
||||
# point = edge.Vertexes[-1].Point
|
||||
# if DraftVecUtils.equals(point, lastpt): # edges can come flipped
|
||||
# point = edge.Vertexes[0].Point
|
||||
# output = "G1 X" + str(fmt(point.x)) + " Y" + str(fmt(point.y)) + \
|
||||
# " Z" + str(fmt(Z)) + " F" + str(hf) + "\n"
|
||||
# lastpt = point
|
||||
# # FreeCAD.Console.PrintMessage("line\n")
|
||||
# # FreeCAD.Console.PrintMessage("last pt line= " + str(lastpt)+ "\n")
|
||||
# return lastpt, output
|
||||
|
||||
|
||||
def convert(toolpath, Z=0.0, PlungeAngle=90.0, Zprevious=None, StopLength=None, vf=1.0, hf=2.0) :
|
||||
'''convert(toolpath,Z=0.0,vf=1.0,hf=2.0,PlungeAngle=90.0,Zprevious=None,StopLength=None) Converts lines and arcs to G1,G2,G3 moves. Returns a string.'''
|
||||
# def convert(toolpath, Z=0.0, PlungeAngle=90.0, Zprevious=None, StopLength=None, vf=1.0, hf=2.0) :
|
||||
# '''convert(toolpath,Z=0.0,vf=1.0,hf=2.0,PlungeAngle=90.0,Zprevious=None,StopLength=None) Converts lines and arcs to G1,G2,G3 moves. Returns a string.'''
|
||||
|
||||
if PlungeAngle != 90.0:
|
||||
if Zprevious is None:
|
||||
raise Exception("Cannot use PlungeAngle != 90.0 degrees without parameter Zprevious")
|
||||
tanA = math.tan(math.pi * PlungeAngle / 180.0)
|
||||
minA = (Zprevious - Z) / sum(edge.Length for edge in toolpath)
|
||||
if tanA < minA:
|
||||
tanA = minA
|
||||
#FreeCAD.Console.PrintMessage('Increasing ramp angle to {0} degrees, to be able to make a full round\n'.format(math.atan(tanA) * 180.0 / math.pi))
|
||||
else:
|
||||
Zprevious = Z
|
||||
# if PlungeAngle != 90.0:
|
||||
# if Zprevious is None:
|
||||
# raise Exception("Cannot use PlungeAngle != 90.0 degrees without parameter Zprevious")
|
||||
# tanA = math.tan(math.pi * PlungeAngle / 180.0)
|
||||
# minA = (Zprevious - Z) / sum(edge.Length for edge in toolpath)
|
||||
# if tanA < minA:
|
||||
# tanA = minA
|
||||
# #FreeCAD.Console.PrintMessage('Increasing ramp angle to {0} degrees, to be able to make a full round\n'.format(math.atan(tanA) * 180.0 / math.pi))
|
||||
# else:
|
||||
# Zprevious = Z
|
||||
|
||||
lastpt = None
|
||||
output = ""
|
||||
path_length = 0.0
|
||||
Z_cur = Zprevious
|
||||
# lastpt = None
|
||||
# output = ""
|
||||
# path_length = 0.0
|
||||
# Z_cur = Zprevious
|
||||
|
||||
# create the path from the offset shape
|
||||
for edge in toolpath:
|
||||
if not lastpt:
|
||||
# set the first point
|
||||
lastpt = edge.Vertexes[0].Point
|
||||
# FreeCAD.Console.PrintMessage("last pt= " + str(lastpt)+ "\n")
|
||||
output += "G1 X" + str(fmt(lastpt.x)) + " Y" + str(fmt(lastpt.y)) + \
|
||||
" Z" + str(fmt(Z_cur)) + " F" + str(vf) + "\n"
|
||||
# # create the path from the offset shape
|
||||
# for edge in toolpath:
|
||||
# if not lastpt:
|
||||
# # set the first point
|
||||
# lastpt = edge.Vertexes[0].Point
|
||||
# # FreeCAD.Console.PrintMessage("last pt= " + str(lastpt)+ "\n")
|
||||
# output += "G1 X" + str(fmt(lastpt.x)) + " Y" + str(fmt(lastpt.y)) + \
|
||||
# " Z" + str(fmt(Z_cur)) + " F" + str(vf) + "\n"
|
||||
|
||||
if StopLength:
|
||||
if path_length + edge.Length > StopLength:
|
||||
# have to split current edge in two
|
||||
t0 = edge.FirstParameter
|
||||
t1 = edge.LastParameter
|
||||
dL = StopLength - path_length
|
||||
t = t0 + (t1 - t0) * dL / edge.Length
|
||||
assert(t0 < t < t1)
|
||||
edge = edge.split(t).Edges[0]
|
||||
path_length = StopLength
|
||||
else:
|
||||
path_length += edge.Length
|
||||
else:
|
||||
path_length += edge.Length
|
||||
# if StopLength:
|
||||
# if path_length + edge.Length > StopLength:
|
||||
# # have to split current edge in two
|
||||
# t0 = edge.FirstParameter
|
||||
# t1 = edge.LastParameter
|
||||
# dL = StopLength - path_length
|
||||
# t = t0 + (t1 - t0) * dL / edge.Length
|
||||
# assert(t0 < t < t1)
|
||||
# edge = edge.split(t).Edges[0]
|
||||
# path_length = StopLength
|
||||
# else:
|
||||
# path_length += edge.Length
|
||||
# else:
|
||||
# path_length += edge.Length
|
||||
|
||||
if Z_cur > Z:
|
||||
Z_next = Zprevious - path_length * tanA
|
||||
if Z_next < Z:
|
||||
# have to split current edge in two
|
||||
t0 = edge.FirstParameter
|
||||
t1 = edge.LastParameter
|
||||
dZ = Z_cur - Z
|
||||
t = t0 + (t1 - t0) * (dZ / tanA) / edge.Length
|
||||
assert(t0 < t < t1)
|
||||
subwire = edge.split(t)
|
||||
assert(len(subwire.Edges) == 2)
|
||||
Z_cur = Z
|
||||
lastpt, codes = edge_to_path(lastpt, subwire.Edges[0], Z_cur, hf)
|
||||
output += codes
|
||||
edge = subwire.Edges[1]
|
||||
else:
|
||||
Z_cur = Z_next
|
||||
# if Z_cur > Z:
|
||||
# Z_next = Zprevious - path_length * tanA
|
||||
# if Z_next < Z:
|
||||
# # have to split current edge in two
|
||||
# t0 = edge.FirstParameter
|
||||
# t1 = edge.LastParameter
|
||||
# dZ = Z_cur - Z
|
||||
# t = t0 + (t1 - t0) * (dZ / tanA) / edge.Length
|
||||
# assert(t0 < t < t1)
|
||||
# subwire = edge.split(t)
|
||||
# assert(len(subwire.Edges) == 2)
|
||||
# Z_cur = Z
|
||||
# lastpt, codes = edge_to_path(lastpt, subwire.Edges[0], Z_cur, hf)
|
||||
# output += codes
|
||||
# edge = subwire.Edges[1]
|
||||
# else:
|
||||
# Z_cur = Z_next
|
||||
|
||||
lastpt, codes = edge_to_path(lastpt, edge, Z_cur, hf)
|
||||
output += codes
|
||||
# lastpt, codes = edge_to_path(lastpt, edge, Z_cur, hf)
|
||||
# output += codes
|
||||
|
||||
if StopLength:
|
||||
if path_length >= StopLength:
|
||||
break
|
||||
# if StopLength:
|
||||
# if path_length >= StopLength:
|
||||
# break
|
||||
|
||||
return output
|
||||
# return output
|
||||
|
||||
def SortPath(wire, Side, radius, clockwise, firstedge=None, SegLen=0.5):
|
||||
'''SortPath(wire,Side,radius,clockwise,firstedge=None,SegLen =0.5) Sorts the wire and reverses it, if needed. Splits arcs over 180 degrees in two. Returns the reordered offset of the wire. '''
|
||||
if firstedge:
|
||||
edgelist = wire.Edges[:]
|
||||
if wire.isClosed():
|
||||
elindex = None
|
||||
n = 0
|
||||
for e in edgelist:
|
||||
if isSameEdge(e, firstedge):
|
||||
# FreeCAD.Console.PrintMessage('found first edge\n')
|
||||
elindex = n
|
||||
n = n + 1
|
||||
l1 = edgelist[:elindex]
|
||||
l2 = edgelist[elindex:]
|
||||
newedgelist = l2 + l1
|
||||
# def SortPath(wire, Side, radius, clockwise, firstedge=None, SegLen=0.5):
|
||||
# '''SortPath(wire,Side,radius,clockwise,firstedge=None,SegLen =0.5) Sorts the wire and reverses it, if needed. Splits arcs over 180 degrees in two. Returns the reordered offset of the wire. '''
|
||||
# if firstedge:
|
||||
# edgelist = wire.Edges[:]
|
||||
# if wire.isClosed():
|
||||
# elindex = None
|
||||
# n = 0
|
||||
# for e in edgelist:
|
||||
# if isSameEdge(e, firstedge):
|
||||
# # FreeCAD.Console.PrintMessage('found first edge\n')
|
||||
# elindex = n
|
||||
# n = n + 1
|
||||
# l1 = edgelist[:elindex]
|
||||
# l2 = edgelist[elindex:]
|
||||
# newedgelist = l2 + l1
|
||||
|
||||
if clockwise:
|
||||
newedgelist.reverse()
|
||||
last = newedgelist.pop(-1)
|
||||
newedgelist.insert(0, last)
|
||||
# if clockwise:
|
||||
# newedgelist.reverse()
|
||||
# last = newedgelist.pop(-1)
|
||||
# newedgelist.insert(0, last)
|
||||
|
||||
preoffset = []
|
||||
for e in newedgelist:
|
||||
if clockwise:
|
||||
r = reverseEdge(e)
|
||||
preoffset.append(r)
|
||||
else:
|
||||
preoffset.append(e)
|
||||
# preoffset = []
|
||||
# for e in newedgelist:
|
||||
# if clockwise:
|
||||
# r = reverseEdge(e)
|
||||
# preoffset.append(r)
|
||||
# else:
|
||||
# preoffset.append(e)
|
||||
|
||||
sortedpreoff = Part.__sortEdges__(preoffset)
|
||||
wire = Part.Wire(sortedpreoff)
|
||||
#wire = findWires(sortedpreoff)[0]
|
||||
else:
|
||||
sortedpreoff = Part.__sortEdges__(edgelist)
|
||||
wire = Part.Wire(sortedpreoff)
|
||||
#wire = findWires(sortedpreoff)[0]
|
||||
# sortedpreoff = Part.__sortEdges__(preoffset)
|
||||
# wire = Part.Wire(sortedpreoff)
|
||||
# #wire = findWires(sortedpreoff)[0]
|
||||
# else:
|
||||
# sortedpreoff = Part.__sortEdges__(edgelist)
|
||||
# wire = Part.Wire(sortedpreoff)
|
||||
# #wire = findWires(sortedpreoff)[0]
|
||||
|
||||
edgelist = []
|
||||
for e in wire.Edges:
|
||||
if geomType(e) == "Circle":
|
||||
arclist = filterArcs(e)
|
||||
for a in arclist:
|
||||
edgelist.append(a)
|
||||
elif geomType(e) == "LineSegment":
|
||||
edgelist.append(e)
|
||||
elif geomType(e) == "BSplineCurve" or \
|
||||
geomType(e) == "BezierCurve" or \
|
||||
geomType(e) == "Ellipse":
|
||||
edgelist.append(Part.Wire(curvetowire(e, (SegLen))))
|
||||
#newwire = Part.Wire(edgelist)
|
||||
sortededges = Part.__sortEdges__(edgelist)
|
||||
newwire = findWires(sortededges)[0]
|
||||
# edgelist = []
|
||||
# for e in wire.Edges:
|
||||
# if geomType(e) == "Circle":
|
||||
# arclist = filterArcs(e)
|
||||
# for a in arclist:
|
||||
# edgelist.append(a)
|
||||
# elif geomType(e) == "LineSegment":
|
||||
# edgelist.append(e)
|
||||
# elif geomType(e) == "BSplineCurve" or \
|
||||
# geomType(e) == "BezierCurve" or \
|
||||
# geomType(e) == "Ellipse":
|
||||
# edgelist.append(Part.Wire(curvetowire(e, (SegLen))))
|
||||
# #newwire = Part.Wire(edgelist)
|
||||
# sortededges = Part.__sortEdges__(edgelist)
|
||||
# newwire = findWires(sortededges)[0]
|
||||
|
||||
if is_clockwise(newwire) is not clockwise:
|
||||
newwire.reverse()
|
||||
# if is_clockwise(newwire) is not clockwise:
|
||||
# newwire.reverse()
|
||||
|
||||
if Side == 'Left':
|
||||
# we use the OCC offset feature
|
||||
offset = newwire.makeOffset(radius) # tool is outside line
|
||||
elif Side == 'Right':
|
||||
offset = newwire.makeOffset(-radius) # tool is inside line
|
||||
else:
|
||||
if wire.isClosed():
|
||||
offset = newwire.makeOffset(0.0)
|
||||
else:
|
||||
offset = newwire
|
||||
offset.reverse()
|
||||
# if Side == 'Left':
|
||||
# # we use the OCC offset feature
|
||||
# offset = newwire.makeOffset(radius) # tool is outside line
|
||||
# elif Side == 'Right':
|
||||
# offset = newwire.makeOffset(-radius) # tool is inside line
|
||||
# else:
|
||||
# if wire.isClosed():
|
||||
# offset = newwire.makeOffset(0.0)
|
||||
# else:
|
||||
# offset = newwire
|
||||
# offset.reverse()
|
||||
|
||||
return offset
|
||||
# return offset
|
||||
|
||||
|
||||
def MakePath(wire, Side, radius, clockwise, ZClearance, StepDown, ZStart,
|
||||
ZFinalDepth, firstedge=None, PathClosed=True, SegLen=0.5,
|
||||
VertFeed=1.0, HorizFeed=2.0, VertJog=1.0, HorizJog = 2.0, PlungeAngle=90.0):
|
||||
''' makes the path - just a simple profile for now '''
|
||||
offset = SortPath(wire, Side, radius, clockwise, firstedge, SegLen=SegLen)
|
||||
if len(offset.Edges) == 0:
|
||||
return ""
|
||||
# def MakePath(wire, Side, radius, clockwise, ZClearance, StepDown, ZStart,
|
||||
# ZFinalDepth, firstedge=None, PathClosed=True, SegLen=0.5,
|
||||
# VertFeed=1.0, HorizFeed=2.0, VertJog=1.0, HorizJog = 2.0, PlungeAngle=90.0):
|
||||
# ''' makes the path - just a simple profile for now '''
|
||||
# offset = SortPath(wire, Side, radius, clockwise, firstedge, SegLen=SegLen)
|
||||
# if len(offset.Edges) == 0:
|
||||
# return ""
|
||||
|
||||
toolpath = offset.Edges[:]
|
||||
paths = ""
|
||||
paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog) + "\n"
|
||||
first = toolpath[0].Vertexes[0].Point
|
||||
paths += "G0 X" + str(fmt(first.x)) + "Y" + str(fmt(first.y)) + "F " + fmt(HorizJog) + "\n"
|
||||
Zprevious = ZStart
|
||||
ZCurrent = ZStart - StepDown
|
||||
# toolpath = offset.Edges[:]
|
||||
# paths = ""
|
||||
# paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog) + "\n"
|
||||
# first = toolpath[0].Vertexes[0].Point
|
||||
# paths += "G0 X" + str(fmt(first.x)) + "Y" + str(fmt(first.y)) + "F " + fmt(HorizJog) + "\n"
|
||||
# Zprevious = ZStart
|
||||
# ZCurrent = ZStart - StepDown
|
||||
|
||||
while ZCurrent > ZFinalDepth:
|
||||
paths += convert(toolpath, Z=ZCurrent, Zprevious=Zprevious, PlungeAngle=PlungeAngle,
|
||||
vf=VertFeed, hf=HorizFeed)
|
||||
if not PathClosed:
|
||||
paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog)
|
||||
paths += "G0 X" + str(fmt(first.x)) + "Y" + \
|
||||
str(fmt(first.y)) + "F " + fmt(HorizJog) + "\n"
|
||||
Zprevious = ZCurrent
|
||||
ZCurrent = ZCurrent - abs(StepDown)
|
||||
# while ZCurrent > ZFinalDepth:
|
||||
# paths += convert(toolpath, Z=ZCurrent, Zprevious=Zprevious, PlungeAngle=PlungeAngle,
|
||||
# vf=VertFeed, hf=HorizFeed)
|
||||
# if not PathClosed:
|
||||
# paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog)
|
||||
# paths += "G0 X" + str(fmt(first.x)) + "Y" + \
|
||||
# str(fmt(first.y)) + "F " + fmt(HorizJog) + "\n"
|
||||
# Zprevious = ZCurrent
|
||||
# ZCurrent = ZCurrent - abs(StepDown)
|
||||
|
||||
# do the final Z value
|
||||
paths += convert(toolpath, Z=ZFinalDepth, Zprevious=Zprevious, PlungeAngle=PlungeAngle,
|
||||
vf=VertFeed, hf=HorizFeed)
|
||||
# # do the final Z value
|
||||
# paths += convert(toolpath, Z=ZFinalDepth, Zprevious=Zprevious, PlungeAngle=PlungeAngle,
|
||||
# vf=VertFeed, hf=HorizFeed)
|
||||
|
||||
# when plunging with != 90 degree we have to do one last pass to clear the remaining ramp
|
||||
if PlungeAngle != 90.0:
|
||||
tanA = math.tan(math.pi * PlungeAngle / 180.0)
|
||||
if tanA <= 0.0:
|
||||
StopLength=None
|
||||
else:
|
||||
StopLength=abs(StepDown/tanA)
|
||||
paths += convert(toolpath, Z=ZFinalDepth, Zprevious=Zprevious, StopLength=StopLength,
|
||||
vf=VertFeed, hf=HorizFeed)
|
||||
# # when plunging with != 90 degree we have to do one last pass to clear the remaining ramp
|
||||
# if PlungeAngle != 90.0:
|
||||
# tanA = math.tan(math.pi * PlungeAngle / 180.0)
|
||||
# if tanA <= 0.0:
|
||||
# StopLength=None
|
||||
# else:
|
||||
# StopLength=abs(StepDown/tanA)
|
||||
# paths += convert(toolpath, Z=ZFinalDepth, Zprevious=Zprevious, StopLength=StopLength,
|
||||
# vf=VertFeed, hf=HorizFeed)
|
||||
|
||||
paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog) + "\n"
|
||||
return paths
|
||||
# paths += "G0 Z" + str(ZClearance) + "F " + fmt(VertJog) + "\n"
|
||||
# return paths
|
||||
|
||||
# the next two functions are for automatically populating tool
|
||||
# numbers/height offset numbers based on previously active toolnumbers
|
||||
@@ -548,19 +547,19 @@ def getLastToolLoad(obj):
|
||||
continue
|
||||
return tc
|
||||
|
||||
def getToolControllers(obj):
|
||||
controllers = []
|
||||
try:
|
||||
parent = obj.InList[0]
|
||||
except:
|
||||
parent = None
|
||||
# def getToolControllers(obj):
|
||||
# controllers = []
|
||||
# try:
|
||||
# parent = obj.InList[0]
|
||||
# except:
|
||||
# parent = None
|
||||
|
||||
if parent is not None and hasattr(parent, 'Group'):
|
||||
sibs = parent.Group
|
||||
for g in sibs:
|
||||
if isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool):
|
||||
controllers.append(g.Name)
|
||||
return controllers
|
||||
# if parent is not None and hasattr(parent, 'Group'):
|
||||
# sibs = parent.Group
|
||||
# for g in sibs:
|
||||
# if isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool):
|
||||
# controllers.append(g.Name)
|
||||
# return controllers
|
||||
|
||||
|
||||
|
||||
@@ -614,7 +613,6 @@ def addToJob(obj, jobname = None):
|
||||
else:
|
||||
#form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/DlgJobChooser.ui")
|
||||
form = FreeCADGui.PySideUic.loadUi(":/panels/DlgJobChooser.ui")
|
||||
|
||||
mylist = [i.Name for i in jobs]
|
||||
form.cboProject.addItems(mylist)
|
||||
r = form.exec_()
|
||||
@@ -629,15 +627,15 @@ def addToJob(obj, jobname = None):
|
||||
job.Group = g
|
||||
return job
|
||||
|
||||
def getLastZ(obj):
|
||||
''' find the last z value in the job '''
|
||||
lastZ = ""
|
||||
for g in obj.Group:
|
||||
for c in g.Path.Commands:
|
||||
for n in c.Parameters:
|
||||
if n == 'Z':
|
||||
lastZ = c.Parameters['Z']
|
||||
return lastZ
|
||||
# def getLastZ(obj):
|
||||
# ''' find the last z value in the job '''
|
||||
# lastZ = ""
|
||||
# for g in obj.Group:
|
||||
# for c in g.Path.Commands:
|
||||
# for n in c.Parameters:
|
||||
# if n == 'Z':
|
||||
# lastZ = c.Parameters['Z']
|
||||
# return lastZ
|
||||
|
||||
def rapid(x=None, y=None, z=None):
|
||||
""" Returns gcode string to perform a rapid move."""
|
||||
@@ -811,34 +809,58 @@ def rampPlunge(edge, rampangle, destZ, startZ):
|
||||
|
||||
|
||||
class depth_params:
|
||||
'''calculates the intermediate depth values for various operations given the starting, ending, and stepdown parameters'''
|
||||
'''calculates the intermediate depth values for various operations given the starting, ending, and stepdown parameters
|
||||
(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_depth, final_depth, [user_depths=None])
|
||||
|
||||
Note: if user_depths are supplied, only user_depths will be used.
|
||||
|
||||
clearance_height: Height to clear all obstacles
|
||||
rapid_safety_space: Height to rapid between locations
|
||||
start_depth: Top of Stock
|
||||
step_down: Distance to step down between passes (always positive)
|
||||
z_finish_step: Maximum amount of material to remove on the final pass
|
||||
final_depth: Lowest point of the cutting operation
|
||||
user_depths: List of specified depths
|
||||
'''
|
||||
|
||||
def __init__(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths=None):
|
||||
'''self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_depth, final_depth, [user_depths=None]'''
|
||||
if z_finish_step > step_down:
|
||||
raise ValueError('z_finish_step must be less than step_down')
|
||||
|
||||
def __init__(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_depth, final_depth, user_depths=None):
|
||||
self.clearance_height = clearance_height
|
||||
self.rapid_safety_space = math.fabs(rapid_safety_space)
|
||||
self.start_depth = start_depth
|
||||
self.step_down = math.fabs(step_down)
|
||||
self.z_finish_depth = math.fabs(z_finish_depth)
|
||||
self.z_finish_step = math.fabs(z_finish_step)
|
||||
self.final_depth = final_depth
|
||||
self.user_depths = user_depths
|
||||
|
||||
def get_depths(self):
|
||||
def get_depths(self, equalstep=False):
|
||||
'''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:
|
||||
depth = self.final_depth
|
||||
depths = [depth]
|
||||
depth += self.z_finish_depth
|
||||
if depth + 0.0000001 < self.start_depth:
|
||||
if self.z_finish_depth > 0.0000001:
|
||||
depths.insert(0, depth)
|
||||
layer_count = int((self.start_depth - depth) /
|
||||
self.step_down - 0.0000001) + 1
|
||||
if layer_count > 0:
|
||||
layer_depth = (self.start_depth - depth) / layer_count
|
||||
for i in range(1, layer_count):
|
||||
depth += layer_depth
|
||||
depths.append(depth)
|
||||
depths.reverse()
|
||||
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))
|
||||
else:
|
||||
layerstep = self.step_down
|
||||
|
||||
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)
|
||||
|
||||
return depths
|
||||
|
||||
@@ -33,19 +33,19 @@ FreeCADGui = None
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
class OldHighlighter(QtGui.QSyntaxHighlighter):
|
||||
def highlightBlock(self, text):
|
||||
myClassFormat = QtGui.QTextCharFormat()
|
||||
myClassFormat.setFontWeight(QtGui.QFont.Bold)
|
||||
myClassFormat.setForeground(QtCore.Qt.green)
|
||||
# the regex pattern to be colored
|
||||
pattern = "(G.*?|M.*?)\\s"
|
||||
expression = QtCore.QRegExp(pattern)
|
||||
index = text.index(expression)
|
||||
while index >= 0:
|
||||
length = expression.matchedLength()
|
||||
setFormat(index, length, myClassFormat)
|
||||
index = text.index(expression, index + length)
|
||||
# class OldHighlighter(QtGui.QSyntaxHighlighter):
|
||||
# def highlightBlock(self, text):
|
||||
# myClassFormat = QtGui.QTextCharFormat()
|
||||
# myClassFormat.setFontWeight(QtGui.QFont.Bold)
|
||||
# myClassFormat.setForeground(QtCore.Qt.green)
|
||||
# # the regex pattern to be colored
|
||||
# pattern = "(G.*?|M.*?)\\s"
|
||||
# expression = QtCore.QRegExp(pattern)
|
||||
# index = text.index(expression)
|
||||
# while index >= 0:
|
||||
# length = expression.matchedLength()
|
||||
# setFormat(index, length, myClassFormat)
|
||||
# index = text.index(expression, index + length)
|
||||
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ def editor(gcode):
|
||||
'''pops up a handy little editor to look at the code output '''
|
||||
dia = GCodeEditorDialog()
|
||||
dia.editor.setText(gcode)
|
||||
result = dia.exec_()
|
||||
# result = dia.exec_()
|
||||
|
||||
def fcoms(string,commentsym):
|
||||
''' filter and rebuild comments with user preferred comment symbol'''
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>423</width>
|
||||
<height>435</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Tool Properties</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="NameField"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="TypeField"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Material</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="MaterialField"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Diameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QDoubleSpinBox" name="DiameterField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Length Offset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QDoubleSpinBox" name="LengthOffsetField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Flat Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QDoubleSpinBox" name="FlatRadiusField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Corner Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<widget class="QDoubleSpinBox" name="CornerRadiusField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Cutting Edge Angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<widget class="QDoubleSpinBox" name="CuttingEdgeAngleField_2">
|
||||
<property name="suffix">
|
||||
<string>°</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Cutting Edge Height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<widget class="QDoubleSpinBox" name="CuttingEdgeHeightField">
|
||||
<property name="suffix">
|
||||
<string>mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,72 +0,0 @@
|
||||
################################################################################
|
||||
# drag knife.py
|
||||
#
|
||||
# NC code creator for attaching Z coordinates to a surface
|
||||
#
|
||||
# Dan Heeks 26th April 2012
|
||||
|
||||
import recreator
|
||||
dragging = False
|
||||
from kurve_funcs import cut_curve as cut_curve
|
||||
import nc
|
||||
import area
|
||||
|
||||
################################################################################
|
||||
class Creator(recreator.Redirector):
|
||||
|
||||
def __init__(self, original, drag_distance):
|
||||
recreator.Redirector.__init__(self, original)
|
||||
|
||||
self.drag_distance = drag_distance
|
||||
self.path = None
|
||||
|
||||
def cut_path(self):
|
||||
if self.path == None: return
|
||||
|
||||
print self.drag_distance
|
||||
self.path.OffsetForward(self.drag_distance, False)
|
||||
|
||||
nc.creator = nc.creator.original
|
||||
|
||||
if self.path.getNumVertices() > 0:
|
||||
v = self.path.FirstVertex()
|
||||
nc.creator.feed(v.p.x, v.p.y)
|
||||
|
||||
cut_curve(self.path)
|
||||
nc.creator = self
|
||||
|
||||
self.path = area.Curve()
|
||||
|
||||
def feed(self, x=None, y=None, z=None, a=None, b=None, c=None):
|
||||
px = self.x
|
||||
py = self.y
|
||||
pz = self.z
|
||||
recreator.Redirector.feed(self, x, y, z, a, b, c)
|
||||
if self.x == None or self.y == None or self.z == None:
|
||||
return
|
||||
if px == self.x and py == self.y:
|
||||
return
|
||||
|
||||
# add a line to the path
|
||||
if self.path == None: self.path = area.Curve()
|
||||
self.path.append(area.Point(self.x, self.y))
|
||||
|
||||
def arc(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None, ccw = True):
|
||||
recreator.Redirector.arc(self, x, y, z, i, j, k, r, ccw)
|
||||
|
||||
# add an arc to the path
|
||||
if self.path == None: self.path = area.Curve()
|
||||
self.path.append(area.Vertex(1 if ccw else -1, area.Point(self.x, self.y), area.Point(i, j)))
|
||||
|
||||
def drag_begin(drag_distance):
|
||||
global dragging
|
||||
if dragging == True:
|
||||
drag_end()
|
||||
nc.creator = Creator(nc.creator, drag_distance)
|
||||
dragging = True
|
||||
|
||||
def drag_end():
|
||||
global dragging
|
||||
nc.creator.cut_path()
|
||||
nc.creator = nc.creator.original
|
||||
attached = False
|
||||
@@ -1,306 +0,0 @@
|
||||
import nc
|
||||
import makerbot_codes as maker
|
||||
import datetime
|
||||
import iso_modal
|
||||
import math
|
||||
|
||||
|
||||
now = datetime.datetime.now()
|
||||
|
||||
################################################################################
|
||||
class CreatorMakerbotHBP(iso_modal.CreatorIsoModal):
|
||||
def __init__(self):
|
||||
iso_modal.CreatorIsoModal.__init__(self)
|
||||
|
||||
self.absolute_flag = True
|
||||
self.prev_g91 = ''
|
||||
|
||||
|
||||
################################################################################
|
||||
# program begin and end
|
||||
|
||||
def program_begin(self, id, name=''):
|
||||
self.write((maker.codes.COMMENT(now)))
|
||||
self.write((maker.codes.EXTRUDER_TEMP('220')) + (maker.codes.COMMENT('Extruder Temp')) )
|
||||
self.write((maker.codes.BUILD_BED_TEMP('110'))+ (maker.codes.COMMENT('Build Bed Temp')) )
|
||||
self.write((maker.codes.FAN_OFF()) + (maker.codes.COMMENT('Fan Off')) )
|
||||
self.write((maker.codes.METRIC()) + (maker.codes.COMMENT('Metric units')) )
|
||||
self.write((maker.codes.ABSOLUTE()) + (maker.codes.COMMENT('Absolute units')) )
|
||||
self.write('G92 X0 Y0 Z0 (You are now at 0,0,0)\n')
|
||||
self.write('G0 Z15 (Move up for warmup)\n')
|
||||
self.write((maker.codes.EXTRUDER_SPEED_PWM('255')) + (maker.codes.COMMENT('Extruder Speed')) )
|
||||
self.write('M6 T0 (Wait for tool to heat up)\n')
|
||||
self.write('G04 P5000 (Wait 5 seconds)\n')
|
||||
self.write((maker.codes.EXTRUDER_ON_FWD()) + (maker.codes.COMMENT('Extruder On')) )
|
||||
self.write('G04 P5000 (Wait 5 seconds)\n')
|
||||
self.write((maker.codes.EXTRUDER_OFF()) + (maker.codes.COMMENT('Extruder Off')) )
|
||||
self.write('M01 (The heated build platform is heating up. Wait until after the lights have turned off for the first time, clear the test extrusion, and click yes.)\n')
|
||||
self.write('G0 Z0 (Go back to zero.)\n')
|
||||
|
||||
def program_end(self):
|
||||
self.write((maker.codes.COMMENT('End of the file. Begin cool-down')))
|
||||
self.write((maker.codes.EXTRUDER_TEMP('0')) + (maker.codes.COMMENT('Extruder Temp')) )
|
||||
self.write((maker.codes.BUILD_BED_TEMP('0')) + (maker.codes.COMMENT('Build Bed Temp')) )
|
||||
self.write((maker.codes.FAN_ON()) + (maker.codes.COMMENT('Fan On')) )
|
||||
self.write('G92 Z0 (zero our z axis - hack b/c skeinforge mangles gcodes in end.txt)\n')
|
||||
self.write('G1 Z10 (go up 10 b/c it was zeroed earlier.)\n')
|
||||
self.write('G1 X0 Y0 Z10 (go to 0,0,z)\n')
|
||||
self.write((maker.codes.STEPPERS_OFF()) + (maker.codes.COMMENT('Steppers Off')) )
|
||||
|
||||
def program_stop(self):
|
||||
self.write((maker.codes.EXTRUDER_TEMP('0')))
|
||||
self.write((maker.codes.BUILD_BED_TEMP('0')))
|
||||
self.write((maker.codes.STEPPERS_OFF()))
|
||||
|
||||
################################################################################
|
||||
# general
|
||||
def write_blocknum(self):
|
||||
pass
|
||||
|
||||
def set_plane(self, plane):
|
||||
pass
|
||||
|
||||
def workplane(self, id):
|
||||
pass
|
||||
|
||||
def spindle(self, s, clockwise):
|
||||
pass
|
||||
################################################################################
|
||||
# Extruder Control
|
||||
|
||||
def extruder_on(self):
|
||||
self.write((maker.codes.EXTRUDER_ON()) + ('\n'))
|
||||
|
||||
def extruder_off(self):
|
||||
self.write((maker.codes.EXTRUDER_OFF()) + ('\n'))
|
||||
|
||||
def set_extruder_flowrate(self, flowrate):
|
||||
self.write((maker.codes.EXTRUDER_SPEED_PWM(flowrate)) + ('\n'))
|
||||
|
||||
def extruder_temp(self, temp):
|
||||
self.write((maker.codes.EXTRUDER_TEMP(temp)) + ('\n'))
|
||||
|
||||
################################################################################
|
||||
# Build Environment Control
|
||||
def build_bed_temp(self, temp):
|
||||
self.write((maker.codes.BUILD_BED_TEMP(temp)) + ('\n'))
|
||||
|
||||
def chamber_temp(self, temp):
|
||||
self.write((maker.codes.CHAMBER_TEMP(temp)) + ('\n'))
|
||||
|
||||
################################################################################
|
||||
# Fan Control
|
||||
def fan_on(self):
|
||||
self.write((maker.codes.FAN_ON()) + ('\n'))
|
||||
|
||||
def fan_off(self):
|
||||
self.write((maker.codes.FAN_OFF()) + ('\n'))
|
||||
|
||||
################################################################################
|
||||
# Custom routines
|
||||
|
||||
def wipe(self):
|
||||
self.write(('(This would be a good place for a custom wipe routine)\n'))
|
||||
|
||||
################################################################################
|
||||
# APT style INSERT- insert anything into program
|
||||
|
||||
def insert(self, text):
|
||||
self.write((text + '\n'))
|
||||
|
||||
################################################################################
|
||||
# tool info
|
||||
def tool_change(self, id):
|
||||
pass
|
||||
# self.write_blocknum()
|
||||
# self.write((maker.codes.TOOL() % id) + '\n')
|
||||
# self.t = id
|
||||
|
||||
def tool_defn(self, id, name='', params=None):
|
||||
pass
|
||||
############################################################################
|
||||
## Moves
|
||||
|
||||
def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None ):
|
||||
self.write_blocknum()
|
||||
if self.g0123_modal:
|
||||
if self.prev_g0123 != maker.codes.RAPID():
|
||||
self.write(maker.codes.RAPID())
|
||||
self.prev_g0123 = maker.codes.RAPID()
|
||||
else:
|
||||
self.write(maker.codes.RAPID())
|
||||
self.write_preps()
|
||||
if (x != None):
|
||||
dx = x - self.x
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.X() + (self.fmt % x))
|
||||
else:
|
||||
self.write(maker.codes.X() + (self.fmt % dx))
|
||||
self.x = x
|
||||
if (y != None):
|
||||
dy = y - self.y
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.Y() + (self.fmt % y))
|
||||
else:
|
||||
self.write(maker.codes.Y() + (self.fmt % dy))
|
||||
|
||||
self.y = y
|
||||
if (z != None):
|
||||
dz = z - self.z
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.Z() + (self.fmt % z))
|
||||
else:
|
||||
self.write(maker.codes.Z() + (self.fmt % dz))
|
||||
|
||||
self.z = z
|
||||
|
||||
if (a != None):
|
||||
da = a - self.a
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.A() + (self.fmt % a))
|
||||
else:
|
||||
self.write(maker.codes.A() + (self.fmt % da))
|
||||
self.a = a
|
||||
|
||||
if (b != None):
|
||||
db = b - self.b
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.B() + (self.fmt % b))
|
||||
else:
|
||||
self.write(maker.codes.B() + (self.fmt % db))
|
||||
self.b = b
|
||||
|
||||
if (c != None):
|
||||
dc = c - self.c
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.C() + (self.fmt % c))
|
||||
else:
|
||||
self.write(maker.codes.C() + (self.fmt % dc))
|
||||
self.c = c
|
||||
self.write_spindle()
|
||||
self.write_misc()
|
||||
self.write('\n')
|
||||
|
||||
def feed(self, x=None, y=None, z=None, a = None, b = None, c = None):
|
||||
if self.same_xyz(x, y, z): return
|
||||
self.write_blocknum()
|
||||
if self.g0123_modal:
|
||||
if self.prev_g0123 != maker.codes.FEED():
|
||||
self.write(maker.codes.FEED())
|
||||
self.prev_g0123 = maker.codes.FEED()
|
||||
else:
|
||||
self.write(maker.codes.FEED())
|
||||
self.write_preps()
|
||||
dx = dy = dz = 0
|
||||
if (x != None):
|
||||
dx = x - self.x
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.X() + (self.fmt % x))
|
||||
else:
|
||||
self.write(maker.codes.X() + (self.fmt % dx))
|
||||
self.x = x
|
||||
if (y != None):
|
||||
dy = y - self.y
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.Y() + (self.fmt % y))
|
||||
else:
|
||||
self.write(maker.codes.Y() + (self.fmt % dy))
|
||||
|
||||
self.y = y
|
||||
if (z != None):
|
||||
dz = z - self.z
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.Z() + (self.fmt % z))
|
||||
else:
|
||||
self.write(maker.codes.Z() + (self.fmt % dz))
|
||||
|
||||
self.z = z
|
||||
if (self.fhv) : self.calc_feedrate_hv(math.sqrt(dx*dx+dy*dy), math.fabs(dz))
|
||||
self.write_feedrate()
|
||||
self.write_spindle()
|
||||
self.write_misc()
|
||||
self.write('\n')
|
||||
|
||||
def same_xyz(self, x=None, y=None, z=None):
|
||||
if (x != None):
|
||||
if (self.fmt % x) != (self.fmt % self.x):
|
||||
return False
|
||||
if (y != None):
|
||||
if (self.fmt % y) != (self.fmt % self.y):
|
||||
return False
|
||||
if (z != None):
|
||||
if (self.fmt % z) != (self.fmt % self.z):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def arc(self, cw, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
|
||||
if self.same_xyz(x, y, z): return
|
||||
self.write_blocknum()
|
||||
arc_g_code = ''
|
||||
if cw: arc_g_code = maker.codes.ARC_CW()
|
||||
else: arc_g_code = maker.codes.ARC_CCW()
|
||||
if self.g0123_modal:
|
||||
if self.prev_g0123 != arc_g_code:
|
||||
self.write(arc_g_code)
|
||||
self.prev_g0123 = arc_g_code
|
||||
else:
|
||||
self.write(arc_g_code)
|
||||
self.write_preps()
|
||||
if (x != None):
|
||||
dx = x - self.x
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.X() + (self.fmt % x))
|
||||
else:
|
||||
self.write(maker.codes.X() + (self.fmt % dx))
|
||||
self.x = x
|
||||
if (y != None):
|
||||
dy = y - self.y
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.Y() + (self.fmt % y))
|
||||
else:
|
||||
self.write(maker.codes.Y() + (self.fmt % dy))
|
||||
self.y = y
|
||||
if (z != None):
|
||||
dz = z - self.z
|
||||
if (self.absolute_flag ):
|
||||
self.write(maker.codes.Z() + (self.fmt % z))
|
||||
else:
|
||||
self.write(maker.codes.Z() + (self.fmt % dz))
|
||||
self.z = z
|
||||
if (i != None) : self.write(maker.codes.CENTRE_X() + (self.fmt % i))
|
||||
if (j != None) : self.write(maker.codes.CENTRE_Y() + (self.fmt % j))
|
||||
if (k != None) : self.write(maker.codes.CENTRE_Z() + (self.fmt % k))
|
||||
if (r != None) : self.write(maker.codes.RADIUS() + (self.fmt % r))
|
||||
# use horizontal feed rate
|
||||
if (self.fhv) : self.calc_feedrate_hv(1, 0)
|
||||
self.write_feedrate()
|
||||
self.write_spindle()
|
||||
self.write_misc()
|
||||
self.write('\n')
|
||||
|
||||
def arc_cw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
|
||||
self.arc(True, x, y, z, i, j, k, r)
|
||||
|
||||
def arc_ccw(self, x=None, y=None, z=None, i=None, j=None, k=None, r=None):
|
||||
self.arc(False, x, y, z, i, j, k, r)
|
||||
|
||||
def dwell(self, t):
|
||||
self.write_blocknum()
|
||||
self.write_preps()
|
||||
self.write(maker.codes.DWELL() + (maker.codes.TIME() % t))
|
||||
self.write_misc()
|
||||
self.write('\n')
|
||||
|
||||
def rapid_home(self, x=None, y=None, z=None, a=None, b=None, c=None):
|
||||
pass
|
||||
|
||||
def rapid_unhome(self):
|
||||
pass
|
||||
|
||||
def set_machine_coordinates(self):
|
||||
self.write(maker.codes.MACHINE_COORDINATES())
|
||||
self.prev_g0123 = ''
|
||||
|
||||
nc.creator = CreatorMakerbotHBP()
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
################################################################################
|
||||
# makerbot_codes.py
|
||||
#
|
||||
# a lot like iso_codes.py but with reprap/makerbot specific M codes.
|
||||
#
|
||||
# Brad Collette, 12th Sept 2010
|
||||
#
|
||||
# Many of these codes have nothing to do with reprap/additive machining but are left here in anticipation of future hybrid machines.
|
||||
|
||||
class Codes():
|
||||
def SPACE(self): return(' ')
|
||||
def FORMAT_FEEDRATE(self): return('%.2f')
|
||||
def FORMAT_IN(self): return('%.5f')
|
||||
def FORMAT_MM(self): return('%.3f')
|
||||
def FORMAT_ANG(self): return('%.1f')
|
||||
def FORMAT_TIME(self): return('%.2f')
|
||||
def FORMAT_DWELL(self): return('P%f')
|
||||
|
||||
def BLOCK(self): return('N%i' + self.SPACE())
|
||||
def COMMENT(self,comment): return( (' (%s)\n' % comment ) )
|
||||
def VARIABLE(self): return( '#%i')
|
||||
def VARIABLE_SET(self): return( '=%.3f')
|
||||
|
||||
def PROGRAM(self): return( 'O%i')
|
||||
def PROGRAM_END(self): return( 'M02')
|
||||
|
||||
def SUBPROG_CALL(self): return( 'M98' + self.SPACE() + 'P%i')
|
||||
def SUBPROG_END(self): return( 'M99')
|
||||
|
||||
def STOP_OPTIONAL(self): return('M01')
|
||||
def STOP(self): return('M00')
|
||||
|
||||
def IMPERIAL(self): return(self.SPACE() + 'G20')
|
||||
def METRIC(self): return(self.SPACE() + 'G21' + self.SPACE())
|
||||
def ABSOLUTE(self): return(self.SPACE() + 'G90' + self.SPACE())
|
||||
def INCREMENTAL(self): return(self.SPACE() + 'G91')
|
||||
def SET_TEMPORARY_COORDINATE_SYSTEM(self): return('G92' + self.SPACE())
|
||||
def REMOVE_TEMPORARY_COORDINATE_SYSTEM(self): return('G92.1' + self.SPACE())
|
||||
def POLAR_ON(self): return(self.SPACE() + 'G16')
|
||||
def POLAR_OFF(self): return(self.SPACE() + 'G15')
|
||||
def PLANE_XY(self): return(self.SPACE() + 'G17')
|
||||
def PLANE_XZ(self): return(self.SPACE() + 'G18')
|
||||
def PLANE_YZ(self): return(self.SPACE() + 'G19')
|
||||
|
||||
def TOOL(self): return(self.SPACE() +'T%i')
|
||||
def TOOL_DEFINITION(self): return('G10' + self.SPACE() + 'L1' + self.SPACE())
|
||||
|
||||
def WORKPLANE(self): return('G%i')
|
||||
def WORKPLANE_BASE(self): return(53)
|
||||
|
||||
def FEEDRATE(self): return((self.SPACE() + ' F'))
|
||||
def SPINDLE(self, format, speed): return(self.SPACE() + 'S' + (format % speed))
|
||||
def SPINDLE_CW(self): return(self.SPACE() + 'M03')
|
||||
def SPINDLE_CCW(self): return(self.SPACE() + 'M04')
|
||||
def COOLANT_OFF(self): return(self.SPACE() + 'M09')
|
||||
def COOLANT_MIST(self): return(self.SPACE() + 'M07')
|
||||
def COOLANT_FLOOD(self): return(self.SPACE() + 'M08')
|
||||
def GEAR_OFF(self): return(self.SPACE() + '?')
|
||||
def GEAR(self): return('M%i')
|
||||
def GEAR_BASE(self): return(37)
|
||||
|
||||
def RAPID(self): return('G0')
|
||||
def FEED(self): return('G1')
|
||||
def ARC_CW(self): return('G2')
|
||||
def ARC_CCW(self): return('G3')
|
||||
def DWELL(self): return('G04')
|
||||
def DRILL(self): return(self.SPACE() + 'G81')
|
||||
def DRILL_WITH_DWELL(self, format, dwell): return(self.SPACE() + 'G82' + (format % dwell))
|
||||
def PECK_DRILL(self): return(self.SPACE() + 'G83')
|
||||
def PECK_DEPTH(self, format, depth): return(self.SPACE() + 'Q' + (format % depth))
|
||||
def RETRACT(self, format, height): return(self.SPACE() + 'R' + (format % height))
|
||||
def END_CANNED_CYCLE(self): return(self.SPACE() + 'G80')
|
||||
|
||||
def X(self): return(self.SPACE() + 'X')
|
||||
def Y(self): return(self.SPACE() + 'Y')
|
||||
def Z(self): return(self.SPACE() + 'Z')
|
||||
def A(self): return(self.SPACE() + 'A')
|
||||
def B(self): return(self.SPACE() + 'B')
|
||||
def C(self): return(self.SPACE() + 'C')
|
||||
def CENTRE_X(self): return(self.SPACE() + 'I')
|
||||
def CENTRE_Y(self): return(self.SPACE() + 'J')
|
||||
def CENTRE_Z(self): return(self.SPACE() + 'K')
|
||||
def RADIUS(self): return(self.SPACE() + 'R')
|
||||
def TIME(self): return(self.SPACE() + 'P')
|
||||
|
||||
def PROBE_TOWARDS_WITH_SIGNAL(self): return('G38.2' + self.SPACE())
|
||||
def PROBE_TOWARDS_WITHOUT_SIGNAL(self): return('G38.3' + self.SPACE())
|
||||
def PROBE_AWAY_WITH_SIGNAL(self): return('G38.4' + self.SPACE())
|
||||
def PROBE_AWAY_WITHOUT_SIGNAL(self): return('G38.5' + self.SPACE())
|
||||
|
||||
def MACHINE_COORDINATES(self): return('G53' + self.SPACE())
|
||||
|
||||
def EXTRUDER_ON (self): return('M101') #deprecated
|
||||
def EXTRUDER_OFF (self): return('M103')
|
||||
def EXTRUDER_TEMP (self, degree_celsius): return('M104 S' + '%s' % degree_celsius)
|
||||
def EXTRUDER_TEMP_WAIT (self, degree_celsius): return('M109 S' + '%s' % degree_celsius)
|
||||
def READ_EXTRUDER_TEMP (self): return('M105')
|
||||
def EXTRUDER_SPEED_PWM (self, speed_in_PWM): return('M108 S' + '%s' % speed_in_PWM) #deprecated
|
||||
def EXTRUDER_SPEED_RPM (self, speed_in_RPM): return('M108 P' + '%s' % speed_in_RPM) #deprecated
|
||||
|
||||
def STEPPERS_OFF(self): return(self.SPACE() + 'M118')
|
||||
|
||||
def ALL_WAIT (self): return(self.SPACE() + 'M116') # Wait for all temperature and slow-changing variables to reach set values
|
||||
|
||||
def FAN_ON (self): return(self.SPACE() + 'M106')
|
||||
def FAN_OFF (self): return(self.SPACE() + 'M107')
|
||||
|
||||
def VALVE_OPEN (self, delay): return(self.SPACE() + ('M126 P' + '%' % delay) )
|
||||
def VALVE_CLOSE (self, delay): return(self.SPACE() + ('M127 P' + '%' % delay) )
|
||||
|
||||
def BUILD_BED_TEMP (self, degree_celsius): return('M140 S' + '%s' % degree_celsius)
|
||||
def BED_HOLDING_PRESSURE (self, pressure): return('M142 S' + '%s' % pressure)
|
||||
|
||||
def CHAMBER_TEMP (self, degree_celsius): return('M141 S' + '%s' % degree_celsius)
|
||||
|
||||
#The following codes are listed on the reprap wiki page at http://reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes but require more study.
|
||||
#
|
||||
#G28 G Y Xnnn Ynnn Znnn Move to origin (on specified axes only, if X/Y/Z parameters are present)
|
||||
#M105 M N none Request current extruder and base temperatures (in Celsius)
|
||||
#M110 M N none Set current line number to Nxxx value preceeding command
|
||||
#M111 M N Snnn Set debug level bitfield to value of parameter (default 6)
|
||||
#M112 M N none Emergency stop (stop immediately, discarding any buffered commands)
|
||||
#M113 M N Snnn Set Extruder PWM (to value defined by pot, or to parameter value if present)
|
||||
#M114 M N none Get Current Position (return current X, Y, Z and E values)
|
||||
#M117 M N none Get Zero Position (return X, Y, Z and E values of endstop hits)
|
||||
|
||||
|
||||
codes = Codes()
|
||||
@@ -1,53 +0,0 @@
|
||||
################################################################################
|
||||
# printbot3d.py
|
||||
#
|
||||
# Dan Heeks 18th October 2010
|
||||
|
||||
import nc
|
||||
import iso_modal
|
||||
import math
|
||||
|
||||
################################################################################
|
||||
class CreatorPrintbot(iso_modal.CreatorIsoModal):
|
||||
|
||||
def __init__(self):
|
||||
iso_modal.CreatorIsoModal.__init__(self)
|
||||
|
||||
def tool_defn(self, id, name='', params=None):
|
||||
pass
|
||||
|
||||
def write_blocknum(self):
|
||||
pass
|
||||
|
||||
def set_plane(self, plane):
|
||||
pass
|
||||
|
||||
def workplane(self, id):
|
||||
pass
|
||||
|
||||
# Extruder Control
|
||||
|
||||
def extruder_on(self):
|
||||
self.write('M101\n')
|
||||
|
||||
def extruder_off(self):
|
||||
self.write('M103\n')
|
||||
|
||||
def set_extruder_flowrate(self, flowrate):
|
||||
# re-use the spindle speed function
|
||||
self.spindle(flowrate, True)
|
||||
|
||||
def extruder_temp(self, temp):
|
||||
self.write((maker.codes.EXTRUDER_TEMP(temp)) + ('\n'))
|
||||
|
||||
# General
|
||||
def rapid(x=None, y=None, z=None, a=None, b=None, c=None):
|
||||
# do a G1 even for rapid moves
|
||||
iso_modal.CreatorIsoModal.feed(self, x, y, z)
|
||||
|
||||
def feed(self, x=None, y=None, z=None, a = None, b = None, c = None):
|
||||
iso_modal.CreatorIsoModal.feed(self, x, y, z)
|
||||
|
||||
################################################################################
|
||||
|
||||
nc.creator = CreatorPrintbot()
|
||||
@@ -1,17 +0,0 @@
|
||||
import iso_read as iso
|
||||
import sys
|
||||
|
||||
# based on the iso reader
|
||||
|
||||
class Parser(iso.Parser):
|
||||
def __init__(self, writer):
|
||||
iso.Parser.__init__(self, writer)
|
||||
|
||||
def ParseWord(self, word):
|
||||
iso.Parser.ParseWord(self, word)
|
||||
if (word == 'M103'):
|
||||
self.path_col = "rapid"
|
||||
self.col = "rapid"
|
||||
elif (word == 'M101'):
|
||||
self.path_col = "feed"
|
||||
self.col = "feed"
|
||||
@@ -1,242 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2014 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 xml.sax
|
||||
import FreeCADGui
|
||||
import Path
|
||||
import Draft
|
||||
import Part
|
||||
import os
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
# Tooltable XML readers
|
||||
|
||||
class FreeCADTooltableHandler(xml.sax.ContentHandler):
|
||||
# http://www.tutorialspoint.com/python/python_xml_processing.htm
|
||||
|
||||
def __init__(self):
|
||||
self.tooltable = None
|
||||
self.tool = None
|
||||
self.number = None
|
||||
|
||||
# Call when an element is found
|
||||
def startElement(self, tag, attributes):
|
||||
if tag == "Tooltable":
|
||||
self.tooltable = Path.Tooltable()
|
||||
elif tag == "Toolslot":
|
||||
self.number = int(attributes["number"])
|
||||
elif tag == "Tool":
|
||||
self.tool = Path.Tool()
|
||||
self.tool.Name = str(attributes["name"])
|
||||
self.tool.ToolType = str(attributes["type"])
|
||||
self.tool.Material = str(attributes["mat"])
|
||||
# for some reason without the following line I get an error
|
||||
print attributes["diameter"]
|
||||
self.tool.Diameter = float(attributes["diameter"])
|
||||
self.tool.LengthOffset = float(attributes["length"])
|
||||
self.tool.FlatRadius = float(attributes["flat"])
|
||||
self.tool.CornerRadius = float(attributes["corner"])
|
||||
self.tool.CuttingEdgeAngle = float(attributes["angle"])
|
||||
self.tool.CuttingEdgeHeight = float(attributes["height"])
|
||||
|
||||
# Call when an elements ends
|
||||
def endElement(self, tag):
|
||||
if tag == "Toolslot":
|
||||
if self.tooltable and self.tool and self.number:
|
||||
self.tooltable.setTool(self.number, self.tool)
|
||||
self.number = None
|
||||
self.tool = None
|
||||
|
||||
|
||||
class HeeksTooltableHandler(xml.sax.ContentHandler):
|
||||
|
||||
def __init__(self):
|
||||
self.tooltable = Path.Tooltable()
|
||||
self.tool = None
|
||||
self.number = None
|
||||
|
||||
# Call when an element is found
|
||||
def startElement(self, tag, attributes):
|
||||
if tag == "Tool":
|
||||
self.tool = Path.Tool()
|
||||
self.number = int(attributes["tool_number"])
|
||||
self.tool.Name = str(attributes["title"])
|
||||
elif tag == "params":
|
||||
t = str(attributes["type"])
|
||||
if t == "drill":
|
||||
self.tool.ToolType = "Drill"
|
||||
elif t == "center_drill_bit":
|
||||
self.tool.ToolType = "CenterDrill"
|
||||
elif t == "end_mill":
|
||||
self.tool.ToolType = "EndMill"
|
||||
elif t == "slot_cutter":
|
||||
self.tool.ToolType = "SlotCutter"
|
||||
elif t == "ball_end_mill":
|
||||
self.tool.ToolType = "BallEndMill"
|
||||
elif t == "chamfer":
|
||||
self.tool.ToolType = "Chamfer"
|
||||
elif t == "engraving_bit":
|
||||
self.tool.ToolType = "Engraver"
|
||||
m = str(attributes["material"])
|
||||
if m == "0":
|
||||
self.tool.Material = "HighSpeedSteel"
|
||||
elif m == "1":
|
||||
self.tool.Material = "Carbide"
|
||||
# for some reason without the following line I get an error
|
||||
print attributes["diameter"]
|
||||
self.tool.Diameter = float(attributes["diameter"])
|
||||
self.tool.LengthOffset = float(attributes["tool_length_offset"])
|
||||
self.tool.FlatRadius = float(attributes["flat_radius"])
|
||||
self.tool.CornerRadius = float(attributes["corner_radius"])
|
||||
self.tool.CuttingEdgeAngle = float(
|
||||
attributes["cutting_edge_angle"])
|
||||
self.tool.CuttingEdgeHeight = float(
|
||||
attributes["cutting_edge_height"])
|
||||
|
||||
# Call when an elements ends
|
||||
def endElement(self, tag):
|
||||
if tag == "Tool":
|
||||
if self.tooltable and self.tool and self.number:
|
||||
self.tooltable.setTool(self.number, self.tool)
|
||||
self.number = None
|
||||
self.tool = None
|
||||
|
||||
|
||||
class ToolLibraryManager():
|
||||
'''
|
||||
The Tool Library is a list of individual tool tables. Each
|
||||
Tool Table can contain n tools. The tool library will be persisted to user
|
||||
preferences and all or part of the library can be exported to other formats
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
self.ToolLibrary = []
|
||||
self.prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path/ToolLibrary")
|
||||
return
|
||||
|
||||
def saveLibrary(self):
|
||||
'''Persists the entire library to FreeCAD user preferences'''
|
||||
tmpstring = ""
|
||||
for table in self.ToolLibrary:
|
||||
if table["listtype"] == 'User':
|
||||
tmpstring += table["list"].Content
|
||||
self.prefs.SetString("ToolLibrary", tmpstring)
|
||||
|
||||
# FreeCAD.ConfigSet("PathToolTable:" + table[0], table[2].Content)
|
||||
|
||||
def loadLibrary(self):
|
||||
'''Loads the current library from FreeCAD user preferences'''
|
||||
# Get persisted libraries from user prefs
|
||||
tmpstring = self.prefs.GetString("ToolLibrary", "")
|
||||
ToolLibrary = []
|
||||
if tmpstring != "":
|
||||
Handler = FreeCADTooltableHandler()
|
||||
try:
|
||||
xml.sax.parseString(tmpstring, Handler)
|
||||
tt = Handler.tooltable
|
||||
toollist = {'name': "main", 'listtype': "User", 'list': tt}
|
||||
ToolLibrary.append(toollist)
|
||||
except:
|
||||
FreeCAD.Console.PrintError(
|
||||
"Unable to import tools from user preferences")
|
||||
|
||||
# Get ToolTables from any open CNC jobs
|
||||
for o in FreeCAD.ActiveDocument.Objects:
|
||||
if "Proxy" in o.PropertiesList:
|
||||
if hasattr(o, "Tooltable"):
|
||||
toollist = {'name': o.Name,
|
||||
'listtype': "Job", 'list': o.Tooltable}
|
||||
ToolLibrary.append(toollist)
|
||||
self.ToolLibrary = ToolLibrary
|
||||
return self.ToolLibrary
|
||||
|
||||
# methods for lists
|
||||
def addList(self, tablename, listtype="User", TL=None):
|
||||
'''Add a new tooltable to the user library'''
|
||||
if TL is None:
|
||||
TL = Path.Tooltable()
|
||||
toollist = {'name': tablename, 'listtype': listtype, 'list': TL}
|
||||
self.ToolLibrary.append(toollist)
|
||||
return TL
|
||||
|
||||
def deleteList(self, tablename):
|
||||
'''Delete all lists from the user library with the given listname'''
|
||||
for l in self.ToolLibrary:
|
||||
if l['name'] == tablename:
|
||||
# maybe check if tools exist in list
|
||||
self.ToolLibrary.remove(l)
|
||||
return
|
||||
|
||||
def findList(self, tablename):
|
||||
'''Finds and returns list by name'''
|
||||
returnlist = []
|
||||
for l in self.ToolLibrary:
|
||||
if l['name'] == tablename:
|
||||
returnlist.append(l)
|
||||
return returnlist
|
||||
|
||||
# methods for importing and exporting
|
||||
def read(self):
|
||||
"imports a tooltable from a file"
|
||||
filename = QtGui.QFileDialog.getOpenFileName(None, _translate("ToolLibraryManager", "Import tooltable", None), None, _translate(
|
||||
"ToolLibraryManager", "Tooltable XML (*.xml);;HeeksCAD tooltable (*.tooltable)", None))
|
||||
if filename:
|
||||
parser = xml.sax.make_parser()
|
||||
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
|
||||
if os.path.splitext(filename[0])[1].lower() == ".tooltable":
|
||||
Handler = HeeksTooltableHandler()
|
||||
else:
|
||||
Handler = FreeCADTooltableHandler()
|
||||
parser.setContentHandler(Handler)
|
||||
parser.parse(str(filename[0]))
|
||||
if Handler.tooltable:
|
||||
self.addList(filename[0], Handler.tooltable)
|
||||
# self.reset()
|
||||
|
||||
def createToolController(self, job, tool):
|
||||
pass
|
||||
|
||||
def exportListHeeks(self, tooltable):
|
||||
'''exports one or more Lists as a HeeksCNC tooltable'''
|
||||
pass
|
||||
|
||||
def exportListLinuxCNC(self, tooltable):
|
||||
'''exports one or more Lists as a LinuxCNC tooltable'''
|
||||
pass
|
||||
|
||||
def exportListXML(self, tooltable):
|
||||
'''exports one or more Lists as an XML file'''
|
||||
pass
|
||||
163
src/Mod/Path/PathTests/TestPathDepthParams.py
Normal file
163
src/Mod/Path/PathTests/TestPathDepthParams.py
Normal file
@@ -0,0 +1,163 @@
|
||||
# -*- 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 PathScripts.PathUtils as PU
|
||||
import unittest
|
||||
|
||||
|
||||
class depthTestCases(unittest.TestCase):
|
||||
def test00(self):
|
||||
'''Stepping down to zero '''
|
||||
clearance_height= 15
|
||||
rapid_safety_space = 12
|
||||
|
||||
start_depth = 10
|
||||
step_down = 2
|
||||
z_finish_step = 1
|
||||
final_depth = 0
|
||||
user_depths = None
|
||||
|
||||
expected =[8,6,4,2,1,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()
|
||||
self.assertListEqual (r, expected)
|
||||
|
||||
def test10(self):
|
||||
'''Stepping from zero to a negative depth '''
|
||||
|
||||
clearance_height= 10
|
||||
rapid_safety_space = 5
|
||||
|
||||
start_depth = 0
|
||||
step_down = 2
|
||||
z_finish_step = 0
|
||||
final_depth = -10
|
||||
user_depths = None
|
||||
|
||||
expected =[-2, -4, -6, -8, -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()
|
||||
self.assertListEqual (r, expected)
|
||||
|
||||
def test20(self):
|
||||
'''Start and end are equal or start lower than finish '''
|
||||
clearance_height= 15
|
||||
rapid_safety_space = 12
|
||||
|
||||
start_depth = 10
|
||||
step_down = 2
|
||||
z_finish_step = 0
|
||||
final_depth = 10
|
||||
user_depths = None
|
||||
|
||||
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)
|
||||
|
||||
start_depth = 10
|
||||
final_depth = 15
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
||||
def test30(self):
|
||||
'''User Parameters passed in'''
|
||||
clearance_height= 10
|
||||
rapid_safety_space = 5
|
||||
|
||||
start_depth = 0
|
||||
step_down = 2
|
||||
z_finish_step = 0
|
||||
final_depth = -10
|
||||
user_depths = [2, 4, 8, 10, 11, 12]
|
||||
|
||||
expected =[2, 4, 8, 10, 11, 12]
|
||||
|
||||
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)
|
||||
|
||||
def test40(self):
|
||||
'''Finish depth passed in.'''
|
||||
clearance_height= 10
|
||||
rapid_safety_space = 5
|
||||
|
||||
start_depth = 0
|
||||
step_down = 2
|
||||
z_finish_step = 1
|
||||
final_depth = -10
|
||||
user_depths = None
|
||||
|
||||
expected =[-2, -4, -6, -8, -9, -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()
|
||||
self.assertListEqual (r, expected)
|
||||
|
||||
|
||||
def test50(self):
|
||||
'''stepping down with equalstep=True'''
|
||||
clearance_height= 10
|
||||
rapid_safety_space = 5
|
||||
|
||||
start_depth = 10
|
||||
step_down = 3
|
||||
z_finish_step = 0
|
||||
final_depth = 0
|
||||
user_depths = None
|
||||
|
||||
expected =[7.5, 5.0, 2.5, 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)
|
||||
|
||||
|
||||
def test60(self):
|
||||
'''stepping down with equalstep=True and a finish depth'''
|
||||
clearance_height= 10
|
||||
rapid_safety_space = 5
|
||||
|
||||
start_depth = 10
|
||||
step_down = 3
|
||||
z_finish_step = 1
|
||||
final_depth = 0
|
||||
user_depths = None
|
||||
|
||||
expected =[7.0, 4.0, 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)
|
||||
|
||||
@@ -30,7 +30,7 @@ import math
|
||||
import unittest
|
||||
|
||||
from FreeCAD import Vector
|
||||
from PathScripts.PathDressupHoldingTags import *
|
||||
#from PathScripts.PathDressupHoldingTags import *
|
||||
from PathScripts.PathGeom import PathGeom
|
||||
from PathTests.PathTestUtils import PathTestBase
|
||||
|
||||
|
||||
@@ -27,3 +27,5 @@ import TestApp
|
||||
from PathTests.TestPathPost import PathPostTestCases
|
||||
|
||||
from PathTests.TestPathGeom import TestPathGeom
|
||||
from PathTests.TestPathDepthParams import depthTestCases
|
||||
|
||||
|
||||
Reference in New Issue
Block a user