diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py index 353af594deb4..00d0e0e2e916 100644 --- a/src/Mod/AddonManager/AddonManager.py +++ b/src/Mod/AddonManager/AddonManager.py @@ -26,14 +26,11 @@ from __future__ import print_function import os -import re import shutil import stat -import sys import tempfile from PySide import QtGui, QtCore -import AddonManager_rc import FreeCADGui from addonmanager_utilities import translate # this needs to be as is for pylupdate diff --git a/src/Mod/AddonManager/InitGui.py b/src/Mod/AddonManager/InitGui.py index 60ee0ce51c9b..993cf5ae1e03 100644 --- a/src/Mod/AddonManager/InitGui.py +++ b/src/Mod/AddonManager/InitGui.py @@ -4,7 +4,6 @@ # License LGPL import AddonManager -import AddonManager_rc FreeCADGui.addLanguagePath(":/translations") FreeCADGui.addCommand('Std_AddonMgr', AddonManager.CommandAddonManager()) diff --git a/src/Mod/AddonManager/addonmanager_workers.py b/src/Mod/AddonManager/addonmanager_workers.py index 453e75b4eb07..562141a9052f 100644 --- a/src/Mod/AddonManager/addonmanager_workers.py +++ b/src/Mod/AddonManager/addonmanager_workers.py @@ -24,9 +24,7 @@ import os import re import shutil -import stat import sys -import tempfile from PySide import QtCore, QtGui diff --git a/src/Mod/Fem/Gui/TaskFemConstraintContact.cpp b/src/Mod/Fem/Gui/TaskFemConstraintContact.cpp index 00b95526a461..2681b21d2e7e 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintContact.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintContact.cpp @@ -404,7 +404,7 @@ TaskDlgFemConstraintContact::TaskDlgFemConstraintContact(ViewProviderFemConstrai { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintContact(ConstraintView);; + this->parameter = new TaskFemConstraintContact(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.cpp b/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.cpp index 19f9c4f623b9..2d215d516845 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintDisplacement.cpp @@ -571,7 +571,7 @@ TaskDlgFemConstraintDisplacement::TaskDlgFemConstraintDisplacement(ViewProviderF { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintDisplacement(ConstraintView);; + this->parameter = new TaskFemConstraintDisplacement(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintFixed.cpp b/src/Mod/Fem/Gui/TaskFemConstraintFixed.cpp index e7b38bb73d89..d35fbd6af008 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintFixed.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintFixed.cpp @@ -252,7 +252,7 @@ TaskDlgFemConstraintFixed::TaskDlgFemConstraintFixed(ViewProviderFemConstraintFi { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintFixed(ConstraintView);; + this->parameter = new TaskFemConstraintFixed(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.cpp b/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.cpp index 3cf01ee589b1..b6f00406b362 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintFluidBoundary.cpp @@ -872,7 +872,7 @@ TaskDlgFemConstraintFluidBoundary::TaskDlgFemConstraintFluidBoundary(ViewProvide { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintFluidBoundary(ConstraintView);; + this->parameter = new TaskFemConstraintFluidBoundary(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp index 67a0530a541c..6fedd3fffe91 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp @@ -394,7 +394,7 @@ TaskDlgFemConstraintForce::TaskDlgFemConstraintForce(ViewProviderFemConstraintFo { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintForce(ConstraintView);; + this->parameter = new TaskFemConstraintForce(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintHeatflux.cpp b/src/Mod/Fem/Gui/TaskFemConstraintHeatflux.cpp index 7a3b44525cd4..90475d3151e7 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintHeatflux.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintHeatflux.cpp @@ -383,7 +383,7 @@ TaskDlgFemConstraintHeatflux::TaskDlgFemConstraintHeatflux(ViewProviderFemConstr { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintHeatflux(ConstraintView);; + this->parameter = new TaskFemConstraintHeatflux(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintInitialTemperature.cpp b/src/Mod/Fem/Gui/TaskFemConstraintInitialTemperature.cpp index 38e83c63b519..e2286adc202c 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintInitialTemperature.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintInitialTemperature.cpp @@ -106,7 +106,7 @@ TaskDlgFemConstraintInitialTemperature::TaskDlgFemConstraintInitialTemperature(V { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintInitialTemperature(ConstraintView);; + this->parameter = new TaskFemConstraintInitialTemperature(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintPlaneRotation.cpp b/src/Mod/Fem/Gui/TaskFemConstraintPlaneRotation.cpp index a24600f395cc..67cc747d21fd 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintPlaneRotation.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintPlaneRotation.cpp @@ -273,7 +273,7 @@ TaskDlgFemConstraintPlaneRotation::TaskDlgFemConstraintPlaneRotation(ViewProvide { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintPlaneRotation(ConstraintView);; + this->parameter = new TaskFemConstraintPlaneRotation(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintPressure.cpp b/src/Mod/Fem/Gui/TaskFemConstraintPressure.cpp index 50ddb206405d..776e04fa5e6c 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintPressure.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintPressure.cpp @@ -269,7 +269,7 @@ TaskDlgFemConstraintPressure::TaskDlgFemConstraintPressure(ViewProviderFemConstr { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintPressure(ConstraintView);; + this->parameter = new TaskFemConstraintPressure(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp b/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp index 2f0604e19131..f7c442c4b339 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintPulley.cpp @@ -182,7 +182,7 @@ TaskDlgFemConstraintPulley::TaskDlgFemConstraintPulley(ViewProviderFemConstraint { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintPulley(ConstraintView);; + this->parameter = new TaskFemConstraintPulley(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintTemperature.cpp b/src/Mod/Fem/Gui/TaskFemConstraintTemperature.cpp index d417c27ae911..a0089f3cf4d6 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintTemperature.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintTemperature.cpp @@ -324,7 +324,7 @@ TaskDlgFemConstraintTemperature::TaskDlgFemConstraintTemperature(ViewProviderFem { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintTemperature(ConstraintView);; + this->parameter = new TaskFemConstraintTemperature(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintTransform.cpp b/src/Mod/Fem/Gui/TaskFemConstraintTransform.cpp index 08dfb7e6bcb0..1339a215f85c 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintTransform.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintTransform.cpp @@ -486,7 +486,7 @@ TaskDlgFemConstraintTransform::TaskDlgFemConstraintTransform(ViewProviderFemCons { this->ConstraintView = ConstraintView; assert(ConstraintView); - this->parameter = new TaskFemConstraintTransform(ConstraintView);; + this->parameter = new TaskFemConstraintTransform(ConstraintView); Content.push_back(parameter); } diff --git a/src/Mod/Fem/femsolver/z88/writer.py b/src/Mod/Fem/femsolver/z88/writer.py index f2612471531a..862913a09664 100644 --- a/src/Mod/Fem/femsolver/z88/writer.py +++ b/src/Mod/Fem/femsolver/z88/writer.py @@ -73,7 +73,7 @@ def write_z88_input(self): self.element_count = len(self.femelement_table) self.set_z88_elparam() self.write_z88_mesh() - self.write_z88_contraints() + self.write_z88_constraints() self.write_z88_face_loads() self.write_z88_materials() self.write_z88_elements_properties() @@ -120,7 +120,7 @@ def write_z88_mesh(self): ) f.close() - def write_z88_contraints(self): + def write_z88_constraints(self): constraints_data = [] # will be a list of tuple for better sorting # fixed constraints @@ -155,8 +155,8 @@ def write_z88_contraints(self): constraints_data.append((n, str(n) + " 3 1 " + str(v3) + "\n")) # write constraints_data to file - contraints_file_path = self.file_name + "i2.txt" - f = open(contraints_file_path, "w") + constraints_file_path = self.file_name + "i2.txt" + f = open(constraints_file_path, "w") f.write(str(len(constraints_data)) + "\n") for c in sorted(constraints_data): f.write(c[1]) diff --git a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp index bcc848aa357d..36451321d5da 100644 --- a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp @@ -436,6 +436,113 @@ void TaskPipeParameters::exitSelectionMode() { Gui::Selection().clearSelection(); } +bool TaskPipeParameters::accept() +{ + //see what to do with external references + //check the prerequisites for the selected objects + //the user has to decide which option we should take if external references are used + PartDesign::Pipe* pcPipe = static_cast(getPipeView()->getObject()); + auto pcActiveBody = PartDesignGui::getBodyFor(pcPipe, false); + if (!pcActiveBody) { + QMessageBox::warning(this, tr("Input error"), tr("No active body")); + return false; + } + //auto pcActivePart = PartDesignGui::getPartFor(pcActiveBody, false); + std::vector copies; + + bool extReference = false; + App::DocumentObject* spine = pcPipe->Spine.getValue(); + App::DocumentObject* auxSpine = pcPipe->AuxillerySpine.getValue(); + + // If a spine isn't set but user entered a label then search for the appropriate document object + QString label = ui->spineBaseEdit->text(); + if (!spine && !label.isEmpty()) { + QByteArray ba = label.toUtf8(); + std::vector objs = pcPipe->getDocument()->findObjects(App::DocumentObject::getClassTypeId(), nullptr, ba.constData()); + if (!objs.empty()) { + pcPipe->Spine.setValue(objs.front()); + spine = objs.front(); + } + } + + if (spine && !pcActiveBody->hasObject(spine) && !pcActiveBody->getOrigin()->hasObject(spine)) { + extReference = true; + } + else if (auxSpine && !pcActiveBody->hasObject(auxSpine) && !pcActiveBody->getOrigin()->hasObject(auxSpine)) { + extReference = true; + } + else { + for(App::DocumentObject* obj : pcPipe->Sections.getValues()) { + if (!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) { + extReference = true; + break; + } + } + } + + if (extReference) { + QDialog dia(Gui::getMainWindow()); + Ui_DlgReference dlg; + dlg.setupUi(&dia); + dia.setModal(true); + int result = dia.exec(); + if (result == QDialog::DialogCode::Rejected) + return false; + + if (!dlg.radioXRef->isChecked()) { + + if (!pcActiveBody->hasObject(spine) && !pcActiveBody->getOrigin()->hasObject(spine)) { + pcPipe->Spine.setValue(PartDesignGui::TaskFeaturePick::makeCopy(spine, "", + dlg.radioIndependent->isChecked()), + pcPipe->Spine.getSubValues()); + copies.push_back(pcPipe->Spine.getValue()); + } + else if (!pcActiveBody->hasObject(auxSpine) && !pcActiveBody->getOrigin()->hasObject(auxSpine)){ + pcPipe->AuxillerySpine.setValue(PartDesignGui::TaskFeaturePick::makeCopy(auxSpine, "", + dlg.radioIndependent->isChecked()), + pcPipe->AuxillerySpine.getSubValues()); + copies.push_back(pcPipe->AuxillerySpine.getValue()); + } + + std::vector objs; + int index = 0; + for(App::DocumentObject* obj : pcPipe->Sections.getValues()) { + + if(!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) { + objs.push_back(PartDesignGui::TaskFeaturePick::makeCopy(obj, "", dlg.radioIndependent->isChecked())); + copies.push_back(objs.back()); + } + else { + objs.push_back(obj); + } + + index++; + } + + pcPipe->Sections.setValues(objs); + } + } + + try { + Gui::cmdAppDocument(pcPipe, "recompute()"); + if (!vp->getObject()->isValid()) + throw Base::RuntimeError(vp->getObject()->getStatusString()); + Gui::cmdGuiDocument(pcPipe, "resetEdit()"); + Gui::Command::commitCommand(); + + //we need to add the copied features to the body after the command action, as otherwise FreeCAD crashes unexplainably + for (auto obj : copies) { + pcActiveBody->addObject(obj); + } + } + catch (const Base::Exception& e) { + QMessageBox::warning(this, tr("Input error"), QString::fromUtf8(e.what())); + return false; + } + + return true; +} + //************************************************************************** //************************************************************************** @@ -1014,89 +1121,7 @@ TaskDlgPipeParameters::~TaskDlgPipeParameters() bool TaskDlgPipeParameters::accept() { - //see what to do with external references - //check the prerequisites for the selected objects - //the user has to decide which option we should take if external references are used - PartDesign::Pipe* pcPipe = static_cast(getPipeView()->getObject()); - auto pcActiveBody = PartDesignGui::getBodyFor(pcPipe, false); - //auto pcActivePart = PartDesignGui::getPartFor(pcActiveBody, false); - std::vector copies; - - bool extReference = false; - if(!pcActiveBody->hasObject(pcPipe->Spine.getValue()) && !pcActiveBody->getOrigin()->hasObject(pcPipe->Spine.getValue())) - extReference = true; - else if(pcPipe->AuxillerySpine.getValue() && !pcActiveBody->hasObject(pcPipe->AuxillerySpine.getValue()) && - !pcActiveBody->getOrigin()->hasObject(pcPipe->AuxillerySpine.getValue())) - extReference = true; - else { - for(App::DocumentObject* obj : pcPipe->Sections.getValues()) { - if(!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) - extReference = true; - } - } - - if (extReference) { - QDialog dia(Gui::getMainWindow()); - Ui_DlgReference dlg; - dlg.setupUi(&dia); - dia.setModal(true); - int result = dia.exec(); - if (result == QDialog::DialogCode::Rejected) - return false; - - if(!dlg.radioXRef->isChecked()) { - - if(!pcActiveBody->hasObject(pcPipe->Spine.getValue()) && !pcActiveBody->getOrigin()->hasObject(pcPipe->Spine.getValue())) { - pcPipe->Spine.setValue(PartDesignGui::TaskFeaturePick::makeCopy(pcPipe->Spine.getValue(), "", dlg.radioIndependent->isChecked()), - pcPipe->Spine.getSubValues()); - copies.push_back(pcPipe->Spine.getValue()); - } - else if(!pcActiveBody->hasObject(pcPipe->AuxillerySpine.getValue()) && !pcActiveBody->getOrigin()->hasObject(pcPipe->AuxillerySpine.getValue())){ - pcPipe->AuxillerySpine.setValue(PartDesignGui::TaskFeaturePick::makeCopy(pcPipe->AuxillerySpine.getValue(), "", dlg.radioIndependent->isChecked()), - pcPipe->AuxillerySpine.getSubValues()); - copies.push_back(pcPipe->AuxillerySpine.getValue()); - } - - std::vector objs; - int index = 0; - for(App::DocumentObject* obj : pcPipe->Sections.getValues()) { - - if(!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) { - objs.push_back(PartDesignGui::TaskFeaturePick::makeCopy(obj, "", dlg.radioIndependent->isChecked())); - copies.push_back(objs.back()); - } - else - objs.push_back(obj); - - index++; - } - - pcPipe->Sections.setValues(objs); - } - } - - try { - Gui::cmdAppDocument(pcPipe, "recompute()"); - if (!vp->getObject()->isValid()) - throw Base::RuntimeError(vp->getObject()->getStatusString()); - Gui::cmdGuiDocument(pcPipe, "resetEdit()"); - Gui::Command::commitCommand(); - - //we need to add the copied features to the body after the command action, as otherwise FreeCAD crashes unexplainably - for(auto obj : copies) { - //Dead code: pcActiveBody was previously used without checking for null, so it won't be null here either. - //if(pcActiveBody) - pcActiveBody->addObject(obj); - //else if (pcActivePart) - // pcActivePart->addObject(obj); - } - } - catch (const Base::Exception& e) { - QMessageBox::warning(parameter, tr("Input error"), QString::fromUtf8(e.what())); - return false; - } - - return true; + return parameter->accept(); } diff --git a/src/Mod/PartDesign/Gui/TaskPipeParameters.h b/src/Mod/PartDesign/Gui/TaskPipeParameters.h index 5d1f95b0ed00..16b4ffeea2b7 100644 --- a/src/Mod/PartDesign/Gui/TaskPipeParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPipeParameters.h @@ -32,10 +32,6 @@ #include "ViewProviderPipe.h" #include "TaskDressUpParameters.h" -class Ui_TaskPipeParameters; -class Ui_TaskPipeOrientation; -class Ui_TaskPipeScaling; - namespace App { class Property; @@ -47,6 +43,9 @@ class ViewProvider; namespace PartDesignGui { +class Ui_TaskPipeParameters; +class Ui_TaskPipeOrientation; +class Ui_TaskPipeScaling; class TaskPipeParameters : public TaskSketchBasedParameters @@ -57,7 +56,8 @@ class TaskPipeParameters : public TaskSketchBasedParameters TaskPipeParameters(ViewProviderPipe *PipeView,bool newObj=false,QWidget *parent = 0); ~TaskPipeParameters(); - + bool accept(); + private Q_SLOTS: void onTangentChanged(bool checked); void onTransitionChanged(int); @@ -80,6 +80,9 @@ private Q_SLOTS: void clearButtons(); void exitSelectionMode(); + ViewProviderPipe* getPipeView() const + { return static_cast(vp); } + bool spineShow = false; private: @@ -135,7 +138,6 @@ class TaskPipeScaling : public TaskSketchBasedParameters TaskPipeScaling(ViewProviderPipe *PipeView,bool newObj=false,QWidget *parent = 0); virtual ~TaskPipeScaling(); - private Q_SLOTS: void onScalingChanged(int); void onButtonRefAdd(bool checked); @@ -170,10 +172,6 @@ class TaskDlgPipeParameters : public TaskDlgSketchBasedParameters TaskDlgPipeParameters(ViewProviderPipe *PipeView,bool newObj=false); ~TaskDlgPipeParameters(); - ViewProviderPipe* getPipeView() const - { return static_cast(vp); } - - public: /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); diff --git a/src/Mod/Path/PathScripts/PathAdaptive.py b/src/Mod/Path/PathScripts/PathAdaptive.py index 7cce64d09206..ed9f87697633 100644 --- a/src/Mod/Path/PathScripts/PathAdaptive.py +++ b/src/Mod/Path/PathScripts/PathAdaptive.py @@ -34,6 +34,11 @@ import area from pivy import coin +# lazily loaded modules +from lazy_loader.lazy_loader import LazyLoader +Part = LazyLoader('Part', globals(), 'Part') +TechDraw = LazyLoader('TechDraw', globals(), 'TechDraw') + __doc__ = "Class and implementation of the Adaptive path operation." def convertTo2d(pathArray): @@ -399,14 +404,9 @@ def Execute(op,obj): if obj.Tolerance < 0.001: obj.Tolerance = 0.001 - pathArray = [] - for base, subs in obj.Base: - for sub in subs: - shape = base.Shape.getElement(sub) - for edge in shape.Edges: - pathArray.append([discretize(edge)]) + # Get list of working edges for adaptive algorithm + pathArray = _get_working_edges(op, obj) - #pathArray=connectEdges(edges) path2d = convertTo2d(pathArray) stockPaths = [] @@ -529,6 +529,35 @@ def progressFn(tpaths): sceneClean() +def _get_working_edges(op, obj): + """_get_working_edges(op, obj)... + Compile all working edges from the Base Geometry selection (obj.Base) + for the current operation. + Additional modifications to selected region(face), such as extensions, + should be placed within this function. + """ + pathArray = list() + + for base, subs in obj.Base: + for sub in subs: + if obj.UseOutline: + face = base.Shape.getElement(sub) + zmin = face.BoundBox.ZMin + # get face outline with same method in PocketShape + wire = TechDraw.findShapeOutline(face, 1, FreeCAD.Vector(0.0, 0.0, 1.0)) + shape = Part.Face(wire) + # translate to face height if necessary + if shape.BoundBox.ZMin != zmin: + shape.translate(FreeCAD.Vector(0.0, 0.0, zmin - shape.BoundBox.ZMin)) + else: + shape = base.Shape.getElement(sub) + + for edge in shape.Edges: + pathArray.append([discretize(edge)]) + + return pathArray + + class PathAdaptive(PathOp.ObjectOp): def opFeatures(self, obj): '''opFeatures(obj) ... returns the OR'ed list of features used and supported by the operation. @@ -574,6 +603,11 @@ def initOperation(self, obj): obj.addProperty("App::PropertyAngle", "HelixConeAngle", "Adaptive", "Helix cone angle (degrees)") obj.addProperty("App::PropertyLength", "HelixDiameterLimit", "Adaptive", "Limit helix entry diameter, if limit larger than tool diameter or 0, tool diameter is used") + if not hasattr(obj, "UseOutline"): + obj.addProperty("App::PropertyBool", + "UseOutline", + "Adaptive", + "Uses the outline of the base geometry.") def opSetDefaultValues(self, obj, job): obj.Side="Inside" @@ -594,6 +628,7 @@ def opSetDefaultValues(self, obj, job): obj.StockToLeave = 0 obj.KeepToolDownRatio = 3.0 obj.UseHelixArcs = False + obj.UseOutline = False def opExecute(self, obj): '''opExecute(obj) ... called whenever the receiver needs to be recalculated. diff --git a/src/Mod/Path/PathScripts/PathAdaptiveGui.py b/src/Mod/Path/PathScripts/PathAdaptiveGui.py index 0e25e9212831..372c4c081e74 100644 --- a/src/Mod/Path/PathScripts/PathAdaptiveGui.py +++ b/src/Mod/Path/PathScripts/PathAdaptiveGui.py @@ -140,6 +140,11 @@ def getForm(self): form.FinishingProfile.setChecked(True) formLayout.addRow(QtGui.QLabel("Finishing Profile"), form.FinishingProfile) + # Use outline checkbox + form.useOutline = QtGui.QCheckBox() + form.useOutline.setChecked(False) + formLayout.addRow(QtGui.QLabel("Use outline"), form.useOutline) + layout.addLayout(formLayout) # stop button @@ -170,6 +175,7 @@ def getSignalsForUpdate(self, obj): # signals.append(self.form.ProcessHoles.stateChanged) signals.append(self.form.ForceInsideOut.stateChanged) signals.append(self.form.FinishingProfile.stateChanged) + signals.append(self.form.useOutline.stateChanged) signals.append(self.form.StopButton.toggled) return signals @@ -191,6 +197,7 @@ def setFields(self, obj): # self.form.ProcessHoles.setChecked(obj.ProcessHoles) self.form.ForceInsideOut.setChecked(obj.ForceInsideOut) self.form.FinishingProfile.setChecked(obj.FinishingProfile) + self.form.useOutline.setChecked(obj.UseOutline) self.setupToolController(obj, self.form.ToolController) self.setupCoolant(obj, self.form.coolantController) self.form.StopButton.setChecked(obj.Stopped) @@ -221,6 +228,7 @@ def getFields(self, obj): obj.ForceInsideOut = self.form.ForceInsideOut.isChecked() obj.FinishingProfile = self.form.FinishingProfile.isChecked() + obj.UseOutline = self.form.useOutline.isChecked() obj.Stopped = self.form.StopButton.isChecked() if(obj.Stopped): self.form.StopButton.setChecked(False) # reset the button diff --git a/src/Mod/Path/PathScripts/PathGeom.py b/src/Mod/Path/PathScripts/PathGeom.py index 5c70b6370103..31031954cae2 100644 --- a/src/Mod/Path/PathScripts/PathGeom.py +++ b/src/Mod/Path/PathScripts/PathGeom.py @@ -284,29 +284,21 @@ def cmdsForEdge(edge, flip = False, useHelixForBSpline = True, segm = 50, hSpeed else: # We're dealing with a helix or a more complex shape and it has to get approximated # by a number of straight segments - eStraight = Part.Edge(Part.LineSegment(p1, p3)) - esP2 = eStraight.valueAt((eStraight.FirstParameter + eStraight.LastParameter)/2) - deviation = (p2 - esP2).Length - if isRoughly(deviation, 0): - return [ Path.Command('G1', {'X': p3.x, 'Y': p3.y, 'Z': p3.z}) ] - # at this point pixellation is all we can do + points = edge.discretize(Deflection=0.01) + if flip: + points = points[::-1] + commands = [] - segments = int(math.ceil((deviation / eStraight.Length) * segm)) - #print("**** pixellation with %d segments" % segments) - dParameter = (edge.LastParameter - edge.FirstParameter) / segments - # starting point - p0 = edge.valueAt(edge.LastParameter) if flip else edge.valueAt(edge.FirstParameter) - for i in range(0, segments): - if flip: - p = edge.valueAt(edge.LastParameter - (i + 1) * dParameter) - else: - p = edge.valueAt(edge.FirstParameter + (i + 1) * dParameter) - if hSpeed > 0 and vSpeed > 0: - params.update({'F': speedBetweenPoints(p0, p, hSpeed, vSpeed)}) - cmd = Path.Command('G1', {'X': p.x, 'Y': p.y, 'Z': p.z}) - #print("***** %s" % cmd) - commands.append(cmd) - p0 = p + if points: + p0 = points[0] + for p in points[1:]: + params = {'X': p.x, 'Y': p.y, 'Z': p.z} + if hSpeed > 0 and vSpeed > 0: + params['F'] = speedBetweenPoints(p0, p, hSpeed, vSpeed) + cmd = Path.Command('G1', params) + # print("***** {}".format(cmd)) + commands.append(cmd) + p0 = p #print commands return commands @@ -542,13 +534,18 @@ def flipEdge(edge): flipped.buildFromPolesMultsKnots(poles, mults , knots, perio, degree, weights, ratio) return Part.Edge(flipped) + elif type(edge.Curve) == Part.OffsetCurve: + return edge.reversed() global OddsAndEnds # pylint: disable=global-statement OddsAndEnds.append(edge) - PathLog.warning(translate('PathGeom', "%s not support for flipping") % type(edge.Curve)) + PathLog.warning(translate('PathGeom', "%s not supported for flipping") % type(edge.Curve)) + +Wire = [] def flipWire(wire): '''Flip the entire wire and all its edges so it is being processed the other way around.''' + Wire.append(wire) edges = [flipEdge(e) for e in wire.Edges] edges.reverse() PathLog.debug(edges) diff --git a/src/Mod/Path/PathTests/TestPathGeom.py b/src/Mod/Path/PathTests/TestPathGeom.py index d96d1ba202d2..896698c485b6 100644 --- a/src/Mod/Path/PathTests/TestPathGeom.py +++ b/src/Mod/Path/PathTests/TestPathGeom.py @@ -29,10 +29,10 @@ from PathTests.PathTestUtils import PathTestBase class TestPathGeom(PathTestBase): - """Test Path <-> Wire conversion.""" + '''Test Path <-> Wire conversion.''' def test00(self): - """Verify getAngle functionality.""" + '''Verify getAngle functionality.''' self.assertRoughly(PathGeom.getAngle(Vector(1, 0, 0)), 0) self.assertRoughly(PathGeom.getAngle(Vector(1, 1, 0)), math.pi/4) self.assertRoughly(PathGeom.getAngle(Vector(0, 1, 0)), math.pi/2) @@ -43,7 +43,7 @@ def test00(self): self.assertRoughly(PathGeom.getAngle(Vector(1, -1, 0)), -math.pi/4) def test01(self): - """Verify diffAngle functionality.""" + '''Verify diffAngle functionality.''' self.assertRoughly(PathGeom.diffAngle(0, +0*math.pi/4, 'CW') / math.pi, 0/4.) self.assertRoughly(PathGeom.diffAngle(0, +3*math.pi/4, 'CW') / math.pi, 5/4.) self.assertRoughly(PathGeom.diffAngle(0, -3*math.pi/4, 'CW') / math.pi, 3/4.) @@ -68,7 +68,7 @@ def test01(self): self.assertRoughly(PathGeom.diffAngle(-math.pi/4, -1*math.pi/4, 'CCW') / math.pi, 0/4.) def test02(self): - """Verify isVertical/isHorizontal for Vector""" + '''Verify isVertical/isHorizontal for Vector''' self.assertTrue(PathGeom.isVertical(Vector(0, 0, 1))) self.assertTrue(PathGeom.isVertical(Vector(0, 0, -1))) self.assertFalse(PathGeom.isVertical(Vector(1, 0, 1))) @@ -89,7 +89,7 @@ def test02(self): self.assertFalse(PathGeom.isHorizontal(Vector(0, -1, -1))) def test03(self): - """Verify isVertical/isHorizontal for Edges""" + '''Verify isVertical/isHorizontal for Edges''' # lines self.assertTrue(PathGeom.isVertical(Part.Edge(Part.LineSegment(Vector(-1, -1, -1), Vector(-1, -1, 8))))) @@ -136,7 +136,7 @@ def test03(self): def test04(self): - """Verify isVertical/isHorizontal for faces""" + '''Verify isVertical/isHorizontal for faces''' # planes xPlane = Part.makePlane(100, 100, Vector(), Vector(1, 0, 0)) @@ -176,7 +176,7 @@ def test04(self): self.assertFalse(PathGeom.isHorizontal(yzCylinder)) def test07(self): - """Verify speed interpolation works for different pitches""" + '''Verify speed interpolation works for different pitches''' # horizontal self.assertRoughly(100, PathGeom.speedBetweenPoints(Vector(), Vector(1,1,0), 100, 50)) self.assertRoughly(100, PathGeom.speedBetweenPoints(Vector(1,1,0), Vector(), 100, 50)) @@ -202,7 +202,7 @@ def test07(self): self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(0,1,0.5774), Vector(), 100, 50), 0.01) def test08(self): - """Verify speed interpolation works for different pitches if vSpeed > hSpeed""" + '''Verify speed interpolation works for different pitches if vSpeed > hSpeed''' # horizontal self.assertRoughly( 50, PathGeom.speedBetweenPoints(Vector(), Vector(1,1,0), 50, 100)) self.assertRoughly( 50, PathGeom.speedBetweenPoints(Vector(1,1,0), Vector(), 50, 100)) @@ -228,13 +228,13 @@ def test08(self): self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(0,1,0.5774), Vector(), 50, 100), 0.01) def test10(self): - """Verify proper geometry objects for G1 and G01 commands are created.""" + '''Verify proper geometry objects for G1 and G01 commands are created.''' spt = Vector(1,2,3) self.assertLine(PathGeom.edgeForCmd(Path.Command('G1', {'X': 7, 'Y': 2, 'Z': 3}), spt), spt, Vector(7, 2, 3)) self.assertLine(PathGeom.edgeForCmd(Path.Command('G01', {'X': 1, 'Y': 3, 'Z': 5}), spt), spt, Vector(1, 3, 5)) def test20(self): - """Verify proper geometry for arcs in the XY-plane are created.""" + '''Verify proper geometry for arcs in the XY-plane are created.''' p1 = Vector(0, -1, 2) p2 = Vector(-1, 0, 2) self.assertArc( @@ -247,7 +247,7 @@ def test20(self): p2, p1, 'CCW') def test30(self): - """Verify proper geometry for arcs with rising and fall ing Z-axis are created.""" + '''Verify proper geometry for arcs with rising and fall ing Z-axis are created.''' #print("------ rising helix -------") p1 = Vector(0, 1, 0) p2 = Vector(1, 0, 2) @@ -277,7 +277,7 @@ def test30(self): p1, Vector(-1/math.sqrt(2), -1/math.sqrt(2), 1), p2) def test40(self): - """Verify arc results in proper G2/3 command.""" + '''Verify arc results in proper G2/3 command.''' p1 = Vector( 0, -10, 0) p2 = Vector(-10, 0, 0) p3 = Vector( 0, +10, 0) @@ -295,7 +295,7 @@ def cmd(g, end, off): self.assertCommandEqual(cmds(p1, p4, p3, True), cmd('G2', p1, Vector(0, -10, 0))) def test41(self): - """Verify circle results in proper G2/G3 commands.""" + '''Verify circle results in proper G2/G3 commands.''' def cmds(center, radius, up = True): norm = Vector(0, 0, 1) if up else Vector(0, 0, -1) @@ -308,8 +308,16 @@ def cmd(g, end, off): self.assertCommandEqual(cmds(center, radius), cmd('G3', Vector(15, 10, 0), Vector(-5, 0, 0))) + def test42(self): + '''Verify ellipsis results in a proper segmentation of G1 commands.''' + ellipse = Part.Edge(Part.Ellipse()) + cmds = PathGeom.cmdsForEdge(ellipse) + # let's make sure all commands are G1 and there are more than 20 of those + self.assertGreater(len(cmds), 20) + self.assertTrue(all([cmd.Name == 'G1' for cmd in cmds])) + def test50(self): - """Verify proper wire(s) aggregation from a Path.""" + '''Verify proper wire(s) aggregation from a Path.''' commands = [] commands.append(Path.Command('G1', {'X': 1})) commands.append(Path.Command('G1', {'Y': 1})) @@ -335,7 +343,7 @@ def test50(self): def test60(self): - """Verify arcToHelix returns proper helix.""" + '''Verify arcToHelix returns proper helix.''' p1 = Vector(10,-10,0) p2 = Vector(0,0,0) p3 = Vector(10,10,0) @@ -368,7 +376,7 @@ def test60(self): def test62(self): - """Verify splitArcAt returns proper subarcs.""" + '''Verify splitArcAt returns proper subarcs.''' p1 = Vector(10,-10,0) p2 = Vector(0,0,0) p3 = Vector(10,10,0) @@ -392,7 +400,7 @@ def test62(self): def test65(self): - """Verify splitEdgeAt.""" + '''Verify splitEdgeAt.''' # split a line segment e = PathGeom.splitEdgeAt(Part.Edge(Part.LineSegment(Vector(), Vector(2, 4, 6))), Vector(1, 2, 3)) @@ -522,4 +530,16 @@ def test75(self): edge = Part.Edge(Part.BSplineCurve([Vector(-8,4,0), Vector(1,-5,0), Vector(5,11,0), Vector(12,-5,0)], weights=[2,3,5,7])) self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + def test76(self): + '''Flip an offset wire''' + + e0 = Part.Edge(Part.BSplineCurve([Vector(-8,4,0), Vector(1,-5,0), Vector(5,11,0), Vector(12,-5,0)], weights=[2,3,5,7])) + e1 = Part.Edge(Part.LineSegment(Vector(12,-5,0), Vector(0,-7,0))) + e2 = Part.Edge(Part.LineSegment(Vector(0,-7,0), Vector(-8,4,0))) + w0 = Part.Wire([e0, e1, e2]) + w1 = w0.makeOffset2D(1) + w2 = PathGeom.flipWire(w1) + # do some sanity checks + self.assertTrue(w2.isValid()) + self.assertTrue(w2.isClosed())