Taskpanels for Drilling, Engrave, and Profile basically working

Profile still missing some functionality.
I haven't tried to do anything about cmake requirements or testing.
This is a checkpoint commit, please don't build.
This commit is contained in:
sliptonic 2016-04-02 12:58:22 -05:00 committed by Yorik van Havre
parent 82a75e2a20
commit dcdbf75e55
15 changed files with 2564 additions and 794 deletions

View File

@ -0,0 +1,268 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskPanel</class>
<widget class="QWidget" name="TaskPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>322</width>
<height>452</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>400</height>
</size>
</property>
<property name="windowTitle">
<string>Drilling</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="Geometry">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>314</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/accessories-calculator.svg</normaloff>:/icons/FreeCAD-default/scalable/accessories-calculator.svg</iconset>
</attribute>
<attribute name="label">
<string>Base Geometry</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QPushButton" name="addBase">
<property name="toolTip">
<string>Add item selected in window.</string>
</property>
<property name="text">
<string>add</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QListWidget" name="baseList">
<property name="toolTip">
<string>Drag to reorder, then update.</string>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="reorderBase">
<property name="toolTip">
<string>Update the path with the removed and reordered items.</string>
</property>
<property name="text">
<string>Update</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="deleteBase">
<property name="toolTip">
<string>Remove Item selected in list, then update.</string>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="Depths">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>116</width>
<height>108</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/Part_Measure_Clear_All.svg</normaloff>:/icons/FreeCAD-default/scalable/Part_Measure_Clear_All.svg</iconset>
</attribute>
<attribute name="label">
<string>Depths</string>
</attribute>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="Gui::InputField" name="startDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Start Depth</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Gui::InputField" name="finalDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Final Depth</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="Gui::InputField" name="peckDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Peck Depth</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>150</width>
<height>108</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/document-open.svg</normaloff>:/icons/FreeCAD-default/scalable/document-open.svg</iconset>
</attribute>
<attribute name="label">
<string>Heights</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="Gui::InputField" name="safeHeight">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Safe Height</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Gui::InputField" name="clearanceHeight">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Clearance Height</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="Gui::InputField" name="retractHeight">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Retract Height</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_3">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>234</width>
<height>50</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/user.svg</normaloff>:/icons/FreeCAD-default/scalable/user.svg</iconset>
</attribute>
<attribute name="label">
<string>Operation</string>
</attribute>
<layout class="QFormLayout" name="formLayout_5">
<item row="0" column="0">
<widget class="QComboBox" name="algorithmSelect">
<item>
<property name="text">
<string>OCC Native Outline</string>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Algorithm</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../Gui/Icons/resource.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,373 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskPanel</class>
<widget class="QWidget" name="TaskPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>352</width>
<height>525</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>400</height>
</size>
</property>
<property name="windowTitle">
<string>Pocket</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="Geometry">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>327</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/accessories-calculator.svg</normaloff>:/icons/FreeCAD-default/scalable/accessories-calculator.svg</iconset>
</attribute>
<attribute name="label">
<string>Base Geometry</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="3">
<widget class="QListWidget" name="baseList">
<property name="toolTip">
<string>Drag to reorder, then update.</string>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="addBase">
<property name="toolTip">
<string>Add item selected in window.</string>
</property>
<property name="text">
<string>add</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="deleteBase">
<property name="toolTip">
<string>Remove Item selected in list, then update.</string>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="reorderBase">
<property name="toolTip">
<string>Update the path with the removed and reordered items.</string>
</property>
<property name="text">
<string>Update</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>All objects will be profiled using the same depth and speed settings</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="Depths">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>327</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/Part_Measure_Clear_All.svg</normaloff>:/icons/FreeCAD-default/scalable/Part_Measure_Clear_All.svg</iconset>
</attribute>
<attribute name="label">
<string>Depths</string>
</attribute>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="Gui::InputField" name="startDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Start Depth</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Gui::InputField" name="finalDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Final Depth</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="Gui::InputField" name="finishDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Finish Depth</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="stepDown">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Step Down</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="Heights">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>327</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/document-open.svg</normaloff>:/icons/FreeCAD-default/scalable/document-open.svg</iconset>
</attribute>
<attribute name="label">
<string>Heights</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="Gui::InputField" name="safeHeight">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Safe Height</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Gui::InputField" name="clearanceHeight">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Clearance Height</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="Entry">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>327</height>
</rect>
</property>
<attribute name="label">
<string>Entry</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3"/>
</widget>
<widget class="QWidget" name="Pattern">
<attribute name="label">
<string>Pattern</string>
</attribute>
</widget>
<widget class="QWidget" name="page_3">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>327</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/user.svg</normaloff>:/icons/FreeCAD-default/scalable/user.svg</iconset>
</attribute>
<attribute name="label">
<string>Operation</string>
</attribute>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Algorithm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="algorithmSelect">
<item>
<property name="text">
<string>OCC Native</string>
</property>
</item>
<item>
<property name="text">
<string>libarea</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QWidget" name="widget_3" native="true">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Cut Mode</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cutMode">
<item>
<property name="text">
<string>Climb</string>
</property>
</item>
<item>
<property name="text">
<string>Conventional</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QWidget" name="widget_2" native="true">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="useStartPoint">
<property name="text">
<string>Use Start Point</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QWidget" name="widget_4" native="true">
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Material Allowance</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="extraOffset"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../Gui/Icons/resource.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,450 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskPanel</class>
<widget class="QWidget" name="TaskPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>352</width>
<height>525</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>400</height>
</size>
</property>
<property name="windowTitle">
<string>Profile</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="Geometry">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>357</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/accessories-calculator.svg</normaloff>:/icons/FreeCAD-default/scalable/accessories-calculator.svg</iconset>
</attribute>
<attribute name="label">
<string>Base Geometry</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="3">
<widget class="QListWidget" name="baseList">
<property name="toolTip">
<string>Drag to reorder, then update.</string>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="addBase">
<property name="toolTip">
<string>Add item selected in window.</string>
</property>
<property name="text">
<string>add</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="deleteBase">
<property name="toolTip">
<string>Remove Item selected in list, then update.</string>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="reorderBase">
<property name="toolTip">
<string>Update the path with the removed and reordered items.</string>
</property>
<property name="text">
<string>Update</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>All objects will be profiled using the same depth and speed settings</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="Depths">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>357</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/Part_Measure_Clear_All.svg</normaloff>:/icons/FreeCAD-default/scalable/Part_Measure_Clear_All.svg</iconset>
</attribute>
<attribute name="label">
<string>Depths</string>
</attribute>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="Gui::InputField" name="startDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Start Depth</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Gui::InputField" name="finalDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Final Depth</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="stepDown">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Step Down</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="Heights">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>357</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/document-open.svg</normaloff>:/icons/FreeCAD-default/scalable/document-open.svg</iconset>
</attribute>
<attribute name="label">
<string>Heights</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="Gui::InputField" name="safeHeight">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Safe Height</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Gui::InputField" name="clearanceHeight">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Clearance Height</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="Holding">
<attribute name="label">
<string>Holding</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" colspan="2">
<widget class="QTreeWidget" name="tagTree">
<column>
<property name="text">
<string>Tag</string>
</property>
</column>
<column>
<property name="text">
<string>Location</string>
</property>
</column>
<column>
<property name="text">
<string>Height</string>
</property>
</column>
<column>
<property name="text">
<string>Length</string>
</property>
</column>
<column>
<property name="text">
<string>Angle</string>
</property>
</column>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="addTag">
<property name="text">
<string>Add New</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="deleteTag">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_3">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>357</height>
</rect>
</property>
<attribute name="icon">
<iconset resource="../../../Gui/Icons/resource.qrc">
<normaloff>:/icons/FreeCAD-default/scalable/user.svg</normaloff>:/icons/FreeCAD-default/scalable/user.svg</iconset>
</attribute>
<attribute name="label">
<string>Operation</string>
</attribute>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Algorithm</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="algorithmSelect">
<item>
<property name="text">
<string>OCC Native</string>
</property>
</item>
<item>
<property name="text">
<string>libarea</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QWidget" name="widget_3" native="true">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Cut Side</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cutSide">
<item>
<property name="text">
<string>Left</string>
</property>
</item>
<item>
<property name="text">
<string>Right</string>
</property>
</item>
<item>
<property name="text">
<string>On</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Direction</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="direction">
<item>
<property name="text">
<string>CW</string>
</property>
</item>
<item>
<property name="text">
<string>CCW</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QWidget" name="widget_2" native="true">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="useStartPoint">
<property name="text">
<string>Use Start Point</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="useCompensation">
<property name="text">
<string>Use Compensation</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="useEndPoint">
<property name="text">
<string>Use End Point</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QWidget" name="widget_4" native="true">
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Extra Offset</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="extraOffset"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Segment Length</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="segLen"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Roll Radius</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="rollRadius"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../Gui/Icons/resource.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -378,12 +378,9 @@ def pocket(a,tool_radius, extra_offset, stepover, depthparams, from_center, keep
use_internal_function = (area.holes_linked() == False) # use internal function, if area module is the Clipper library
if use_internal_function:
print "using internal. PathAreaUtils:382 "
curve_list = a.MakePocketToolpath(tool_radius, extra_offset, stepover, from_center, use_zig_zag, zig_angle)
else:
print "not using internal. PathAreaUtils:386 "
global sin_angle_for_zigs
global cos_angle_for_zigs
global sin_minus_angle_for_zigs
@ -421,14 +418,12 @@ def pocket(a,tool_radius, extra_offset, stepover, depthparams, from_center, keep
depths = depthparams.get_depths()
current_start_depth = depthparams.start_depth
print "Startpoint: " + str(start_point)
if start_point==None:
for depth in depths:
cut_curvelist1(curve_list, depthparams.rapid_safety_space, current_start_depth, depth, depthparams.clearance_height, keep_tool_down_if_poss)
current_start_depth = depth
else:
print "PathAreaUtils:438 I guess it IS used. Who knew?"
for depth in depths:
cut_curvelist2(curve_list, depthparams.rapid_safety_space, current_start_depth, depth, depthparams.clearance_height, keep_tool_down_if_poss, start_point)
current_start_depth = depth

View File

@ -22,7 +22,7 @@
#* *
#***************************************************************************
import FreeCAD,FreeCADGui,Path,PathGui
import FreeCAD,FreeCADGui,Path,PathGui, PathUtils
from PySide import QtCore,QtGui
"""Path Compound Extended object and FreeCAD command"""
@ -54,6 +54,13 @@ class ObjectCompoundExtended:
def __setstate__(self,state):
return None
def onChanged(self,obj,prop):
if prop == "Group":
print 'check order'
for child in obj.Group:
if child.isDerivedFrom("Path::Feature"):
child.touch()
def execute(self,obj):
cmds = []
for child in obj.Group:

View File

@ -49,12 +49,13 @@ class ObjectDrilling:
obj.addProperty("App::PropertyLinkSubList","Base","Path",translate("Parent Object(s)","The base geometry of this toolpath"))
obj.addProperty("App::PropertyVectorList","locations","Path","The drilling locations")
obj.addProperty("App::PropertyLength", "PeckDepth", "Depth", translate("PeckDepth","Incremental Drill depth before retracting to clear chips"))
#obj.addProperty("App::PropertyFloat", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Clearance Height","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Final Depth","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyLength", "PeckDepth", "Depth", translate("PathProject","Incremental Drill depth before retracting to clear chips"))
obj.addProperty("App::PropertyLength", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("PathProject","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("PathProject","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("PathProject","Height to clear top of materil"))
obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", translate("Retract Height","The height where feed starts and height during retract tool when path is finished"))
obj.addProperty("App::PropertyLength", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
#obj.addProperty("App::PropertyLength", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertyString","Comment","Path",translate("PathProject","An optional comment for this profile"))
obj.addProperty("App::PropertyBool","Active","Path",translate("Active","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("PathProfile","The tool number in use"))
@ -70,65 +71,75 @@ class ObjectDrilling:
return None
def execute(self,obj):
locations = []
for loc in obj.Base:
if "Face" in loc[1] or "Edge" in loc[1]:
s = getattr(loc[0].Shape,loc[1])
else:
s = loc[0].Shape
if s.ShapeType in ['Face', 'Wire', 'Edge' ]:
X = s.Edges[0].Curve.Center.x
Y = s.Edges[0].Curve.Center.y
Z = s.Edges[0].Curve.Center.z
elif s.ShapeType == 'Vertex':
X = s.Point.x
Y = s.Point.y
Z = s.Point.z
locations.append(FreeCAD.Vector(X,Y,Z))
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
tool = PathUtils.getTool(obj,obj.ToolNumber)
output = "G90 G98\n"
# rapid to clearance height
output += "G0 Z" + str(obj.ClearanceHeight.Value)
# rapid to first hole location, with spindle still retracted:
p0 = locations[0]
output += "G0 X"+str(p0.x) + " Y" + str(p0.y)+ "\n"
# move tool to clearance plane
output += "G0 Z" + str(obj.ClearanceHeight.Value) + "\n"
if obj.PeckDepth.Value > 0:
cmd = "G83"
qword = " Q"+ str(obj.PeckDepth.Value)
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad == None:
self.vertFeed = 100
self.horizFeed = 100
radius = 0.25
obj.ToolNumber= 0
else:
cmd = "G81"
qword = ""
for p in locations:
self.vertFeed = toolLoad.VertFeed.Value
self.horizFeed = toolLoad.HorizFeed.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
radius = tool.Diameter/2
obj.ToolNumber= toolLoad.ToolNumber
if obj.Base:
locations = []
for loc in obj.Base:
output += cmd + " X" + str(p.x) + " Y" + str(p.y) + " Z" + str(obj.FinalDepth.Value) + qword + " R" + str(obj.RetractHeight.Value) + " F" + str(obj.VertFeed.Value) + "\n"
if "Face" in loc[1] or "Edge" in loc[1]:
s = getattr(loc[0].Shape,loc[1])
else:
s = loc[0].Shape
output += "G80\n"
if s.ShapeType in ['Face', 'Wire', 'Edge' ]:
X = s.Edges[0].Curve.Center.x
Y = s.Edges[0].Curve.Center.y
Z = s.Edges[0].Curve.Center.z
elif s.ShapeType == 'Vertex':
X = s.Point.x
Y = s.Point.y
Z = s.Point.z
locations.append(FreeCAD.Vector(X,Y,Z))
output = "G90 G98\n"
# rapid to clearance height
output += "G0 Z" + str(obj.ClearanceHeight.Value)
# rapid to first hole location, with spindle still retracted:
p0 = locations[0]
output += "G0 X"+str(p0.x) + " Y" + str(p0.y)+ "\n"
# move tool to clearance plane
output += "G0 Z" + str(obj.ClearanceHeight.Value) + "\n"
if obj.PeckDepth.Value > 0:
cmd = "G83"
qword = " Q"+ str(obj.PeckDepth.Value)
else:
cmd = "G81"
qword = ""
for p in locations:
output += cmd + " X" + str(p.x) + " Y" + str(p.y) + " Z" + str(obj.FinalDepth.Value) + qword + " R" + str(obj.RetractHeight.Value) + " F" + str(self.vertFeed) + "\n"
output += "G80\n"
path = Path.Path(output)
obj.Path = path
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
class ViewProviderDrill:
def addDrillableLocation(self, obj, ss, sub=""):
baselist = obj.Base
item = (ss, sub)
if item in baselist:
FreeCAD.Console.PrintWarning("Drillable location already in the list"+ "\n")
else:
baselist.append (item)
obj.Base = baselist
self.execute(obj)
class _ViewProviderDrill:
def __init__(self,obj): #mandatory
# obj.addProperty("App::PropertyFloat","SomePropertyName","PropertyGroup","Description of this property")
obj.Proxy = self
def __getstate__(self): #mandatory
@ -152,19 +163,21 @@ class ViewProviderDrill:
# this is executed when a property of the APP OBJECT changes
pass
def setEdit(self,vobj,mode): #optional
# this is executed when the object is double-clicked in the tree
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 CommandPathDrilling:
def GetResources(self):
return {'Pixmap' : 'Path-Drilling',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Drilling","Drilling"),
@ -174,96 +187,8 @@ class CommandPathDrilling:
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Drillable(self, obj):
import Part
drillable = ""
if obj.ShapeType == 'Vertex':
drillable = 'Vertex'
elif obj.ShapeType == 'Edge':
if isinstance(obj.Curve, Part.Circle):
drillable = 'Circle'
elif obj.ShapeType == 'Face':
if isinstance(obj.Edges[0].Curve, Part.Circle):
drillable = 'Circle'
elif obj.ShapeType == 'Wire':
if isinstance(obj.Edges[0].Curve, Part.Circle):
drillable = 'Circle'
else:
drillable = None
return drillable
def Activated(self):
import Path
import Part
from PathScripts import PathUtils,PathDrilling,PathProject
prjexists = False
selection = FreeCADGui.Selection.getSelectionEx()
if not selection:
FreeCAD.Console.PrintError(translate("PathDrilling","Please select points or cirlces for drilling.\n"))
return
diamcount = 0 #keep track of how many different hole sizes we're asked to deal with
lastradius = 0.0
locations = []
vertexcount = 0 #keep track of how many vertices
for s in selection:
if s.HasSubObjects:
for i in s.SubObjects:
d = self.Drillable (i)
if d == 'Circle':
if i.Edges[0].Curve.Radius != lastradius:
diamcount += 1
lastradius = i.Edges[0].Curve.Radius
elif d == 'Vertex':
vertexcount += 1
else:
FreeCAD.Console.PrintError(translate("PathDrilling","No drillable locations were selected.\n"))
return
#subs = []
for n in s.SubElementNames:
# subs.append(n)
locations.append((s.ObjectName, s.Object, n))
else:
d = self.Drillable (s.Object.Shape)
if d == 'Circle':
if not str(s.Object.Shape.Edges[0].Curve.Radius) == str(lastradius):
diamcount += 1
lastradius = s.Object.Shape.Edges[0].Curve.Radius
elif d == 'Vertex':
vertexcount += 1
else:
FreeCAD.Console.PrintError(translate("PathDrilling","No drillable locations were selected.\n"))
return
locations.append((s.ObjectName, s.Object, []))
if diamcount > 1:
FreeCAD.Console.PrintError(translate("PathDrilling","Circles of different radii found. Select only one size circle at a time.\n"))
return
if diamcount >= 1 and vertexcount >= 1:
FreeCAD.Console.PrintError(translate("PathDrilling","Please select either points or circles but not both.\n"))
return
# Take a guess at some reasonable values for Finish depth.
if selection[0].HasSubObjects:
bb = selection[0].Object.Shape.BoundBox #parent boundbox
fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
if fbb.ZMax < bb.ZMax:
zbottom = fbb.ZMax
ztop = bb.ZMax + 1
else:
zbottom = bb.ZMin
ztop = 5
else:
zbottom = 0
ztop = 5
import Path, Part
# if everything is ok, execute and register the transaction in the undo/redo stack
@ -272,15 +197,10 @@ class CommandPathDrilling:
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Drilling")')
FreeCADGui.doCommand('PathScripts.PathDrilling.ObjectDrilling(obj)')
FreeCADGui.doCommand('obj.Active = True')
FreeCADGui.doCommand('PathScripts.PathDrilling.ViewProviderDrill(obj.ViewObject)')
FreeCADGui.doCommand('PathScripts.PathDrilling._ViewProviderDrill(obj.ViewObject)')
baselist = "["
for loc in locations:
baselist += "(FreeCAD.ActiveDocument." + str(loc[0]) + ',"' + str(loc[2]) + '"),'
baselist += "]"
FreeCADGui.doCommand('obj.Base = (' + baselist + ')')
FreeCADGui.doCommand('from PathScripts import PathUtils')
ztop = 10.0
zbottom = 0.0
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop))
FreeCADGui.doCommand('obj.RetractHeight= ' + str(ztop))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
@ -288,6 +208,147 @@ class CommandPathDrilling:
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/DrillingEdit.ui")
#self.form = FreeCADGui.PySideUic.loadUi(":/DrillingEdit.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,"PeckDepth"):
self.obj.PeckDepth = self.form.peckDepth.text()
if hasattr(self.obj,"SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
if hasattr(self.obj,"ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
if hasattr(self.obj,"RetractHeight"):
self.obj.RetractHeight = self.form.retractHeight.text()
self.obj.Proxy.execute(self.obj)
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 not len(selection) >= 1:
FreeCAD.Console.PrintError(translate("PathProject","Please select at least one Drillable Location\n"))
return
for s in selection:
if s.HasSubObjects:
for i in s.SubElementNames:
self.obj.Proxy.addDrillableLocation(self.obj, s.Object, i)
else:
self.obj.Proxy.addDrillableLocation(self.obj, s.Object)
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().partition(".")[0]:
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:
objstring = i.text().partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
# sub = o.Shape.getElement(objstring[2])
if objstring[2] != "":
FreeCADGui.Selection.addSelection(obj,objstring[2])
else:
FreeCADGui.Selection.addSelection(obj)
FreeCADGui.updateGui()
def reorderBase(self):
newlist = []
for i in range(self.form.baseList.count()):
s = self.form.baseList.item(i).text()
objstring = s.partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
item = (obj, str(objstring[2]))
newlist.append(item)
self.obj.Base=newlist
self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok)
def setupUi(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.peckDepth.setText(str(self.obj.PeckDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.retractHeight.setText(str(self.obj.RetractHeight.Value))
for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name + "." + i[1])
#Connect Signals and Slots
self.form.startDepth.editingFinished.connect(self.getFields) #This is newer syntax
#QtCore.QObject.connect(self.form.startDepth, QtCore.SIGNAL("editingFinished()"), self.getFields)
QtCore.QObject.connect(self.form.finalDepth, QtCore.SIGNAL("editingFinished()"), self.getFields)
QtCore.QObject.connect(self.form.safeHeight, QtCore.SIGNAL("editingFinished()"), self.getFields)
QtCore.QObject.connect(self.form.clearanceHeight, QtCore.SIGNAL("editingFinished()"), self.getFields)
QtCore.QObject.connect(self.form.addBase, QtCore.SIGNAL("clicked()"), self.addBase)
QtCore.QObject.connect(self.form.deleteBase, QtCore.SIGNAL("clicked()"), self.deleteBase)
QtCore.QObject.connect(self.form.reorderBase, QtCore.SIGNAL("clicked()"), self.reorderBase)
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
class SelObserver:
def __init__(self):
import PathScripts.PathSelection as PST
PST.drillselect()
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:

View File

@ -25,6 +25,7 @@
import FreeCAD,FreeCADGui,Path,PathGui,Draft
from PySide import QtCore,QtGui
from PathScripts import PathUtils,PathProject
"""Path Engrave object and FreeCAD command"""
@ -46,6 +47,10 @@ class ObjectPathEngrave:
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("Path", "The library or Algorithm used to generate the path"))
obj.Algorithm = ['OCC Native']
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("Path","The tool number in use"))
obj.ToolNumber = (0,0,1000,1)
obj.setEditorMode('ToolNumber',1) #make this read only
#Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Path","The height needed to clear clamps and obstructions"))
@ -54,8 +59,6 @@ class ObjectPathEngrave:
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Path","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyInteger","StartVertex","Path","The vertex index to start the path from")
#Feed Properties
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Path","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Path","Feed rate for horizontal moves"))
if FreeCAD.GuiUp:
_ViewProviderEngrave(obj.ViewObject)
@ -70,6 +73,20 @@ class ObjectPathEngrave:
def execute(self,obj):
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad == None:
self.vertFeed = 100
self.horizFeed = 100
radius = 0.25
obj.ToolNumber= 0
else:
self.vertFeed = toolLoad.VertFeed.Value
self.horizFeed = toolLoad.HorizFeed.Value
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
radius = tool.Diameter/2
obj.ToolNumber= toolLoad.ToolNumber
if obj.Base:
for o in obj.Base:
output += "G0 " + str(obj.ClearanceHeight.Value)+"\n"
@ -81,7 +98,6 @@ class ObjectPathEngrave:
#print output
if output == "":
#output += "G0 Z" + str(obj.ClearanceHeight.Value)
output +="G0"
path = Path.Path(output)
obj.Path = path
@ -106,7 +122,7 @@ class ObjectPathEngrave:
# we set the first move to our first point
last = edge.Vertexes[0].Point
output += "G0" + " X" + str("%f" % last.x) + " Y" + str("%f" % last.y) #Rapid sto starting position
output += "G1" + " Z" + str("%f" % last.z) +"F " + str(obj.VertFeed.Value)+ "\n" #Vertical feed to depth
output += "G1" + " Z" + str("%f" % last.z) +"F " + str(self.vertFeed)+ "\n" #Vertical feed to depth
if isinstance(edge.Curve,Part.Circle):
point = edge.Vertexes[-1].Point
if point == last: # edges can come flipped
@ -121,7 +137,7 @@ class ObjectPathEngrave:
output += "G3"
output += " X" + str("%f" % point.x) + " Y" + str("%f" % point.y) + " Z" + str("%f" % point.z)
output += " I" + str("%f" % relcenter.x) + " J" + str("%f" % relcenter.y) + " K" + str("%f" % relcenter.z)
output += " F " + str(obj.HorizFeed.Value)
output += " F " + str(self.horizFeed)
output += "\n"
last = point
else:
@ -129,7 +145,7 @@ class ObjectPathEngrave:
if point == last: # edges can come flipped
point = edge.Vertexes[0].Point
output += "G1 X" + str("%f" % point.x) + " Y" + str("%f" % point.y) + " Z" + str("%f" % point.z)
output += " F " + str(obj.HorizFeed.Value)
output += " F " + str(self.horizFeed)
output += "\n"
last = point
output += "G0 Z " + str(obj.SafeHeight.Value)
@ -232,10 +248,7 @@ class TaskPanel:
self.obj.SafeHeight = self.form.safeHeight.text()
if hasattr(self.obj,"ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
if hasattr(self.obj,"VertFeed"):
self.obj.VertFeed= self.form.vertFeed.text()
if hasattr(self.obj,"HorizFeed"):
self.obj.HorizFeed = self.form.horizFeed.text()
self.obj.Proxy.execute(self.obj)
@ -299,8 +312,7 @@ class TaskPanel:
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.vertFeed.setText(str(self.obj.VertFeed.Value))
self.form.horizFeed.setText(str(self.obj.HorizFeed.Value))
for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name)
@ -309,8 +321,6 @@ class TaskPanel:
self.form.startDepth.editingFinished.connect(self.getFields) #This is newer syntax
#QtCore.QObject.connect(self.form.startDepth, QtCore.SIGNAL("editingFinished()"), self.getFields)
QtCore.QObject.connect(self.form.finalDepth, QtCore.SIGNAL("editingFinished()"), self.getFields)
QtCore.QObject.connect(self.form.horizFeed, QtCore.SIGNAL("editingFinished()"), self.getFields)
QtCore.QObject.connect(self.form.vertFeed, QtCore.SIGNAL("editingFinished()"), self.getFields)
QtCore.QObject.connect(self.form.safeHeight, QtCore.SIGNAL("editingFinished()"), self.getFields)
QtCore.QObject.connect(self.form.clearanceHeight, QtCore.SIGNAL("editingFinished()"), self.getFields)

View File

@ -57,8 +57,8 @@ def makeAreaCurve(edges,direction,startpt=None,endpt=None):
cleanededges = Part.__sortEdges__(PathUtils.cleanedges(edges, 0.01))
for e in cleanededges:
print str(e.valueAt(e.FirstParameter)) + "," + str(e.valueAt(e.LastParameter))
#for e in cleanededges:
#print str(e.valueAt(e.FirstParameter)) + "," + str(e.valueAt(e.LastParameter))
edgelist=[]
if len(cleanededges) == 1: #user selected a single edge.
@ -270,31 +270,12 @@ def make_smaller( curve, start = None, finish = None, end_beyond = False ):
else:
curve.ChangeEnd(curve.NearestPoint(finish))
# def makePath(edges,side,radius,vertfeed,horizfeed,offset_extra,rapid_safety_space,clearance,start_depth,step_down,final_depth,use_CRC,direction,startpt=None,endpt=None):
# curve = makeAreaCurve(edges,direction,startpt, endpt)
# path = profile(curve,side,radius,vertfeed,horizfeed,offset_extra,rapid_safety_space,clearance,start_depth,step_down,final_depth,use_CRC)
# del curve
# return path
# def edgedumper (mylist):
# import Part, PathUtils
# print "The amazing edgedumper"
# print "mylist: " + str(mylist)
# edgs = PathUtils.cleanedges(mylist, 0.01)
# edgs = Part.Wire(edgs)
# for i in edgs.Edges:
# mystring = str(i)
# for v in i.Vertexes:
# mystring = mystring + " : " + str(v.Point)
# print mystring
'''The following procedures are copied almost directly from heekscnc kurve_funcs.py. They depend on nc directory existing below PathScripts and have not been
throughly optimized, understood, or tested for FreeCAD.'''
def profile2(curve, direction = "on", radius = 1.0, vertfeed=0.0,horizfeed=0.0, offset_extra = 0.0, roll_radius = 2.0, roll_on = None, roll_off = None, depthparams = None, extend_at_start = 0.0, extend_at_end = 0.0, lead_in_line_len=0.0,lead_out_line_len= 0.0):
print "we're in"
from PathScripts.nc.nc import *
global tags
direction = direction.lower()

View File

@ -70,11 +70,11 @@ class LoadTool:
def onChanged(self,obj,prop):
mode = 2
obj.setEditorMode('Placement',mode)
if prop == "ToolNumber":
proj = PathUtils.findProj()
for g in proj.Group:
if not(isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool)):
g.touch()
#if prop == "ToolNumber":
proj = PathUtils.findProj()
for g in proj.Group:
if not(isinstance(g.Proxy, PathScripts.PathLoadTool.LoadTool)):
g.touch()
class _ViewProviderLoadTool:
@ -110,9 +110,9 @@ class _ViewProviderLoadTool:
vobj.setEditorMode('DisplayMode',mode)
vobj.setEditorMode('BoundingBox',mode)
vobj.setEditorMode('Selectable',mode)
vobj.setEditorMode('ShapeColor',mode)
vobj.setEditorMode('Transparency',mode)
vobj.setEditorMode('Visibility',mode)
#vobj.setEditorMode('ShapeColor',mode)
#vobj.setEditorMode('Transparency',mode)
#vobj.setEditorMode('Visibility',mode)
def updateData(self,vobj,prop): #optional
# this is executed when a property of the APP OBJECT changes
@ -137,15 +137,12 @@ class CommandPathLoadTool:
return not FreeCAD.ActiveDocument is None
def Activated(self):
FreeCAD.ActiveDocument.openTransaction(translate("Current Tool","Tool Number to Load"))
FreeCADGui.addModule("PathScripts.PathLoadTool")
snippet = '''
import Path
import PathScripts
from PathScripts import PathProject, PathUtils
prjexists = False
import Path, PathScripts
from PathScripts import PathUtils, PathLoadTool
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Tool")
PathScripts.PathLoadTool.LoadTool(obj)
PathScripts.PathLoadTool._ViewProviderLoadTool(obj.ViewObject)
PathUtils.addToProject(obj)
@ -154,6 +151,18 @@ PathUtils.addToProject(obj)
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
@staticmethod
def Create():
#FreeCADGui.addModule("PathScripts.PathLoadTool")
import Path, PathScripts, PathUtils
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Tool")
PathScripts.PathLoadTool.LoadTool(obj)
PathScripts.PathLoadTool._ViewProviderLoadTool(obj.ViewObject)
PathUtils.addToProject(obj)
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_LoadTool', CommandPathLoadTool())

View File

@ -47,7 +47,7 @@ class ObjectPocket:
def __init__(self,obj):
obj.addProperty("App::PropertyLinkSub","Base","Path",translate("PathProject","The base geometry of this object"))
obj.addProperty("App::PropertyLinkSubList","Base","Path",translate("PathProject","The base geometry of this object"))
obj.addProperty("App::PropertyBool","Active","Path",translate("PathProject","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyString","Comment","Path",translate("PathProject","An optional comment for this profile"))
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("PathProject", "The library to use to generate the path"))
@ -59,29 +59,18 @@ class ObjectPocket:
obj.setEditorMode('ToolNumber',1) #make this read only
#Depth Properties
obj.addProperty("App::PropertyFloat", "ClearanceHeight", "Depth", translate("PathProject","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyFloat", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("PathProject","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", translate("PathProject","Incremental Step Down of Tool"))
obj.StepDown = (0.0, 0.01, 100.0, 0.5)
obj.addProperty("App::PropertyFloat", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyFloat", "FinalDepth", "Depth", translate("PathProject","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyFloat", "FinishDepth", "Depth", translate("PathProject","Maximum material removed on final pass."))
#obj.addProperty("App::PropertyFloat", "RetractHeight", "Depth", translate("PathProject","The height desired to retract tool when path is finished"))
# #Feed Properties
# obj.addProperty("App::PropertyFloatConstraint", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
# obj.VertFeed = (0.0, 0.0, 100000.0, 1.0)
# obj.addProperty("App::PropertyFloatConstraint", "HorizFeed", "Feed",translate("Horiz Feed","Feed rate for horizontal moves"))
# obj.HorizFeed = (0.0, 0.0, 100000.0, 1.0)
#Feed Properties
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Path","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Path","Feed rate for horizontal moves"))
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("PathProject","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyDistance", "FinishDepth", "Depth", translate("PathProject","Maximum material removed on final pass."))
#Pocket Properties
obj.addProperty("App::PropertyEnumeration", "CutMode", "Pocket",translate("PathProject", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
obj.CutMode = ['Climb','Conventional']
obj.addProperty("App::PropertyFloat", "MaterialAllowance", "Pocket", translate("PathProject","Amount of material to leave"))
obj.addProperty("App::PropertyDistance", "MaterialAllowance", "Pocket", translate("PathProject","Amount of material to leave"))
obj.addProperty("App::PropertyEnumeration", "StartAt", "Pocket",translate("PathProject", "Start pocketing at center or boundary"))
obj.StartAt = ['Center', 'Edge']
obj.addProperty("App::PropertyFloatConstraint","StepOver","Pocket",translate("PathProject","Amount to step over on each pass"))
@ -122,7 +111,21 @@ class ObjectPocket:
def __setstate__(self,state):
return None
def addpocketbase(self, obj, ss, sub=""):
#sublist = []
#sublist.append(sub)
baselist = obj.Base
if baselist == None:
baselist = []
item = (ss, sub)
if item in baselist:
FreeCAD.Console.PrintWarning("this object already in the list"+ "\n")
else:
baselist.append (item)
obj.Base = baselist
print "this base is: " + str(baselist)
self.execute(obj)
def getStock(self,obj):
"retrieves a stock object from hosting project if any"
@ -144,10 +147,10 @@ class ObjectPocket:
FreeCAD.Console.PrintMessage(translate("PathPocket","Generating toolpath with libarea offsets.\n"))
depthparams = depth_params (obj.ClearanceHeight, obj.SafeHeight, obj.StartDepth, obj.StepDown, obj.FinishDepth, obj.FinalDepth)
depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value)
horizfeed = obj.HorizFeed.Value
extraoffset = obj.MaterialAllowance
horizfeed = self.horizFeed
extraoffset = obj.MaterialAllowance.Value
stepover = obj.StepOver
use_zig_zag = obj.UseZigZag
zig_angle = obj.ZigZagAngle
@ -159,15 +162,26 @@ class ObjectPocket:
PathAreaUtils.flush_nc()
PathAreaUtils.output('mem')
PathAreaUtils.feedrate_hv(obj.HorizFeed.Value, obj.VertFeed.Value)
PathAreaUtils.feedrate_hv(self.horizFeed, self.vertFeed)
if obj.UseStartPoint:
start_point = (obj.StartPoint.x,obj.StartPoint.y)
print "a," + str(self.radius) + "," + str(extraoffset) + "," + str(stepover) + ",depthparams, " + str(from_center) + "," + str(keep_tool_down) + "," + str(use_zig_zag) + "," + str(zig_angle) + "," + str(zig_unidirectional) + "," + str(start_point) + "," + str(cut_mode)
#print "a," + str(self.radius) + "," + str(extraoffset) + "," + str(stepover) + ",depthparams, " + str(from_center) + "," + str(keep_tool_down) + "," + str(use_zig_zag) + "," + str(zig_angle) + "," + str(zig_unidirectional) + "," + str(start_point) + "," + str(cut_mode)
PathAreaUtils.pocket(a,self.radius,extraoffset, stepover,depthparams,from_center,keep_tool_down,use_zig_zag,zig_angle,zig_unidirectional,start_point,cut_mode)
PathAreaUtils.pocket(a,\
self.radius,\
extraoffset, \
stepover,\
depthparams,\
from_center,\
keep_tool_down,\
use_zig_zag,\
zig_angle,\
zig_unidirectional,\
start_point,\
cut_mode)
return PathAreaUtils.retrieve_gcode()
@ -197,9 +211,9 @@ class ObjectPocket:
global feedxy
retstr = "G01 F"
if(x == None) and (y == None):
retstr += str("%.4f" % obj.HorizFeed.Value)
retstr += str("%.4f" % self.horizFeed)
else:
retstr += str("%.4f" % obj.VertFeed.Value)
retstr += str("%.4f" % self.vertFeed)
if (x != None) or (y != None) or (z != None):
if (x != None):
@ -228,7 +242,7 @@ class ObjectPocket:
retstr += "G03 F"
else:
retstr += "G02 F"
retstr += str(obj.HorizFeed.Value)
retstr += str(self.horizFeed)
#End location
retstr += " X" + str("%.4f" % ex) + " Y" + str("%.4f" % ey)
@ -350,16 +364,16 @@ class ObjectPocket:
# first move will be rapid, subsequent will be at feed rate
first = True
startPoint = None
fastZPos = max(obj.StartDepth + 2, obj.ClearanceHeight)
fastZPos = max(obj.StartDepth.Value + 2, obj.ClearanceHeight.Value)
# revert the list so we start with the outer wires
if obj.StartAt != 'Edge':
offsets.reverse()
# print "startDepth: " + str(obj.StartDepth)
# print "finalDepth: " + str(obj.FinalDepth)
# print "startDepth: " + str(obj.StartDepth.Value)
# print "finalDepth: " + str(obj.FinalDepth.Value)
# print "stepDown: " + str(obj.StepDown)
# print "finishDepth" + str(obj.FinishDepth)
# print "finishDepth" + str(obj.FinishDepth.Value)
# print "offsets:", len(offsets)
#Fraction of tool radius our plunge helix is to be
@ -421,7 +435,7 @@ class ObjectPocket:
#FIXME: Can probably get this from the "machine"?
lastZ = fastZPos
for vpos in PathUtils.frange(obj.StartDepth, obj.FinalDepth, obj.StepDown, obj.FinishDepth):
for vpos in PathUtils.frange(obj.StartDepth.Value, obj.FinalDepth.Value, obj.StepDown, obj.FinishDepth.Value):
#Every for every depth we should helix down
first = True
# loop over successive wires
@ -483,71 +497,77 @@ class ObjectPocket:
#To reload this from FreeCAD, use: import PathScripts.PathPocket; reload(PathScripts.PathPocket)
def execute(self,obj):
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad == None:
self.vertFeed = 100
self.horizFeed = 100
self.radius = 0.25
obj.ToolNumber = 0
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
if obj.Base:
import Part, PathScripts.PathKurveUtils, DraftGeomUtils
if "Face" in obj.Base[1][0]:
shape = getattr(obj.Base[0].Shape,obj.Base[1][0])
wire = shape.OuterWire
edges = wire.Edges
else:
edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]]
print "myedges: " + str(edges)
wire = Part.Wire(edges)
shape = None
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
tool = PathUtils.getTool(obj,obj.ToolNumber)
if tool:
self.radius = tool.Diameter/2
else:
# temporary value,in case we don't have any tools defined already
self.radius = 0.25
output = ""
if obj.Algorithm == "OCC Native":
if shape == None:
shape = wire
output += self.buildpathocc(obj, shape)
else:
try:
import area
except:
FreeCAD.Console.PrintError(translate("PathKurve","libarea needs to be installed for this command to work.\n"))
return
a = area.Area()
if shape == None:
c = PathScripts.PathKurveUtils.makeAreaCurve(wire.Edges, 'CW')
a.append(c)
for b in obj.Base:
print "object base: " + str(b)
import Part, PathScripts.PathKurveUtils, DraftGeomUtils
if "Face" in b[1]:
print "inside"
shape = getattr(b[0].Shape,b[1])
wire = shape.OuterWire
edges = wire.Edges
else:
for w in shape.Wires:
c = PathScripts.PathKurveUtils.makeAreaCurve(w.Edges, 'CW')
# if w.isSame(shape.OuterWire):
# print "outerwire"
# if c.IsClockwise():
# c.Reverse()
# print "reverse outterwire"
# else:
# print "inner wire"
# if not c.IsClockwise():
# c.Reverse()
# print "reverse inner"
a.append(c)
print "in else"
edges = [getattr(b[0].Shape,sub) for sub in b[1]]
print "myedges: " + str(edges)
wire = Part.Wire(edges)
shape = None
########
##This puts out some interesting information from libarea
print a.text()
########
a.Reorder()
output += self.buildpathlibarea(obj, a)
# output = ""
if obj.Algorithm == "OCC Native":
if shape == None:
shape = wire
output += self.buildpathocc(obj, shape)
else:
try:
import area
except:
FreeCAD.Console.PrintError(translate("PathKurve","libarea needs to be installed for this command to work.\n"))
return
a = area.Area()
if shape == None:
c = PathScripts.PathKurveUtils.makeAreaCurve(wire.Edges, 'CW')
a.append(c)
else:
for w in shape.Wires:
c = PathScripts.PathKurveUtils.makeAreaCurve(w.Edges, 'CW')
# if w.isSame(shape.OuterWire):
# print "outerwire"
# if c.IsClockwise():
# c.Reverse()
# print "reverse outterwire"
# else:
# print "inner wire"
# if not c.IsClockwise():
# c.Reverse()
# print "reverse inner"
a.append(c)
########
##This puts out some interesting information from libarea
print a.text()
########
a.Reorder()
output += self.buildpathlibarea(obj, a)
if obj.Active:
@ -586,14 +606,11 @@ class ViewProviderPocket:
return
def setEdit(self,vobj,mode=0):
import PocketEdit
FreeCADGui.Control.closeDialog()
taskd = QtGui.QWidget()
taskd = PocketEdit.Ui_Dialog()
taskd = TaskPanel()
taskd.obj = vobj.Object
#taskd.update()
FreeCADGui.Control.showDialog(taskd)
taskd.setupUi()
return True
def getIcon(self):
@ -621,37 +638,40 @@ class CommandPathPocket:
def Activated(self):
# check that the selection contains exactly what we want
selection = FreeCADGui.Selection.getSelectionEx()
if len(selection) != 1:
FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n"))
return
if len(selection[0].SubObjects) == 0:
FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n"))
return
for s in selection[0].SubObjects:
if s.ShapeType != "Edge":
if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1):
FreeCAD.Console.PrintError(translate("PathPocket","Please select only edges or a single face\n"))
return
if selection[0].SubObjects[0].ShapeType == "Edge":
try:
import Part
w = Part.Wire(selection[0].SubObjects)
if w.isClosed() == False:
FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n"))
return
# selection = FreeCADGui.Selection.getSelectionEx()
# if len(selection) != 1:
# FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n"))
# return
# if len(selection[0].SubObjects) == 0:
# FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n"))
# return
# for s in selection[0].SubObjects:
# if s.ShapeType != "Edge":
# if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1):
# FreeCAD.Console.PrintError(translate("PathPocket","Please select only edges or a single face\n"))
# return
# if selection[0].SubObjects[0].ShapeType == "Edge":
# try:
# import Part
# w = Part.Wire(selection[0].SubObjects)
# if w.isClosed() == False:
# FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n"))
# return
except:
FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n"))
return
# except:
# FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n"))
# return
# Take a guess at some reasonable values for Finish depth.
bb = selection[0].Object.Shape.BoundBox #parent boundbox
fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
if fbb.ZMax < bb.ZMax:
zbottom = fbb.ZMax
else:
zbottom = bb.ZMin
# bb = selection[0].Object.Shape.BoundBox #parent boundbox
# fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
# if fbb.ZMax < bb.ZMax:
# zbottom = fbb.ZMax
# else:
# zbottom = bb.ZMin
zbottom = 0.0
ztop = 10.0
# if everything is ok, execute and register the transaction in the undo/redo stack
FreeCAD.ActiveDocument.openTransaction(translate("PathPocket","Create Pocket"))
@ -663,19 +683,13 @@ class CommandPathPocket:
FreeCADGui.doCommand('obj.Active = True')
FreeCADGui.doCommand('PathScripts.PathPocket.ViewProviderPocket(obj.ViewObject)')
subs = "["
for s in selection[0].SubElementNames:
subs += '"' + s + '",'
subs += "]"
FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' + selection[0].ObjectName + ',' + subs + ')')
FreeCADGui.doCommand('from PathScripts import PathUtils')
FreeCADGui.doCommand('obj.StepOver = 1.0')
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(bb.ZMax + 2.0))
FreeCADGui.doCommand('obj.ClearanceHeight = 10')# + str(bb.ZMax + 2.0))
FreeCADGui.doCommand('obj.StepDown = 1.0')
FreeCADGui.doCommand('obj.StartDepth= ' + str(bb.ZMax))
FreeCADGui.doCommand('obj.StartDepth= ' + str(ztop))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
FreeCADGui.doCommand('obj.ZigZagAngle=45')
FreeCADGui.doCommand('obj.UseEntry=True')
@ -687,7 +701,172 @@ class CommandPathPocket:
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/PocketEdit.ui")
#self.form = FreeCADGui.PySideUic.loadUi(":/PocketEdit.ui")
self.updating = False
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,"SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
if hasattr(self.obj,"ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
if hasattr(self.obj,"StepDown"):
self.obj.StepDown = self.form.stepDown.value()
if hasattr(self.obj,"MaterialAllowance"):
self.obj.MaterialAllowance = self.form.extraOffset.value()
if hasattr(self.obj,"UseStartPoint"):
self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
if hasattr(self.obj,"Algorithm"):
self.obj.Algorithm = str(self.form.algorithmSelect.currentText())
if hasattr(self.obj,"CutMode"):
self.obj.CutMode = str(self.form.cutMode.currentText())
self.obj.Proxy.execute(self.obj)
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 not len(selection) >= 1:
FreeCAD.Console.PrintError(translate("PathProject","Please select at least one profileable object\n"))
return
for s in selection:
if s.HasSubObjects:
for i in s.SubElementNames:
self.obj.Proxy.addpocketbase(self.obj, s.Object, i)
else:
self.obj.Proxy.addpocketbase(self.obj, s.Object)
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()
newlist = []
for d in dlist:
for i in self.obj.Base:
if i[0].Name != d.text().partition(".")[0] or i[1] != d.text().partition(".")[2] :
newlist.append (i)
self.form.baseList.takeItem(self.form.baseList.row(d))
self.obj.Base = newlist
self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def itemActivated(self):
FreeCADGui.Selection.clearSelection()
slist = self.form.baseList.selectedItems()
for i in slist:
objstring = i.text().partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
# sub = o.Shape.getElement(objstring[2])
if objstring[2] != "":
FreeCADGui.Selection.addSelection(obj,objstring[2])
else:
FreeCADGui.Selection.addSelection(obj)
FreeCADGui.updateGui()
def reorderBase(self):
newlist = []
for i in range(self.form.baseList.count()):
s = self.form.baseList.item(i).text()
objstring = s.partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
item = (obj, str(objstring[2]))
newlist.append(item)
self.obj.Base=newlist
self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok)
def edit(self,item,column):
if not self.updating:
self.resetObject()
def setupUi(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.stepDown.setValue(self.obj.StepDown)
self.form.extraOffset.setValue(self.obj.MaterialAllowance.Value)
self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
index = self.form.algorithmSelect.findText(self.obj.Algorithm, QtCore.Qt.MatchFixedString)
if index >= 0:
self.form.algorithmSelect.setCurrentIndex(index)
for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name + "." + i[1])
#Connect Signals and Slots
#Base Controls
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
self.form.addBase.clicked.connect(self.addBase)
self.form.deleteBase.clicked.connect(self.deleteBase)
self.form.reorderBase.clicked.connect(self.reorderBase)
#Depths
self.form.startDepth.editingFinished.connect(self.getFields)
self.form.finalDepth.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)
#operation
self.form.algorithmSelect.currentIndexChanged.connect(self.getFields)
self.form.cutMode.currentIndexChanged.connect(self.getFields)
self.form.useStartPoint.clicked.connect(self.getFields)
self.form.extraOffset.editingFinished.connect(self.getFields)
class SelObserver:
def __init__(self):
import PathScripts.PathSelection as PST
PST.pocketselect()
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

View File

@ -24,13 +24,14 @@
import FreeCAD,Path
from FreeCAD import Vector
from PathScripts import PathUtils,PathSelection,PathProject
from PathScripts import PathUtils #,PathSelection,PathProject
from PathScripts.PathUtils import depth_params
if FreeCAD.GuiUp:
import FreeCADGui, PathGui
import FreeCADGui
from PySide import QtCore, QtGui
from DraftTools import translate
from pivy import coin
#from pivy import coin
else:
def translate(ctxt,txt):
return txt
@ -50,38 +51,15 @@ except AttributeError:
def translate(context, text, disambig=None):
return QtGui.QApplication.translate(context, text, disambig)
def makeProfile(self, name="Profile"):
'''creates a Profile operation'''
#obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",name)
#obj.Label = translate("Path",name)
obj=self
ObjectProfile(obj)
if FreeCAD.GuiUp:
_ViewProviderProfile(obj.ViewObject)
locations = []
angles = []
lengths = []
heights = []
obj.locs = locations
obj.angles = angles
obj.lengths = lengths
obj.heights = heights
FreeCAD.ActiveDocument.recompute()
return obj
class ObjectProfile:
def __init__(self,obj):
obj.addProperty("App::PropertyLinkSub","Base","Path",translate("Parent Object","The base geometry of this toolpath"))
obj.addProperty("App::PropertyLinkSubList","Base","Path",translate("Parent Object","The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool","Active","Path",translate("Path","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyString","Comment","Path",translate("Path","An optional comment for this profile"))
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("Path", "The library or algorithm used to generate the path"))
obj.Algorithm = ['OCC Native','libarea']
obj.Algorithm = ['OCC Native','libareal']
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("Path","The tool number in use"))
obj.ToolNumber = (0,0,1000,1)
@ -94,12 +72,7 @@ class ObjectProfile:
obj.StepDown = (1,0.01,1000,0.5)
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", translate("Path","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Path","Final Depth of Tool- lowest value in Z"))
#obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", translate("Retract Height","The height desired to retract tool when path is finished"))
#Feed Properties
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Path","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Path","Feed rate for horizontal moves"))
#Start Point Properties
obj.addProperty("App::PropertyVector","StartPoint","Start Point",translate("Path_Profile","The start point of this path"))
obj.addProperty("App::PropertyBool","UseStartPoint","Start Point",translate("Path_Profile","make True, if specifying a Start Point"))
@ -128,6 +101,15 @@ class ObjectProfile:
obj.addProperty("App::PropertyFloatList","angles","Tags", translate("Path_Profile", "List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList","heights","Tags", translate("Path_Profile", "List of angles for the holding tags"))
obj.addProperty("App::PropertyFloatList","lengths","Tags", translate("Path_Profile", "List of angles for the holding tags"))
locations = []
angles = []
lengths = []
heights = []
obj.locs = locations
obj.angles = angles
obj.lengths = lengths
obj.heights = heights
obj.Proxy = self
@ -137,142 +119,176 @@ class ObjectProfile:
def __setstate__(self,state):
return None
def execute(self,obj):
import Part, DraftGeomUtils, math
def addprofilebase(self, obj, ss, sub=""):
baselist = obj.Base
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 _buildPathOCC(self,obj,wire):
import DraftGeomUtils
output = ""
output += '('+ str(obj.Comment)+')\n'
if obj.Direction == 'CCW':
clockwise=False
else:
clockwise=True
FirstEdge= None
PathClosed = DraftGeomUtils.isReallyClosed(wire)
output += PathUtils.MakePath(wire, \
obj.Side, \
self.radius, \
clockwise, \
obj.ClearanceHeight.Value, \
obj.StepDown, \
obj.StartDepth.Value, \
obj.FinalDepth.Value, \
FirstEdge, \
PathClosed, \
obj.SegLen.Value, \
self.vertFeed, \
self.horizFeed)
return output
def _buildPathLibarea(self,obj, edgelist):
import PathScripts.PathKurveUtils as PathKurveUtils
from PathScripts.PathUtils import depth_params
import math, area
output = ""
if obj.StartPoint and obj.UseStartPoint:
startpoint = obj.StartPoint
else:
startpoint = None
if obj.EndPoint and obj.UseEndPoint:
endpoint = obj.EndPoint
else:
endpoint = None
PathKurveUtils.output('mem')
PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed)
output = ""
output += "G0 Z" + str(obj.ClearanceHeight.Value)
curve = PathKurveUtils.makeAreaCurve(edgelist,obj.Direction,startpoint, endpoint)
'''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle
print "x = " + str(point.x)
print "y - " + str(point.y)
holding tags
start location
CRC
or probably other features in heekscnc'''
#output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)
'''The following calls the original procedure from heekscnc profile function. This, in turn, calls many other procedures to modify the profile.
This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be
thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16'''
roll_radius = 2.0
extend_at_start = 0.0
extend_at_end = 0.0
lead_in_line_len=0.0
lead_out_line_len= 0.0
'''
Right here, I need to know the Holding Tags group from the tree that refers to this profile operation and build up the tags for PathKurve Utils.
I need to access the location vector, length, angle in radians and height.
'''
PathKurveUtils.clear_tags()
for i in range(len(obj.locs)):
tag = obj.locs[i]
h = obj.heights[i]
l = obj.lengths[i]
a = math.radians(obj.angles[i])
PathKurveUtils.add_tag(area.Point(tag.x,tag.y), l, a, h)
depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None)
PathKurveUtils.profile2(curve, \
obj.Side, \
self.radius, \
self.vertFeed, \
self.horizFeed, \
obj.OffsetExtra.Value,\
roll_radius, \
None,\
None, \
depthparams, \
extend_at_start, \
extend_at_end, \
lead_in_line_len,\
lead_out_line_len)
output += PathKurveUtils.retrieve_gcode()
return output
def execute(self,obj):
import Part #math #DraftGeomUtils
output = ""
toolLoad = PathUtils.getLastToolLoad(obj)
if toolLoad == None:
self.vertFeed = 100
self.horizFeed = 100
self.radius = 0.25
obj.ToolNumber= 0
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
if obj.Base:
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
tool = PathUtils.getTool(obj,obj.ToolNumber)
if tool:
radius = tool.Diameter/2
else:
# temporary value,in case we don't have any tools defined already
radius = 0.25
depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None)
clearance = obj.ClearanceHeight.Value
step_down=obj.StepDown
start_depth=obj.StartDepth.Value
final_depth=obj.FinalDepth.Value
rapid_safety_space=obj.SafeHeight.Value
side=obj.Side
offset_extra=obj.OffsetExtra.Value
use_CRC=obj.UseComp
vf=obj.VertFeed.Value
hf=obj.HorizFeed.Value
seglen=obj.SegLen.Value
direction = obj.Direction
for b in obj.Base:
# we only consider the outer wire if this is a Face
shape = getattr(obj.Base[0].Shape,obj.Base[1][0])
if shape.ShapeType in ["Edge"]:
edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]]
wire = Part.Wire(edges)
if not wire.Edges[0].isSame(shape):
wire.Edges.reverse()
#shape = getattr(obj.Base[0][0].Shape,obj.Base[0][1])
shape = getattr(b[0].Shape,b[1])
else:
wire = shape.OuterWire
edgelist = wire.Edges
#edgelist = Part.__sortEdges__(wire.Edges)
if obj.StartPoint and obj.UseStartPoint:
startpoint = obj.StartPoint
else:
startpoint = None
if obj.EndPoint and obj.UseEndPoint:
endpoint = obj.EndPoint
else:
endpoint = None
if shape.ShapeType in ["Edge"]:
edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]]
wire = Part.Wire(edges)
edgelist = Part.__sortEdges__(edgelist)
if obj.Algorithm == "OCC Native":
output = ""
output += '('+ str(obj.Comment)+')\n'
if not wire.Edges[0].isSame(shape):
wire.Edges.reverse()
if obj.Direction == 'CCW':
clockwise=False
else:
clockwise=True
wire = shape.OuterWire
FirstEdge= None
PathClosed = DraftGeomUtils.isReallyClosed(wire)
edgelist = wire.Edges
edgelist = Part.__sortEdges__(edgelist)
if obj.Algorithm == "OCC Native":
output += self._buildPathOCC(obj, wire)
else:
try:
import area
except:
FreeCAD.Console.PrintError(translate("Path","libarea needs to be installed for this command to work.\n"))
return
output += self._buildPathLibarea(obj,edgelist)
output += PathUtils.MakePath(wire, side, radius, clockwise, clearance, step_down, start_depth, final_depth, FirstEdge, PathClosed, seglen, vf, hf)
else:
try:
import area
except:
FreeCAD.Console.PrintError(translate("Path","libarea needs to be installed for this command to work.\n"))
return
PathKurveUtils.output('mem')
PathKurveUtils.feedrate_hv(obj.HorizFeed.Value, obj.VertFeed.Value)
output = ""
output += "G0 Z" + str(clearance)
curve = PathKurveUtils.makeAreaCurve(edgelist,direction,startpoint, endpoint)
'''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle
print "x = " + str(point.x)
print "y - " + str(point.y)
holding tags
start location
CRC
or probably other features in heekscnc'''
#output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)
'''The following calls the original procedure from heekscnc profile function. This, in turn, calls many other procedures to modify the profile.
This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be
thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16'''
roll_radius = 2.0
extend_at_start = 0.0
extend_at_end = 0.0
lead_in_line_len=0.0
lead_out_line_len= 0.0
'''
Right here, I need to know the Holding Tags group from the tree that refers to this profile operation and build up the tags for PathKurve Utils.
I need to access the location vector, length, angle in radians and height.
'''
PathKurveUtils.clear_tags()
for i in range(len(obj.locs)):
tag = obj.locs[i]
h = obj.heights[i]
l = obj.lengths[i]
a = math.radians(obj.angles[i])
PathKurveUtils.add_tag(area.Point(tag.x,tag.y), l, a, h)
PathKurveUtils.profile2(curve, side, radius, vf, hf, offset_extra, roll_radius, None,None, depthparams, extend_at_start, extend_at_end, lead_in_line_len,lead_out_line_len)
output += PathKurveUtils.retrieve_gcode()
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
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 _ViewProviderProfile:
@ -285,10 +301,10 @@ class _ViewProviderProfile:
def setEdit(self,vobj,mode=0):
FreeCADGui.Control.closeDialog()
taskd = _EditPanel()
taskd = TaskPanel()
taskd.obj = vobj.Object
taskd.update()
FreeCADGui.Control.showDialog(taskd)
taskd.setupUi()
return True
def getIcon(self):
@ -332,8 +348,6 @@ class _CommandAddTag:
obj.lengths = l
obj.angles = a
def Activated(self):
FreeCADGui.Snapper.getPoint(callback=self.setpoint)
@ -384,60 +398,26 @@ class CommandPathProfile:
return not FreeCAD.ActiveDocument is None
def Activated(self):
import Path
from PathScripts import PathProject, PathUtils, PathKurveUtils
#import Path
#from PathScripts import PathProject, PathUtils, PathKurveUtils
# check that the selection contains exactly what we want
selection = FreeCADGui.Selection.getSelectionEx()
if len(selection) != 1:
FreeCAD.Console.PrintError(translate("Path","Select one or more edges or a face from one Document object.\n"))
return
if len(selection[0].SubObjects) == 0:
FreeCAD.Console.PrintError(translate("Path","Select one or more edges or a face from one Document object.\n"))
return
for s in selection[0].SubObjects:
if s.ShapeType != "Edge":
if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1):
FreeCAD.Console.PrintError(translate("Path","Please select only edges or a single face\n"))
return
if selection[0].SubObjects[0].ShapeType == "Edge":
try:
import Part
w = Part.Wire(selection[0].SubObjects)
except:
FreeCAD.Console.PrintError(translate("Path","The selected edges don't form a loop\n"))
return
ztop = 10.0
zbottom = 0.0
# if everything is ok, execute and register the transaction in the undo/redo stack
# Take a guess at some reasonable values for Finish depth.
bb = selection[0].Object.Shape.BoundBox #parent boundbox
fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
if fbb.ZMax < bb.ZMax:
zbottom = fbb.ZMax
else:
zbottom = bb.ZMin
FreeCAD.ActiveDocument.openTransaction(translate("Path","Create a Profile operation using libarea"))
FreeCAD.ActiveDocument.openTransaction(translate("Path","Create a Profile"))
FreeCADGui.addModule("PathScripts.PathProfile")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Profile")')
FreeCADGui.doCommand('PathScripts.PathProfile.makeProfile(obj)')
#FreeCADGui.doCommand('PathScripts.PathProfile.ObjectProfile(obj)')
FreeCADGui.doCommand('PathScripts.PathProfile.ObjectProfile(obj)')
FreeCADGui.doCommand('PathScripts.PathProfile._ViewProviderProfile(obj.ViewObject)')
FreeCADGui.doCommand('obj.Active = True')
subs ="["
for s in selection[0].SubElementNames:
subs += '"' + s + '",'
subs += "]"
FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' + selection[0].ObjectName + ',' + subs + ')')
#FreeCADGui.doCommand('obj.ViewObject.Proxy = 0')
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(bb.ZMax + 10.0))
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(ztop + 10.0))
FreeCADGui.doCommand('obj.StepDown = 1.0')
FreeCADGui.doCommand('obj.StartDepth= ' + str(bb.ZMax))
FreeCADGui.doCommand('obj.StartDepth= ' + str(ztop))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
FreeCADGui.doCommand('obj.SafeHeight = '+ str(bb.ZMax + 2.0))
FreeCADGui.doCommand('obj.SafeHeight = '+ str(ztop + 2.0))
FreeCADGui.doCommand('obj.Side = "Left"')
FreeCADGui.doCommand('obj.OffsetExtra = 0.0')
FreeCADGui.doCommand('obj.Direction = "CW"')
@ -446,100 +426,126 @@ class CommandPathProfile:
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
class _EditPanel:
'''The editmode TaskPanel for profile tags'''
class TaskPanel:
def __init__(self):
# the panel has a tree widget that contains categories
# for the subcomponents, such as additions, subtractions.
# the categories are shown only if they are not empty.
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/ProfileEdit.ui")
#self.form = FreeCADGui.PySideUic.loadUi(":/ProfileEdit.ui")
self.updating = False
self.obj = None
self.form = QtGui.QWidget()
self.form.setObjectName("TaskPanel")
self.grid = QtGui.QGridLayout(self.form)
self.grid.setObjectName("grid")
self.title = QtGui.QLabel(self.form)
self.grid.addWidget(self.title, 0, 0, 1, 2)
# tree
self.tree = QtGui.QTreeWidget(self.form)
self.grid.addWidget(self.tree, 1, 0, 1, 2)
self.tree.setColumnCount(4)
self.tree.header().resizeSection(0,50)
self.tree.header().resizeSection(1,80)
self.tree.header().resizeSection(2,60)
self.tree.header().resizeSection(3,60)
def accept(self):
self.getFields()
# buttons
self.addButton = QtGui.QPushButton(self.form)
self.addButton.setObjectName("addButton")
self.addButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg"))
self.grid.addWidget(self.addButton, 3, 0, 1, 1)
self.addButton.setEnabled(True)
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.removeObserver(self.s)
self.delButton = QtGui.QPushButton(self.form)
self.delButton.setObjectName("delButton")
self.delButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg"))
self.grid.addWidget(self.delButton, 3, 1, 1, 1)
self.delButton.setEnabled(True)
def reject(self):
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.removeObserver(self.s)
QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement)
QtCore.QObject.connect(self.delButton, QtCore.SIGNAL("clicked()"), self.removeElement)
QtCore.QObject.connect(self.tree, QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"), self.edit)
self.update()
self.retranslateUi(self.form)
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,"SafeHeight"):
self.obj.SafeHeight = self.form.safeHeight.text()
if hasattr(self.obj,"ClearanceHeight"):
self.obj.ClearanceHeight = self.form.clearanceHeight.text()
if hasattr(self.obj,"StepDown"):
self.obj.StepDown = self.form.stepDown.value()
if hasattr(self.obj,"OffsetExtra"):
self.obj.OffsetExtra = self.form.extraOffset.value()
if hasattr(self.obj,"SegLen"):
self.obj.SegLen = self.form.segLen.value()
if hasattr(self.obj,"RollRadius"):
self.obj.RollRadius = self.form.rollRadius.value()
if hasattr(self.obj,"UseComp"):
self.obj.UseComp = self.form.useCompensation.isChecked()
if hasattr(self.obj,"UseStartPoint"):
self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
if hasattr(self.obj,"UseEndPoint"):
self.obj.UseEndPoint = self.form.useEndPoint.isChecked()
if hasattr(self.obj,"Algorithm"):
self.obj.Algorithm = str(self.form.algorithmSelect.currentText())
if hasattr(self.obj,"Side"):
self.obj.Side = str(self.form.cutSide.currentText())
if hasattr(self.obj,"Direction"):
self.obj.Direction = str(self.form.direction.currentText())
self.obj.Proxy.execute(self.obj)
def isAllowedAlterSelection(self):
return False
def open(self):
self.s =SelObserver()
# install the function mode resident
FreeCADGui.Selection.addObserver(self.s)
def isAllowedAlterView(self):
return True
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 profileable object\n"))
return
for s in selection:
if s.HasSubObjects:
for i in s.SubElementNames:
self.obj.Proxy.addprofilebase(self.obj, s.Object, i)
else:
self.obj.Proxy.addprofilebase(self.obj, s.Object)
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()
newlist = []
for d in dlist:
for i in self.obj.Base:
if i[0].Name != d.text().partition(".")[0] or i[1] != d.text().partition(".")[2] :
newlist.append (i)
self.form.baseList.takeItem(self.form.baseList.row(d))
self.obj.Base = newlist
self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def itemActivated(self):
FreeCADGui.Selection.clearSelection()
slist = self.form.baseList.selectedItems()
for i in slist:
objstring = i.text().partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
# sub = o.Shape.getElement(objstring[2])
if objstring[2] != "":
FreeCADGui.Selection.addSelection(obj,objstring[2])
else:
FreeCADGui.Selection.addSelection(obj)
FreeCADGui.updateGui()
def reorderBase(self):
newlist = []
for i in range(self.form.baseList.count()):
s = self.form.baseList.item(i).text()
objstring = s.partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
item = (obj, str(objstring[2]))
newlist.append(item)
self.obj.Base=newlist
self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Close)
return int(QtGui.QDialogButtonBox.Ok)
def update(self):
'fills the treewidget'
self.updating = True
self.tree.clear()
if self.obj:
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.tree)
item.setText(0,str(i+1))
l = self.obj.locs[i]
item.setText(1,str(l.x)+", " + str(l.y) +", " + str(l.z))
item.setText(2,str(self.obj.heights[i]))
item.setText(3,str(self.obj.lengths[i]))
item.setText(4,str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0,QtCore.Qt.AlignLeft)
self.retranslateUi(self.form)
self.updating = False
return
def addElement(self):
self.updating = True
item = QtGui.QTreeWidgetItem(self.tree)
item.setText(0,str(self.tree.topLevelItemCount()))
item.setText(1,"0.0, 0.0, 0.0")
item.setText(2, str(float(4.0)))
item.setText(3, str(float(10.0)))
item.setText(4, str(float(45.0)))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
self.updating = False
self.resetObject()
def removeElement(self):
it = self.tree.currentItem()
if it:
nr = int(it.text(0))-1
self.resetObject(remove=nr)
self.update()
def edit(self,item,column):
if not self.updating:
@ -552,8 +558,8 @@ class _EditPanel:
l = []
a = []
for i in range(self.tree.topLevelItemCount()):
it = self.tree.findItems(str(i+1),QtCore.Qt.MatchExactly,0)[0]
for i in range(self.form.tagTree.topLevelItemCount()):
it = self.form.tagTree.findItems(str(i+1),QtCore.Qt.MatchExactly,0)[0]
if (remove == None) or (remove != i):
if it.text(1):
x = float(it.text(1).split()[0].rstrip(","))
@ -584,21 +590,130 @@ class _EditPanel:
self.obj.touch()
FreeCAD.ActiveDocument.recompute()
def reject(self):
FreeCAD.ActiveDocument.recompute()
FreeCADGui.ActiveDocument.resetEdit()
return True
def addElement(self):
self.updating = True
def retranslateUi(self, TaskPanel=None):
TaskPanel.setWindowTitle(QtGui.QApplication.translate("Path", "Holding Tags", None, QtGui.QApplication.UnicodeUTF8))
self.delButton.setText(QtGui.QApplication.translate("Path", "Remove", None, QtGui.QApplication.UnicodeUTF8))
self.addButton.setText(QtGui.QApplication.translate("Path", "Add", None, QtGui.QApplication.UnicodeUTF8))
self.title.setText(QtGui.QApplication.translate("Path", "Tag Locations and Properties", None, QtGui.QApplication.UnicodeUTF8))
self.tree.setHeaderLabels([QtGui.QApplication.translate("Path", "", None, QtGui.QApplication.UnicodeUTF8),
QtGui.QApplication.translate("Path", "Location", None, QtGui.QApplication.UnicodeUTF8),
QtGui.QApplication.translate("Path", "Height", None, QtGui.QApplication.UnicodeUTF8),
QtGui.QApplication.translate("Path", "Length", None, QtGui.QApplication.UnicodeUTF8),
QtGui.QApplication.translate("Path", "Angle", None, QtGui.QApplication.UnicodeUTF8)])
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0,str(self.form.tagTree.topLevelItemCount()))
item.setText(1,"0.0, 0.0, 0.0")
item.setText(2, str(float(4.0)))
item.setText(3, str(float(10.0)))
item.setText(4, str(float(45.0)))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
self.updating = False
self.resetObject()
def removeElement(self):
it = self.form.tagTree.currentItem()
if it:
nr = int(it.text(0))-1
self.resetObject(remove=nr)
self.update()
def update(self):
'fills the treewidget'
self.updating = True
self.form.tagTree.clear()
if self.obj:
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0,str(i+1))
l = self.obj.locs[i]
item.setText(1,str(l.x)+", " + str(l.y) +", " + str(l.z))
item.setText(2,str(self.obj.heights[i]))
item.setText(3,str(self.obj.lengths[i]))
item.setText(4,str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0,QtCore.Qt.AlignLeft)
self.updating = False
return
def setupUi(self):
self.form.startDepth.setText(str(self.obj.StartDepth.Value))
self.form.finalDepth.setText(str(self.obj.FinalDepth.Value))
self.form.safeHeight.setText(str(self.obj.SafeHeight.Value))
self.form.clearanceHeight.setText(str(self.obj.ClearanceHeight.Value))
self.form.stepDown.setValue(self.obj.StepDown)
self.form.extraOffset.setValue(self.obj.OffsetExtra.Value)
self.form.segLen.setValue(self.obj.SegLen.Value)
self.form.rollRadius.setValue(self.obj.RollRadius.Value)
self.form.useCompensation.setChecked(self.obj.UseComp)
self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
self.form.useEndPoint.setChecked(self.obj.UseEndPoint)
index = self.form.algorithmSelect.findText(self.obj.Algorithm, QtCore.Qt.MatchFixedString)
if index >= 0:
self.form.algorithmSelect.setCurrentIndex(index)
index = self.form.cutSide.findText(self.obj.Side, QtCore.Qt.MatchFixedString)
if index >= 0:
self.form.cutSide.setCurrentIndex(index)
index = self.form.direction.findText(self.obj.Direction, QtCore.Qt.MatchFixedString)
if index >= 0:
self.form.direction.setCurrentIndex(index)
for i in self.obj.Base:
self.form.baseList.addItem(i[0].Name + "." + i[1])
for i in range(len(self.obj.locs)):
item = QtGui.QTreeWidgetItem(self.form.tagTree)
item.setText(0,str(i+1))
l = self.obj.locs[i]
item.setText(1,str(l.x)+", " + str(l.y) +", " + str(l.z))
item.setText(2,str(self.obj.heights[i]))
item.setText(3,str(self.obj.lengths[i]))
item.setText(4,str(self.obj.angles[i]))
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setTextAlignment(0,QtCore.Qt.AlignLeft)
#Connect Signals and Slots
#Base Controls
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
self.form.addBase.clicked.connect(self.addBase)
self.form.deleteBase.clicked.connect(self.deleteBase)
self.form.reorderBase.clicked.connect(self.reorderBase)
#Depths
self.form.startDepth.editingFinished.connect(self.getFields)
self.form.finalDepth.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)
#operation
self.form.algorithmSelect.currentIndexChanged.connect(self.getFields)
self.form.cutSide.currentIndexChanged.connect(self.getFields)
self.form.direction.currentIndexChanged.connect(self.getFields)
self.form.useCompensation.clicked.connect(self.getFields)
self.form.useStartPoint.clicked.connect(self.getFields)
self.form.useEndPoint.clicked.connect(self.getFields)
self.form.extraOffset.editingFinished.connect(self.getFields)
self.form.segLen.editingFinished.connect(self.getFields)
self.form.rollRadius.editingFinished.connect(self.getFields)
#Tag Form
QtCore.QObject.connect(self.form.tagTree, QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"), self.edit)
self.form.addTag.clicked.connect(self.addElement)
self.form.deleteTag.clicked.connect(self.removeElement)
class SelObserver:
def __init__(self):
import PathScripts.PathSelection as PST
PST.profileselect()
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:

View File

@ -141,6 +141,11 @@ class CommandProject:
def Create(pathChildren = []):
"""Code to create a project"""
#FreeCADGui.addModule("PathScripts.PathProject")
import PathScripts.PathUtils as PU
if not PU.findProj() == None:
FreeCAD.Console.PrintError("A Path project already exists in this document\n")
return
obj = FreeCAD.ActiveDocument.addObject("Path::FeatureCompoundPython","Project")
ObjectPathProject(obj)
if pathChildren:
@ -152,8 +157,7 @@ class CommandProject:
#create a machine obj
import PathScripts
PathScripts.PathMachine.CommandPathMachine.Create()
PLT = PathScripts.PathLoadTool.CommandPathLoadTool()
PLT.Activated()
PathScripts.PathLoadTool.CommandPathLoadTool.Create()
return obj

View File

@ -71,6 +71,99 @@ class ENGRAVEGate:
def allow(self,doc,obj,sub):
return (obj.Name[0:11] == 'ShapeString')
class DRILLGate:
def allow(self,doc,obj,sub):
import Part
drillable = False
try:
obj = obj.Shape
except:
return False
if obj.ShapeType == 'Vertex':
drillable = True
elif obj.ShapeType == 'Edge':
if isinstance(obj.Curve, Part.Circle):
drillable = True
elif obj.ShapeType == 'Face':
if isinstance(obj.Edges[0].Curve, Part.Circle):
drillable = True
elif obj.ShapeType == 'Wire':
if isinstance(obj.Edges[0].Curve, Part.Circle):
drillable = True
elif obj.ShapeType == 'Solid':
if sub[0:4] == 'Face':
o = obj.getElement(sub)
drillable = isinstance(o.Edges[0].Curve, Part.Circle)
if sub[0:4] == 'Edge':
o = obj.getElement(sub)
drillable = isinstance(o.Curve, Part.Circle)
return drillable
class PROFILEGate:
def allow(self,doc,obj,sub):
import Part
profileable = False
try:
obj = obj.Shape
except:
return False
if obj.ShapeType == 'Edge':
profileable = True
elif obj.ShapeType == 'Face':
profileable = True
elif obj.ShapeType == 'Solid':
if sub[0:4] == 'Face':
profileable = True
if sub[0:4] == 'Edge':
profileable = True
elif obj.ShapeType == 'Wire':
profileable = True
if sub[0:6] == 'Vertex':
print "might be fun to try to derive the loop by hovering near a vertex"
return profileable
class POCKETGate:
def allow(self,doc,obj,sub):
import Part
pocketable = False
try:
obj = obj.Shape
except:
return False
if obj.ShapeType == 'Edge':
pocketable = False
elif obj.ShapeType == 'Face':
pocketable = True
elif obj.ShapeType == 'Solid':
if sub[0:4] == 'Face':
pocketable = True
# if sub[0:4] == 'Edge':
# pocketable = True
# elif obj.ShapeType == 'Wire':
# pocketable = True
# if sub[0:6] == 'Vertex':
# print "might be fun to try to derive the loop by hovering near a vertex"
return pocketable
def fselect():
FreeCADGui.Selection.addSelectionGate(FGate())
@ -84,10 +177,22 @@ def eselect():
FreeCADGui.Selection.addSelectionGate(EGate())
FreeCAD.Console.PrintWarning("Edge Select Mode\n")
def drillselect():
FreeCADGui.Selection.addSelectionGate(DRILLGate())
FreeCAD.Console.PrintWarning("Drilling Select Mode\n")
def engraveselect():
FreeCADGui.Selection.addSelectionGate(ENGRAVEGate())
FreeCAD.Console.PrintWarning("ShapeString Select Mode\n")
FreeCAD.Console.PrintWarning("Engrave Select Mode\n")
def profileselect():
FreeCADGui.Selection.addSelectionGate(PROFILEGate())
FreeCAD.Console.PrintWarning("Profile Select Mode\n")
def pocketselect():
FreeCADGui.Selection.addSelectionGate(POCKETGate())
FreeCAD.Console.PrintWarning("Pocket Select Mode\n")
def clear():
FreeCADGui.Selection.removeSelectionGate()

View File

@ -2,7 +2,7 @@
#***************************************************************************
#* *
#* Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
#* 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) *
@ -22,15 +22,24 @@
#* *
#***************************************************************************
import FreeCAD,FreeCADGui,Path,PathGui
import FreeCAD,Path
from FreeCAD import Vector
from PySide import QtCore,QtGui
from PathScripts import PathUtils,PathSelection,PathProject
"""Path Surface object and FreeCAD command"""
'''Surface operation is used for 3D sculpting, roughing, and finishing
Possible algorithms include waterline, zigzag, and adaptive roughing.
Libraries to consider: opencamlib and libactp'''
if FreeCAD.GuiUp:
import FreeCADGui, PathGui
from PySide import QtCore, QtGui
from DraftTools import translate
from pivy import coin
else:
def translate(ctxt,txt):
return txt
__title__="Path Surface Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
"""Path surface object and FreeCAD command"""
# Qt tanslation handling
try:
@ -42,46 +51,38 @@ except AttributeError:
return QtGui.QApplication.translate(context, text, disambig)
class ObjectProfile:
class ObjectSurface:
def __init__(self,obj):
obj.addProperty("App::PropertyLinkSub","Base","Path",translate("Parent Object","The base geometry of this toolpath"))
obj.addProperty("App::PropertyLinkSub","Base","Path",translate("Parent Object(s)","The base geometry of this toolpath"))
obj.addProperty("App::PropertyBool","Active","Path",translate("Active","Make False, to prevent operation from generating code"))
obj.addProperty("App::PropertyString","Comment","Path",translate("Comment","An optional comment for this profile"))
obj.addProperty("App::PropertyString","Comment","Path",translate("PathProject","An optional comment for this profile"))
obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("PathProject", "The library to use to generate the path"))
obj.Algorithm = ['OCL Waterline']
obj.Algorithm = ['OCL Dropcutter', 'OCL Waterline']
#Tool Properties
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("PathProfile","The tool number in use"))
obj.ToolNumber = (0,0,1000,1)
obj.ToolNumber = (0, 0, 1000, 0)
obj.setEditorMode('ToolNumber',1) #make this read only
#Surface Properties
obj.addProperty("App::PropertyFloatConstraint", "SampleInterval", "Surface", translate("PathSurface","The Sample Interval. Small values cause long wait"))
obj.SampleInterval = (0,0,1,0)
#Depth Properties
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", translate("Clearance Height","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", translate("StepDown","Incremental Step Down of Tool"))
obj.StepDown = (1,0.01,1000,0.5)
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", translate("Start Depth","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", translate("Final Depth","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyFloat", "ClearanceHeight", "Depth", translate("PathProject","The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyFloat", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations."))
obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", translate("PathProject","Incremental Step Down of Tool"))
obj.StepDown = (0.0, 0.01, 100.0, 0.5)
obj.addProperty("App::PropertyFloat", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyFloat", "FinalDepth", "Depth", translate("PathProject","Final Depth of Tool- lowest value in Z"))
obj.addProperty("App::PropertyFloat", "FinishDepth", "Depth", translate("PathProject","Maximum material removed on final pass."))
#Feed Properties
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Horiz Feed","Feed rate for horizontal moves"))
#Start Point Properties
obj.addProperty("App::PropertyVector","StartPoint","Start Point",translate("Start Point","The start point of this path"))
obj.addProperty("App::PropertyBool","UseStartPoint","Start Point",translate("Use Start Point","make True, if specifying a Start Point"))
obj.addProperty("App::PropertyLength", "ExtendAtStart", "Start Point", translate("extend at start", "extra length of tool path before start of part edge"))
obj.addProperty("App::PropertyLength", "LeadInLineLen", "Start Point", translate("lead in length","length of straight segment of toolpath that comes in at angle to first part edge"))
#End Point Properties
obj.addProperty("App::PropertyBool","UseEndPoint","End Point",translate("Use End Point","make True, if specifying an End Point"))
obj.addProperty("App::PropertyLength", "ExtendAtEnd", "End Point", translate("extend at end","extra length of tool path after end of part edge"))
obj.addProperty("App::PropertyLength", "LeadOutLineLen", "End Point", translate("lead_out_line_len","length of straight segment of toolpath that comes in at angle to last part edge"))
obj.addProperty("App::PropertyVector","EndPoint","End Point",translate("End Point","The end point of this path"))
#Surface Properties
obj.addProperty("App::PropertySpeed", "VertFeed", "Feed",translate("Path","Feed rate for vertical moves in Z"))
obj.addProperty("App::PropertySpeed", "HorizFeed", "Feed",translate("Path","Feed rate for horizontal moves"))
obj.Proxy = self
def __getstate__(self):
@ -90,140 +91,316 @@ class ObjectProfile:
def __setstate__(self,state):
return None
def execute(self,obj):
import Part, DraftGeomUtils
from PathScripts.PathUtils import depth_params
def _waterline(self,obj, s, bb):
import ocl
# from PathScripts.PathUtils import fmt
from PathScripts.PathUtils import depth_params, fmt
import time
if obj.Base:
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
tool = PathUtils.getTool(obj,obj.ToolNumber)
if tool:
radius = tool.Diameter/2
else:
# temporary value,in case we don't have any tools defined already
radius = 0.25
depthparams = depth_params (obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None)
clearance = obj.ClearanceHeight.Value
step_down=obj.StepDown
start_depth=obj.StartDepth.Value
final_depth=obj.FinalDepth.Value
rapid_safety_space=obj.SafeHeight.Value
def drawLoops(loops):
nloop = 0
waterlinestring = ""
waterlinestring += "(waterline begin)"
for loop in loops:
p = loop[0]
loopstring = "(loop begin)" +"\n"
loopstring += "G0 Z" + str(obj.SafeHeight) +"\n"
loopstring += "G0 X" + str(fmt(p.x)) + " Y" + str(fmt(p.y)) +"\n"
loopstring += "G1 Z" + str(fmt(p.z)) +"\n"
for p in loop[1:]:
loopstring += "G1 X" + str(fmt(p.x)) + " Y" + str(fmt(p.y)) + " Z" + str(fmt(p.z)) +"\n"
zheight = p.z
p = loop[0]
loopstring += "G1 X" + str(fmt(p.x)) + " Y" + str(fmt(p.y)) + " Z" + str(fmt(zheight)) +"\n"
loopstring += "(loop end)" +"\n"
print " loop ",nloop, " with ", len(loop), " points"
nloop = nloop+1
waterlinestring += loopstring
waterlinestring += "(waterline end)" +"\n"
return waterlinestring
vf=obj.VertFeed.Value
hf=obj.HorizFeed.Value
'''Parse the base and get the necessary geometry here'''
# nloop = 0
# for lop in loops:
# n = 0
# N = len(lop)
# first_point=ocl.Point(-1,-1,5)
# previous=ocl.Point(-1,-1,5)
# for p in lop:
# if n==0: # don't draw anything on the first iteration
# previous=p
# first_point = p
# elif n== (N-1): # the last point
# # and a line from p to the first point
# p1=(p.x,p.y,p.z)
# p2=(first_point.x,first_point.y,first_point.z)
# output += "G1 X" + str(p2[0]) + " Y" + str (p2[1]) + " Z" +str(p2[2]) +"\n"
# else:
# p1=(previous.x,previous.y,previous.z)
# p2=(p.x,p.y,p.z)
# output += "G1 X" + str(p2[0]) + " Y" + str (p2[1]) + " Z" +str(p2[2]) +"\n"
# #print "line from: " + str (p1) + "To: " + str (p2)
# #print "line X: " + str (p1.x) +" Y: " + str(p1.y) + "Z: " + str(p1.z) + " To X: " + str (p2.x) +" Y: " + str(p2.y) + "Z: " + str(p2.z)
# previous=p
# n=n+1
# print " loop ",nloop, " with ", len(lop), " points"
# nloop = nloop+1
# return output
depthparams = depth_params (obj.ClearanceHeight, obj.SafeHeight, obj.StartDepth, obj.StepDown, obj.FinishDepth, obj.FinalDepth)
if obj.Algorithm == "OCL Waterline":
try:
import ocl
except:
FreeCAD.Console.PrintError(translate("Path","OpenCAMLib needs to be installed for this command to work.\n"))
return
# stlfile = "../../stl/gnu_tux_mod.stl"
# surface = STLSurfaceSource(stlfile)
surface = s
output = ""
output += '('+ str(obj.Comment)+')\n'
output += self.buildoclwaterline()
else:
return
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
def buildoclwaterline(self):
output = "Some text"
t_before = time.time()
zheights= depthparams.get_depths()
wl = ocl.Waterline()
#wl = ocl.AdaptiveWaterline() # this is slower, ca 60 seconds on i7 CPU
wl.setSTL(surface)
diam = 0.5
length= 10
cutter = ocl.BallCutter( diam , length ) # any ocl MillingCutter class should work here
wl.setCutter(cutter)
wl.setSampling(obj.SampleInterval) # this should be smaller than the smallest details in the STL file
# AdaptiveWaterline() also has settings for minimum sampling interval (see c++ code)
all_loops=[]
for zh in zheights:
print "calculating Waterline at z= ", zh
wl.reset()
wl.setZ(zh) # height for this waterline
wl.run()
all_loops.append( wl.getLoops() )
t_after = time.time()
calctime = t_after-t_before
n=0
output = ""
for loops in all_loops: # at each z-height, we may get many loops
print " %d/%d:" % (n,len(all_loops))
output += drawLoops(loops)
n=n+1
print "(" + str(calctime) + ")"
return output
class ViewProviderProfile:
def _dropcutter(self,obj, s, bb):
import ocl
import time
def __init__(self,vobj):
vobj.Proxy = self
cutter = ocl.CylCutter(self.radius*2, 5)
pdc = ocl.PathDropCutter() # create a pdc
pdc.setSTL(s)
pdc.setCutter(cutter)
pdc.minimumZ = 0.25
pdc.setSampling(obj.SampleInterval)
# some parameters for this "zigzig" pattern
xmin=bb.XMin - cutter.getDiameter()
xmax=bb.XMax + cutter.getDiameter()
ymin=bb.YMin - cutter.getDiameter()
ymax=bb.YMax + cutter.getDiameter()
zmax=bb.ZMax + cutter.getDiameter()
Ny=int(bb.YLength/cutter.getDiameter()) # number of lines in the y-direction
dy = float(ymax-ymin)/Ny # the y step-over
path = ocl.Path() # create an empty path object
# add Line objects to the path in this loop
for n in xrange(0,Ny):
y = ymin+n*dy
p1 = ocl.Point(xmin,y,0) # start-point of line
p2 = ocl.Point(xmax,y,0) # end-point of line
if (n % 2 == 0): #even
l = ocl.Line(p1,p2) # line-object
else: #odd
l = ocl.Line(p2,p1) # line-object
def attach(self,vobj):
self.Object = vobj.Object
return
path.append( l ) # add the line to the path
pdc.setPath( path )
# run drop-cutter on the path
t_before = time.time()
pdc.run()
t_after = time.time()
print "calculation took ", t_after-t_before," s"
def getIcon(self):
return ":/icons/Path-Surface.svg"
#retrieve the points
clp = pdc.getCLPoints()
print "points received: " + str(len(clp))
def __getstate__(self):
#generate the path commands
output = ""
output += "G0 Z" + str(obj.ClearanceHeight) + "\n"
output += "G0 X" + str(clp[0].x) +" Y" + str(clp[0].y) + "\n"
output += "G1 Z" + str(clp[0].z) + " F" + str(obj.VertFeed.Value) + "\n"
for c in clp:
output += "G1 X" + str(c.x) +" Y" + str(c.y) +" Z" + str(c.z)+ "\n"
return output
def execute(self,obj):
import Part
import Mesh
import MeshPart
FreeCAD.Console.PrintWarning(translate("PathSurface","Hold on. This might take a minute.\n"))
output = ""
if obj.Algorithm in ['OCL Dropcutter', 'OCL Waterline']:
try:
import ocl
except:
FreeCAD.Console.PrintError(translate("PathSurface","This operation requires OpenCamLib to be installed.\n"))
return
# tie the toolnumber to the PathLoadTool object ToolNumber
if len(obj.InList)>0: #check to see if obj is in the Project group yet
project = obj.InList[0]
tl = int(PathUtils.changeTool(obj,project))
obj.ToolNumber= tl
tool = PathUtils.getTool(obj,obj.ToolNumber)
if tool:
self.radius = tool.Diameter/2
else:
# temporary value,in case we don't have any tools defined already
self.radius = 0.25
mesh = obj.Base[0]
if mesh.TypeId.startswith('Mesh'):
mesh = mesh.Mesh
bb = mesh.BoundBox
else:
bb = mesh.Shape.BoundBox
mesh = MeshPart.meshFromShape(mesh.Shape,MaxLength=2)
s= ocl.STLSurf()
for f in mesh.Facets:
p = f.Points[0];q=f.Points[1];r=f.Points[2]
t= ocl.Triangle(ocl.Point(p[0],p[1],p[2]),ocl.Point(q[0],q[1],q[2]),ocl.Point(r[0],r[1],r[2]))
s.addTriangle(t)
if obj.Algorithm == 'OCL Dropcutter':
output = self._dropcutter(obj, s, bb)
elif obj.Algorithm == 'OCL Waterline':
output = self._waterline(obj, s, bb)
path = Path.Path(output)
obj.Path = path
class ViewProviderSurface:
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):
def __setstate__(self,state): #mandatory
return None
def getIcon(self): #optional
return ":/icons/Path-Surfacing.svg"
# def attach(self): #optional
# # this is executed on object creation and object load from file
# pass
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): #optional
# this is executed when the object is double-clicked in the tree
pass
def unsetEdit(self,vobj,mode): #optional
# this is executed when the user cancels or terminates edit mode
pass
class CommandPathSurfacing:
class CommandPathProfile:
def GetResources(self):
return {'Pixmap' : 'Path-Surface',
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathSurface","Surface"),
'Accel': "P, P",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathSurface","Creates a Path Surface object from selected solid")}
return {'Pixmap' : 'Path-Surfacing',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Surface","Surfacing"),
'Accel': "P, D",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Surface","Creates a Path Surfacing object")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
import Path
from PathScripts import PathProject, PathUtils
def Activated(self):
# check that the selection contains exactly what we want
selection = FreeCADGui.Selection.getSelectionEx()
if len(selection) != 1:
FreeCAD.Console.PrintError(translate("Path","Select a Solid.\n"))
FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\n"))
return
if len(selection[0].SubObjects) == 0:
FreeCAD.Console.PrintError(translate("Path","Select a Solid.\n"))
if not len(selection[0].SubObjects) == 0:
FreeCAD.Console.PrintError(translate("PathSurface","Please select a single solid object from the project tree\n"))
return
# if everything is ok, execute and register the transaction in the undo/redo stack
for s in selection[0].SubObjects:
if s.ShapeType != "Edge":
if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1):
FreeCAD.Console.PrintError(translate("PathSurface","Please select only edges or a single face\n"))
return
# Take a guess at some reasonable values for Finish depth.
bb = selection[0].Object.Shape.BoundBox #parent boundbox
fbb = selection[0].SubObjects[0].BoundBox #feature boundbox
if fbb.ZMax < bb.ZMax:
zbottom = fbb.ZMax
sel = selection[0].Object
#get type of object
if sel.TypeId.startswith('Mesh'):
#it is a mesh already
print 'was already mesh'
ztop = sel.Mesh.BoundBox.ZMax
zbottom = sel.Mesh.BoundBox.ZMin
#mesh = sel
elif sel.TypeId.startswith('Part') and \
(sel.Shape.BoundBox.XLength > 0) and \
(sel.Shape.BoundBox.YLength > 0) and \
(sel.Shape.BoundBox.ZLength > 0):
ztop = sel.Shape.BoundBox.ZMax
zbottom = sel.Shape.BoundBox.ZMin
print 'this is a solid Part object'
else:
zbottom = bb.ZMin
FreeCAD.Console.PrintError(translate("PathSurface","Cannot work with this object\n"))
return
FreeCAD.ActiveDocument.openTransaction(translate("Path","Create a Surfacing Operation"))
# if everything is ok, execute and register the transaction in the undo/redo stack
FreeCAD.ActiveDocument.openTransaction(translate("Path_Surfacing","Create Surface"))
FreeCADGui.addModule("PathScripts.PathSurface")
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Surface")')
FreeCADGui.doCommand('PathScripts.PathSurface.ObjectProfile(obj)')
FreeCADGui.doCommand('PathScripts.PathSurface.ObjectSurface(obj)')
FreeCADGui.doCommand('obj.Active = True')
# subs ="["
# for s in selection[0].SubElementNames:
# subs += '"' + s + '",'
# subs += "]"
# FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' + selection[0].ObjectName + ',' + subs + ')')
FreeCADGui.doCommand('PathScripts.PathSurface.ViewProviderSurface(obj.ViewObject)')
FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.'+selection[0].ObjectName+',[])')
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.SampleInterval = 0.4')
FreeCADGui.doCommand('obj.ViewObject.Proxy = 0')
FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(bb.ZMax + 10.0))
FreeCADGui.doCommand('obj.StepDown = 1.0')
FreeCADGui.doCommand('obj.StartDepth= ' + str(bb.ZMax))
FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom))
FreeCADGui.doCommand('obj.SafeHeight = '+ str(bb.ZMax + 2.0))
FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)')
FreeCAD.ActiveDocument.commitTransaction()
@ -232,6 +409,6 @@ class CommandPathProfile:
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Surface',CommandPathSurface())
FreeCADGui.addCommand('Path_Surfacing',CommandPathSurfacing())
FreeCAD.Console.PrintLog("Loading PathSurface... done\n")
FreeCAD.Console.PrintLog("Loading PathSurfacing... done\n")

View File

@ -324,7 +324,6 @@ def changeTool(obj,proj):
if g == obj:
return tlnum
def getLastTool(obj):
toolNum = obj.ToolNumber
if obj.ToolNumber == 0:
@ -333,6 +332,44 @@ def getLastTool(obj):
toolNum = changeTool(obj, proj)
return getTool(obj, toolNum)
def getLastToolLoad(obj):
#This walks up the hierarchy and tries to find the closest preceding toolchange.
import PathScripts
tc = None
lastfound = None
try:
child = obj
parent = obj.InList[0]
except:
parent = None
while parent != None:
sibs = parent.Group
for g in sibs:
if isinstance(g.Proxy,PathScripts.PathLoadTool.LoadTool):
lastfound = g
if g == child:
tc = lastfound
if tc == None:
try:
child = parent
parent = parent.InList[0]
except:
parent = None
else:
return tc
if tc == None:
for g in FreeCAD.ActiveDocument.Objects: #top level object
if isinstance(g.Proxy,PathScripts.PathLoadTool.LoadTool):
lastfound = g
if g == obj:
tc = lastfound
return tc
def getTool(obj,number=0):
"retrieves a tool from a hosting object with a tooltable, if any"
@ -419,7 +456,6 @@ class depth_params:
self.user_depths = user_depths
def get_depths(self):
print "in function"
depths = []
if self.user_depths != None:
depths = self.user_depths