Merge pull request #376 from sliptonic/BugFixes

Bug fixes
This commit is contained in:
wwmayer
2016-12-13 16:45:49 +01:00
committed by GitHub
30 changed files with 1231 additions and 2918 deletions

View File

@@ -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

View File

@@ -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();
}
/**

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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):

View File

@@ -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

View File

@@ -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):

View File

@@ -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

View File

@@ -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):

View File

@@ -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")

View File

@@ -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():

View File

@@ -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")

View File

@@ -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():

View File

@@ -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

View File

@@ -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'''

View File

@@ -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>

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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"

View File

@@ -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

View 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)

View File

@@ -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

View File

@@ -27,3 +27,5 @@ import TestApp
from PathTests.TestPathPost import PathPostTestCases
from PathTests.TestPathGeom import TestPathGeom
from PathTests.TestPathDepthParams import depthTestCases