From 3e9ae6c776533a6a62a398e441056088d10046ed Mon Sep 17 00:00:00 2001 From: Daniel Wood Date: Mon, 2 Mar 2020 12:58:55 +0000 Subject: [PATCH 01/28] skip inactive operations --- src/Mod/Path/PathScripts/post/linuxcnc_post.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Mod/Path/PathScripts/post/linuxcnc_post.py b/src/Mod/Path/PathScripts/post/linuxcnc_post.py index 0219ec223f..2c9337882b 100644 --- a/src/Mod/Path/PathScripts/post/linuxcnc_post.py +++ b/src/Mod/Path/PathScripts/post/linuxcnc_post.py @@ -185,6 +185,14 @@ def export(objectslist, filename, argstring): for obj in objectslist: + # Skip inactive operations + if hasattr(obj, 'Active'): + if not obj.Active: + continue + if hasattr(obj, 'Base') and hasattr(obj.Base, 'Active'): + if not obj.Base.Active: + continue + # fetch machine details job = PathUtils.findParentJob(obj) From e3cca6c2412154d1aeb9253da3978b2dc865fb36 Mon Sep 17 00:00:00 2001 From: Daniel Wood Date: Mon, 2 Mar 2020 13:27:14 +0000 Subject: [PATCH 02/28] Handle coolant for ops using dressups --- .../Path/PathScripts/post/linuxcnc_post.py | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Mod/Path/PathScripts/post/linuxcnc_post.py b/src/Mod/Path/PathScripts/post/linuxcnc_post.py index 2c9337882b..8673c50d1d 100644 --- a/src/Mod/Path/PathScripts/post/linuxcnc_post.py +++ b/src/Mod/Path/PathScripts/post/linuxcnc_post.py @@ -218,16 +218,22 @@ def export(objectslist, filename, argstring): for line in PRE_OPERATION.splitlines(True): gcode += linenumber() + line + # get coolant mode + coolantMode = 'None' + if hasattr(obj, "CoolantMode") or hasattr(obj, 'Base') and hasattr(obj.Base, "CoolantMode"): + if hasattr(obj, "CoolantMode"): + coolantMode = obj.CoolantMode + else: + coolantMode = obj.Base.CoolantMode + # turn coolant on if required - if hasattr(obj, "CoolantMode"): - coolantMode = obj.CoolantMode - if OUTPUT_COMMENTS: - if not coolantMode == 'None': - gcode += linenumber() + '(Coolant On:' + coolantMode + ')\n' - if coolantMode == 'Flood': - gcode += linenumber() + 'M8' + '\n' - if coolantMode == 'Mist': - gcode += linenumber() + 'M7' + '\n' + if OUTPUT_COMMENTS: + if not coolantMode == 'None': + gcode += linenumber() + '(Coolant On:' + coolantMode + ')\n' + if coolantMode == 'Flood': + gcode += linenumber() + 'M8' + '\n' + if coolantMode == 'Mist': + gcode += linenumber() + 'M7' + '\n' # process the operation gcode gcode += parse(obj) @@ -239,12 +245,10 @@ def export(objectslist, filename, argstring): gcode += linenumber() + line # turn coolant off if required - if hasattr(obj, "CoolantMode"): - coolantMode = obj.CoolantMode - if not coolantMode == 'None': - if OUTPUT_COMMENTS: - gcode += linenumber() + '(Coolant Off:' + coolantMode + ')\n' - gcode += linenumber() +'M9' + '\n' + if not coolantMode == 'None': + if OUTPUT_COMMENTS: + gcode += linenumber() + '(Coolant Off:' + coolantMode + ')\n' + gcode += linenumber() +'M9' + '\n' # do the post_amble if OUTPUT_COMMENTS: From be293cdfc2dfaac4b4fd8af6424dbdda8246104c Mon Sep 17 00:00:00 2001 From: Daniel Wood Date: Mon, 2 Mar 2020 13:34:08 +0000 Subject: [PATCH 03/28] Stop the spindle before tool changes. --- src/Mod/Path/PathScripts/post/linuxcnc_post.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/Path/PathScripts/post/linuxcnc_post.py b/src/Mod/Path/PathScripts/post/linuxcnc_post.py index 8673c50d1d..372bd40974 100644 --- a/src/Mod/Path/PathScripts/post/linuxcnc_post.py +++ b/src/Mod/Path/PathScripts/post/linuxcnc_post.py @@ -366,8 +366,8 @@ def parse(pathobj): # Check for Tool Change: if command == 'M6': - # if OUTPUT_COMMENTS: - # out += linenumber() + "(begin toolchange)\n" + # stop the spindle + out += linenumber() + "M5\n" for line in TOOL_CHANGE.splitlines(True): out += linenumber() + line From 51c1897a3a26056827c4b0ec9e65d0ce86b8d28a Mon Sep 17 00:00:00 2001 From: Patrick Felixberger Date: Mon, 2 Mar 2020 18:23:59 +0100 Subject: [PATCH 04/28] Added coolant support to grbl_post Improved canned cycles Added/translated comments --- src/Mod/Path/PathScripts/PathDrilling.py | 1 + src/Mod/Path/PathScripts/post/grbl_post.py | 34 ++++++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDrilling.py b/src/Mod/Path/PathScripts/PathDrilling.py index a1e436efa3..64d5447abe 100644 --- a/src/Mod/Path/PathScripts/PathDrilling.py +++ b/src/Mod/Path/PathScripts/PathDrilling.py @@ -162,6 +162,7 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): # Perform and cancel canned drilling cycle self.commandlist.append(Path.Command(cmd, params)) + self.commandlist.append(Path.Command('G80')) self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value})) diff --git a/src/Mod/Path/PathScripts/post/grbl_post.py b/src/Mod/Path/PathScripts/post/grbl_post.py index 1a80aa2630..1bc939f7ef 100755 --- a/src/Mod/Path/PathScripts/post/grbl_post.py +++ b/src/Mod/Path/PathScripts/post/grbl_post.py @@ -3,6 +3,7 @@ # * * # * (c) sliptonic (shopinthewoods@gmail.com) 2014 * # * (c) Gauthier Briere - 2018, 2019 * +# * (c) Schildkroet - 2019-2020 * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -108,7 +109,7 @@ TOOLTIP_ARGS = parser.format_help() # *************************************************************************** MOTION_COMMANDS = ['G0', 'G00', 'G1', 'G01', 'G2', 'G02', 'G3', 'G03'] # Motion gCode commands definition RAPID_MOVES = ['G0', 'G00'] # Rapid moves gCode commands definition -SUPPRESS_COMMANDS = ['G98', 'G80'] # These commands are ignored by commenting them out +SUPPRESS_COMMANDS = [] # These commands are ignored by commenting them out COMMAND_SPACE = " " # Global variables storing current position CURRENT_X = 0 @@ -208,6 +209,7 @@ def export(objectslist, filename, argstring): global UNIT_FORMAT global UNIT_SPEED_FORMAT global MOTION_MODE + global SUPPRESS_COMMANDS print("Post Processor: " + __name__ + " postprocessing...") gcode = "" @@ -217,6 +219,13 @@ def export(objectslist, filename, argstring): gcode += linenumber() + "(Exported by FreeCAD)\n" gcode += linenumber() + "(Post Processor: " + __name__ + ")\n" gcode += linenumber() + "(Output Time:" + str(datetime.datetime.now()) + ")\n" + + # Check canned cycles for drilling + if TRANSLATE_DRILL_CYCLES: + if len(SUPPRESS_COMMANDS) == 0: + SUPPRESS_COMMANDS = ['G98', 'G80'] + else: + SUPPRESS_COMMANDS += ['G98', 'G80'] # Write the preamble if OUTPUT_COMMENTS: @@ -259,6 +268,17 @@ def export(objectslist, filename, argstring): gcode += linenumber() + "(Begin operation: " + obj.Label + ")\n" for line in PRE_OPERATION.splitlines(True): gcode += linenumber() + line + + # turn coolant on if required + if hasattr(obj, "CoolantMode"): + coolantMode = obj.CoolantMode + if OUTPUT_COMMENTS: + if not coolantMode == 'None': + gcode += linenumber() + '(Coolant On:' + coolantMode + ')\n' + if coolantMode == 'Flood': + gcode += linenumber() + 'M8' + '\n' + if coolantMode == 'Mist': + gcode += linenumber() + 'M7' + '\n' # Parse the op gcode += parse(obj) @@ -269,6 +289,14 @@ def export(objectslist, filename, argstring): for line in POST_OPERATION.splitlines(True): gcode += linenumber() + line + # turn coolant off if required + if hasattr(obj, "CoolantMode"): + coolantMode = obj.CoolantMode + if not coolantMode == 'None': + if OUTPUT_COMMENTS: + gcode += linenumber() + '(Coolant Off:' + coolantMode + ')\n' + gcode += linenumber() +'M9' + '\n' + # do the post_amble if OUTPUT_BCNC: gcode += linenumber() + "(Block-name: post_amble)\n" @@ -380,7 +408,7 @@ def parse(pathobj): # store the latest command lastcommand = command - # Memorise la position courante pour calcul des mouvements relatis et du plan de retrait + # Memorizes the current position for calculating the related movements and the withdrawal plan if command in MOTION_COMMANDS: if 'X' in c.Parameters: CURRENT_X = Units.Quantity(c.Parameters['X'], FreeCAD.Units.Length) @@ -398,7 +426,7 @@ def parse(pathobj): if TRANSLATE_DRILL_CYCLES: if command in ('G81', 'G82', 'G83'): out += drill_translate(outstring, command, c.Parameters) - # Efface la ligne que l'on vient de translater + # Erase the line we just translated del(outstring[:]) outstring = [] From fefc7259038d2f25009a74d1bc07b726636b190e Mon Sep 17 00:00:00 2001 From: Patrick Felixberger Date: Mon, 2 Mar 2020 21:17:19 +0100 Subject: [PATCH 05/28] Fixed coolant with dressup --- src/Mod/Path/PathScripts/post/grbl_post.py | 46 +++++++++++++++------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/Mod/Path/PathScripts/post/grbl_post.py b/src/Mod/Path/PathScripts/post/grbl_post.py index 1bc939f7ef..d080f24d05 100755 --- a/src/Mod/Path/PathScripts/post/grbl_post.py +++ b/src/Mod/Path/PathScripts/post/grbl_post.py @@ -258,6 +258,17 @@ def export(objectslist, filename, argstring): if not hasattr(obj, "Path"): print("The object " + obj.Name + " is not a path. Please select only path and Compounds.") return + + isActive = True + if hasattr(obj, "Active") or hasattr(obj, 'Base') and hasattr(obj.Base, "Active"): + if hasattr(obj, "Active"): + isActive = obj.Active + else: + isActive = obj.Base.Active + if isActive: + print("obj.Base.active true") + else: + print("obj.active false") # do the pre_op if OUTPUT_BCNC: @@ -269,16 +280,22 @@ def export(objectslist, filename, argstring): for line in PRE_OPERATION.splitlines(True): gcode += linenumber() + line + # get coolant mode + coolantMode = 'None' + if hasattr(obj, "CoolantMode") or hasattr(obj, 'Base') and hasattr(obj.Base, "CoolantMode"): + if hasattr(obj, "CoolantMode"): + coolantMode = obj.CoolantMode + else: + coolantMode = obj.Base.CoolantMode + # turn coolant on if required - if hasattr(obj, "CoolantMode"): - coolantMode = obj.CoolantMode - if OUTPUT_COMMENTS: - if not coolantMode == 'None': - gcode += linenumber() + '(Coolant On:' + coolantMode + ')\n' - if coolantMode == 'Flood': - gcode += linenumber() + 'M8' + '\n' - if coolantMode == 'Mist': - gcode += linenumber() + 'M7' + '\n' + if OUTPUT_COMMENTS and isActive: + if not coolantMode == 'None': + gcode += linenumber() + '(Coolant On:' + coolantMode + ')\n' + if coolantMode == 'Flood' and isActive: + gcode += linenumber() + 'M8' + '\n' + if coolantMode == 'Mist' and isActive: + gcode += linenumber() + 'M7' + '\n' # Parse the op gcode += parse(obj) @@ -290,12 +307,11 @@ def export(objectslist, filename, argstring): gcode += linenumber() + line # turn coolant off if required - if hasattr(obj, "CoolantMode"): - coolantMode = obj.CoolantMode - if not coolantMode == 'None': - if OUTPUT_COMMENTS: - gcode += linenumber() + '(Coolant Off:' + coolantMode + ')\n' - gcode += linenumber() +'M9' + '\n' + if not coolantMode == 'None': + if OUTPUT_COMMENTS and isActive: + gcode += linenumber() + '(Coolant Off:' + coolantMode + ')\n' + if isActive: + gcode += linenumber() +'M9' + '\n' # do the post_amble if OUTPUT_BCNC: From 24d64c71ec97d484405e9d606f04b817303e6199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Skowro=C5=84ski?= Date: Mon, 2 Mar 2020 23:13:10 +0100 Subject: [PATCH 06/28] [ImageWB] Fix image scaling dialog for HighDPI displays. --- .../Image/ImageTools/_CommandImageScaling.py | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/Mod/Image/ImageTools/_CommandImageScaling.py b/src/Mod/Image/ImageTools/_CommandImageScaling.py index 09fd943e2b..50f7e5a39e 100644 --- a/src/Mod/Image/ImageTools/_CommandImageScaling.py +++ b/src/Mod/Image/ImageTools/_CommandImageScaling.py @@ -35,7 +35,6 @@ if FreeCAD.GuiUp: import FreeCADGui, FreeCAD, Part import math import pivy.coin as pvy - from PySide import QtCore, QtGui import DraftTrackers, Draft # translation-related code @@ -86,14 +85,13 @@ def cmdCreateImageScaling(name): dz=p2[2]-p1[2] return math.sqrt(dx*dx+dy*dy+dz*dz) - sizeX = 300; sizeY = 102 def centerOnScreen (widg): '''centerOnScreen() Centers the window on the screen.''' - resolution = QtGui.QDesktopWidget().screenGeometry() - xp=(resolution.width() / 2) - sizeX/2 - yp=(resolution.height() / 2) - sizeY/2 - widg.setGeometry(xp, yp, sizeX, sizeY) + resolution = QtGui.QDesktopWidget().screenGeometry() # TODO: fix multi monitor support + xp=(resolution.width() / 2) - widg.frameGeometry().width()/2 + yp=(resolution.height() / 2) - widg.frameGeometry().height()/2 + widg.move(xp, yp) class Ui_Dialog(object): def setupUi(self, Dialog): @@ -105,22 +103,33 @@ def cmdCreateImageScaling(name): self.dialog=Dialog Dialog.setObjectName(_fromUtf8("Dialog")) Dialog.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) - Dialog.resize(sizeX, sizeY) + + self.verticalLayout = QtGui.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout = QtGui.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + + self.label = QtGui.QLabel(Dialog) + self.label.setObjectName(_fromUtf8("label")) + self.horizontalLayout.addWidget(self.label) + + self.lineEdit = QtGui.QLineEdit(Dialog) + self.lineEdit.setObjectName(_fromUtf8("lineEdit")) + self.horizontalLayout.addWidget(self.lineEdit) + + self.label1 = QtGui.QLabel(Dialog) + self.label1.setObjectName(_fromUtf8("label1")) + self.buttonBox = QtGui.QDialogButtonBox(Dialog) - self.buttonBox.setGeometry(QtCore.QRect(50, 70, 191, 32)) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) self.buttonBox.setObjectName(_fromUtf8("buttonBox")) self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False) - self.label = QtGui.QLabel(Dialog) - self.label.setGeometry(QtCore.QRect(30, 10, 86, 17)) - self.label.setObjectName(_fromUtf8("label")) - self.lineEdit = QtGui.QLineEdit(Dialog) - self.lineEdit.setGeometry(QtCore.QRect(140, 10, 153, 29)) - self.lineEdit.setObjectName(_fromUtf8("lineEdit")) - self.label1 = QtGui.QLabel(Dialog) - self.label1.setGeometry(QtCore.QRect(20, 45, 260, 17)) - self.label1.setObjectName(_fromUtf8("label1")) + + self.verticalLayout.addLayout(self.horizontalLayout) + self.verticalLayout.addWidget(self.label1) + self.verticalLayout.addWidget(self.buttonBox) + self.retranslateUi(Dialog) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), self.accept) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), self.reject) From aa422bf7d5a37b69e47492d415663b4a7b157123 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 3 Mar 2020 00:10:48 +0100 Subject: [PATCH 07/28] ReverseEngineering: [skip ci] improve segmentation based on point clouds --- .../App/AppReverseEngineering.cpp | 75 +++++++++++++++++-- .../App/SampleConsensus.cpp | 71 ++++++++++++++++-- .../ReverseEngineering/App/SampleConsensus.h | 17 ++++- 3 files changed, 150 insertions(+), 13 deletions(-) diff --git a/src/Mod/ReverseEngineering/App/AppReverseEngineering.cpp b/src/Mod/ReverseEngineering/App/AppReverseEngineering.cpp index 0f8c79474d..2eb291c43f 100644 --- a/src/Mod/ReverseEngineering/App/AppReverseEngineering.cpp +++ b/src/Mod/ReverseEngineering/App/AppReverseEngineering.cpp @@ -725,27 +725,92 @@ Mesh.show(m) } #endif #if defined(HAVE_PCL_SAMPLE_CONSENSUS) + /* +import ReverseEngineering as reen +import Points +import Part + +p = App.ActiveDocument.Points.Points +data = p.Points +n = reen.normalEstimation(p, 10) + +model = reen.sampleConsensus(SacModel="Plane", Points=p) +indices = model["Model"] +param = model["Parameters"] + +plane = Part.Plane() +plane.Axis = param[0:3] +plane.Position = -plane.Axis * param[3] + +np = Points.Points() +np.addPoints([data[i] for i in indices]) +Points.show(np) + +# sort in descending order +indices = list(indices) +indices.sort(reverse=True) + +# remove points of segment +for i in indices: + del data[i] + del n[i] + +p = Points.Points() +p.addPoints(data) +model = reen.sampleConsensus(SacModel="Cylinder", Points=p, Normals=n) +indices = model["Model"] + +np = Points.Points() +np.addPoints([data[i] for i in indices]) +Points.show(np) + */ Py::Object sampleConsensus(const Py::Tuple& args, const Py::Dict& kwds) { PyObject *pts; + PyObject *vec = nullptr; + const char* sacModelType = nullptr; - static char* kwds_sample[] = {"Points", NULL}; - if (!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O!", kwds_sample, - &(Points::PointsPy::Type), &pts)) + static char* kwds_sample[] = {"SacModel", "Points", "Normals", NULL}; + if (!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "sO!|O", kwds_sample, + &sacModelType, &(Points::PointsPy::Type), &pts, &vec)) throw Py::Exception(); Points::PointKernel* points = static_cast(pts)->getPointKernelPtr(); + std::vector normals; + if (vec) { + Py::Sequence list(vec); + normals.reserve(list.size()); + for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { + Base::Vector3d v = Py::Vector(*it).toVector(); + normals.push_back(v); + } + } + + SampleConsensus::SacModel sacModel = SampleConsensus::SACMODEL_PLANE; + if (sacModelType) { + if (strcmp(sacModelType, "Cylinder") == 0) + sacModel = SampleConsensus::SACMODEL_CYLINDER; + else if (strcmp(sacModelType, "Sphere") == 0) + sacModel = SampleConsensus::SACMODEL_SPHERE; + else if (strcmp(sacModelType, "Cone") == 0) + sacModel = SampleConsensus::SACMODEL_CONE; + } std::vector parameters; - SampleConsensus sample(*points); - double probability = sample.perform(parameters); + SampleConsensus sample(sacModel, *points, normals); + std::vector model; + double probability = sample.perform(parameters, model); Py::Dict dict; Py::Tuple tuple(parameters.size()); for (std::size_t i = 0; i < parameters.size(); i++) tuple.setItem(i, Py::Float(parameters[i])); + Py::Tuple data(model.size()); + for (std::size_t i = 0; i < model.size(); i++) + data.setItem(i, Py::Long(model[i])); dict.setItem(Py::String("Probability"), Py::Float(probability)); dict.setItem(Py::String("Parameters"), tuple); + dict.setItem(Py::String("Model"), data); return dict; } diff --git a/src/Mod/ReverseEngineering/App/SampleConsensus.cpp b/src/Mod/ReverseEngineering/App/SampleConsensus.cpp index cb0d654a66..9c53911e5a 100644 --- a/src/Mod/ReverseEngineering/App/SampleConsensus.cpp +++ b/src/Mod/ReverseEngineering/App/SampleConsensus.cpp @@ -30,8 +30,12 @@ #if defined(HAVE_PCL_SAMPLE_CONSENSUS) #include +#include #include #include +#include +#include +#include using namespace std; using namespace Reen; @@ -39,12 +43,14 @@ using pcl::PointXYZ; using pcl::PointNormal; using pcl::PointCloud; -SampleConsensus::SampleConsensus(const Points::PointKernel& pts) - : myPoints(pts) +SampleConsensus::SampleConsensus(SacModel sac, const Points::PointKernel& pts, const std::vector& nor) + : mySac(sac) + , myPoints(pts) + , myNormals(nor) { } -double SampleConsensus::perform(std::vector& parameters) +double SampleConsensus::perform(std::vector& parameters, std::vector& model) { pcl::PointCloud::Ptr cloud (new pcl::PointCloud); cloud->reserve(myPoints.size()); @@ -57,14 +63,67 @@ double SampleConsensus::perform(std::vector& parameters) cloud->height = 1; cloud->is_dense = true; + pcl::PointCloud::Ptr normals (new pcl::PointCloud ()); + if (mySac == SACMODEL_CONE || mySac == SACMODEL_CYLINDER) { +#if 0 + // Create search tree + pcl::search::KdTree::Ptr tree; + tree.reset (new pcl::search::KdTree (false)); + tree->setInputCloud (cloud); + + // Normal estimation + int ksearch = 10; + pcl::NormalEstimation n; + n.setInputCloud (cloud); + n.setSearchMethod (tree); + n.setKSearch (ksearch); + n.compute (*normals); +#else + normals->reserve(myNormals.size()); + for (std::vector::const_iterator it = myNormals.begin(); it != myNormals.end(); ++it) { + if (!boost::math::isnan(it->x) && !boost::math::isnan(it->y) && !boost::math::isnan(it->z)) + normals->push_back(pcl::Normal(it->x, it->y, it->z)); + } +#endif + } + // created RandomSampleConsensus object and compute the appropriated model - pcl::SampleConsensusModelPlane::Ptr - model_p (new pcl::SampleConsensusModelPlane (cloud)); + pcl::SampleConsensusModel::Ptr model_p; + switch (mySac) { + case SACMODEL_PLANE: + { + model_p.reset(new pcl::SampleConsensusModelPlane (cloud)); + break; + } + case SACMODEL_SPHERE: + { + model_p.reset(new pcl::SampleConsensusModelSphere (cloud)); + break; + } + case SACMODEL_CONE: + { + pcl::SampleConsensusModelCone::Ptr model_c + (new pcl::SampleConsensusModelCone (cloud)); + model_c->setInputNormals(normals); + model_p = model_c; + break; + } + case SACMODEL_CYLINDER: + { + pcl::SampleConsensusModelCylinder::Ptr model_c + (new pcl::SampleConsensusModelCylinder (cloud)); + model_c->setInputNormals(normals); + model_p = model_c; + break; + } + default: + throw Base::RuntimeError("Unsupported SAC model"); + } pcl::RandomSampleConsensus ransac (model_p); ransac.setDistanceThreshold (.01); ransac.computeModel(); - //ransac.getInliers(inliers); + ransac.getInliers(model); //ransac.getModel (model); Eigen::VectorXf model_p_coefficients; ransac.getModelCoefficients (model_p_coefficients); diff --git a/src/Mod/ReverseEngineering/App/SampleConsensus.h b/src/Mod/ReverseEngineering/App/SampleConsensus.h index e24780082b..0d8ea2cdf4 100644 --- a/src/Mod/ReverseEngineering/App/SampleConsensus.h +++ b/src/Mod/ReverseEngineering/App/SampleConsensus.h @@ -34,11 +34,24 @@ namespace Reen { class SampleConsensus { public: - SampleConsensus(const Points::PointKernel&); - double perform(std::vector& parameters); + enum SacModel + { + SACMODEL_PLANE, + SACMODEL_LINE, + SACMODEL_CIRCLE2D, + SACMODEL_CIRCLE3D, + SACMODEL_SPHERE, + SACMODEL_CYLINDER, + SACMODEL_CONE, + SACMODEL_TORUS, + }; + SampleConsensus(SacModel sac, const Points::PointKernel&, const std::vector&); + double perform(std::vector& parameters, std::vector& model); private: + SacModel mySac; const Points::PointKernel& myPoints; + const std::vector& myNormals; }; } // namespace Reen From 2a857dcd81c17b98c6dad7d441264eabaa4334ae Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 3 Mar 2020 12:20:42 +0100 Subject: [PATCH 08/28] Mesh: change MeshSegmentAlgorithm::FindSegments to accept shared instead of raw pointers --- src/Mod/Mesh/App/Core/Approximation.cpp | 7 +++++++ src/Mod/Mesh/App/Core/Approximation.h | 5 +++++ src/Mod/Mesh/App/Core/Segmentation.cpp | 4 ++-- src/Mod/Mesh/App/Core/Segmentation.h | 4 +++- src/Mod/Mesh/App/Mesh.cpp | 6 +++--- src/Mod/Mesh/App/MeshPyImp.cpp | 7 +++---- src/Mod/Mesh/Gui/Segmentation.cpp | 13 ++++++------- src/Mod/Mesh/Gui/SegmentationBestFit.cpp | 11 +++++------ 8 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/Mod/Mesh/App/Core/Approximation.cpp b/src/Mod/Mesh/App/Core/Approximation.cpp index d34b7f894d..0c7521907b 100644 --- a/src/Mod/Mesh/App/Core/Approximation.cpp +++ b/src/Mod/Mesh/App/Core/Approximation.cpp @@ -30,6 +30,7 @@ #endif #include "Approximation.h" +#include "Elements.h" #include "Utilities.h" #include @@ -97,6 +98,12 @@ void Approximation::AddPoints(const std::list &points) _bIsFitted = false; } +void Approximation::AddPoints(const MeshPointArray &points) +{ + std::copy(points.begin(), points.end(), std::back_inserter(_vPoints)); + _bIsFitted = false; +} + Base::Vector3f Approximation::GetGravity() const { Base::Vector3f clGravity; diff --git a/src/Mod/Mesh/App/Core/Approximation.h b/src/Mod/Mesh/App/Core/Approximation.h index 9ce2911593..168eb06e70 100644 --- a/src/Mod/Mesh/App/Core/Approximation.h +++ b/src/Mod/Mesh/App/Core/Approximation.h @@ -94,6 +94,7 @@ protected: } namespace MeshCore { +class MeshPointArray; /** * Abstract base class for approximation of a geometry to a given set of points. @@ -125,6 +126,10 @@ public: * Add points for the fit algorithm. */ void AddPoints(const std::list &rsPointList); + /** + * Add points for the fit algorithm. + */ + void AddPoints(const MeshPointArray &points); /** * Get all added points. */ diff --git a/src/Mod/Mesh/App/Core/Segmentation.cpp b/src/Mod/Mesh/App/Core/Segmentation.cpp index 983d8c6da9..c0f693fee5 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.cpp +++ b/src/Mod/Mesh/App/Core/Segmentation.cpp @@ -471,7 +471,7 @@ bool MeshSurfaceVisitor::Visit (const MeshFacet & face, const MeshFacet &, // -------------------------------------------------------- -void MeshSegmentAlgorithm::FindSegments(std::vector& segm) +void MeshSegmentAlgorithm::FindSegments(std::vector& segm) { // reset VISIT flags unsigned long startFacet; @@ -487,7 +487,7 @@ void MeshSegmentAlgorithm::FindSegments(std::vector& segm) cAlgo.CountFacetFlag(MeshCore::MeshFacet::VISIT); std::vector resetVisited; - for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { + for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { cAlgo.ResetFacetsFlag(resetVisited, MeshCore::MeshFacet::VISIT); resetVisited.clear(); diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h index d2ac9715cf..e1fe5d28d8 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.h +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -27,6 +27,7 @@ #include "Curvature.h" #include "Visitor.h" #include +#include namespace MeshCore { @@ -55,6 +56,7 @@ protected: std::vector segments; unsigned long minFacets; }; +typedef std::shared_ptr MeshSurfaceSegmentPtr; // -------------------------------------------------------- @@ -263,7 +265,7 @@ class MeshExport MeshSegmentAlgorithm { public: MeshSegmentAlgorithm(const MeshKernel& kernel) : myKernel(kernel) {} - void FindSegments(std::vector&); + void FindSegments(std::vector&); private: const MeshKernel& myKernel; diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 5864e6d93d..8288447d37 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -1804,7 +1804,7 @@ std::vector MeshObject::getSegmentsOfType(MeshObject::GeometryType type return segm; MeshCore::MeshSegmentAlgorithm finder(this->_kernel); - std::unique_ptr surf; + std::shared_ptr surf; switch (type) { case PLANE: //surf.reset(new MeshCore::MeshDistancePlanarSegment(this->_kernel, minFacets, dev)); @@ -1824,8 +1824,8 @@ std::vector MeshObject::getSegmentsOfType(MeshObject::GeometryType type } if (surf.get()) { - std::vector surfaces; - surfaces.push_back(surf.get()); + std::vector surfaces; + surfaces.push_back(surf); finder.FindSegments(surfaces); const std::vector& data = surf->GetSegments(); diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index eac9b096ac..08037f771d 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -1887,7 +1887,7 @@ PyObject* MeshPy::getSegmentsByCurvature(PyObject *args) meshCurv.ComputePerVertex(); Py::Sequence func(l); - std::vector segm; + std::vector segm; for (Py::Sequence::iterator it = func.begin(); it != func.end(); ++it) { Py::Tuple t(*it); float c1 = (float)Py::Float(t[0]); @@ -1899,13 +1899,13 @@ PyObject* MeshPy::getSegmentsByCurvature(PyObject *args) #else int num = (int)Py::Int(t[4]); #endif - segm.push_back(new MeshCore::MeshCurvatureFreeformSegment(meshCurv.GetCurvature(), num, tol1, tol2, c1, c2)); + segm.emplace_back(new MeshCore::MeshCurvatureFreeformSegment(meshCurv.GetCurvature(), num, tol1, tol2, c1, c2)); } finder.FindSegments(segm); Py::List list; - for (std::vector::iterator segmIt = segm.begin(); segmIt != segm.end(); ++segmIt) { + for (std::vector::iterator segmIt = segm.begin(); segmIt != segm.end(); ++segmIt) { const std::vector& data = (*segmIt)->GetSegments(); for (std::vector::const_iterator it = data.begin(); it != data.end(); ++it) { Py::List ary; @@ -1918,7 +1918,6 @@ PyObject* MeshPy::getSegmentsByCurvature(PyObject *args) } list.append(ary); } - delete (*segmIt); } return Py::new_reference_to(list); diff --git a/src/Mod/Mesh/Gui/Segmentation.cpp b/src/Mod/Mesh/Gui/Segmentation.cpp index 3fe27d7975..7a8e62e117 100644 --- a/src/Mod/Mesh/Gui/Segmentation.cpp +++ b/src/Mod/Mesh/Gui/Segmentation.cpp @@ -83,23 +83,23 @@ void Segmentation::accept() MeshCore::MeshCurvature meshCurv(kernel); meshCurv.ComputePerVertex(); - std::vector segm; + std::vector segm; if (ui->groupBoxFree->isChecked()) { - segm.push_back(new MeshCore::MeshCurvatureFreeformSegment + segm.emplace_back(new MeshCore::MeshCurvatureFreeformSegment (meshCurv.GetCurvature(), ui->numFree->value(), ui->tol1Free->value(), ui->tol2Free->value(), ui->crv1Free->value(), ui->crv2Free->value())); } if (ui->groupBoxCyl->isChecked()) { - segm.push_back(new MeshCore::MeshCurvatureCylindricalSegment + segm.emplace_back(new MeshCore::MeshCurvatureCylindricalSegment (meshCurv.GetCurvature(), ui->numCyl->value(), ui->tol1Cyl->value(), ui->tol2Cyl->value(), ui->crvCyl->value())); } if (ui->groupBoxSph->isChecked()) { - segm.push_back(new MeshCore::MeshCurvatureSphericalSegment + segm.emplace_back(new MeshCore::MeshCurvatureSphericalSegment (meshCurv.GetCurvature(), ui->numSph->value(), ui->tolSph->value(), ui->crvSph->value())); } if (ui->groupBoxPln->isChecked()) { - segm.push_back(new MeshCore::MeshCurvaturePlanarSegment + segm.emplace_back(new MeshCore::MeshCurvaturePlanarSegment (meshCurv.GetCurvature(), ui->numPln->value(), ui->tolPln->value())); } finder.FindSegments(segm); @@ -114,7 +114,7 @@ void Segmentation::accept() std::string labelname = "Segments "; labelname += myMesh->Label.getValue(); group->Label.setValue(labelname); - for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { + for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { const std::vector& data = (*it)->GetSegments(); for (std::vector::const_iterator jt = data.begin(); jt != data.end(); ++jt) { Mesh::MeshObject* segment = mesh->meshFromSegment(*jt); @@ -128,7 +128,6 @@ void Segmentation::accept() label << feaSegm->Label.getValue() << " (" << (*it)->GetType() << ")"; feaSegm->Label.setValue(label.str()); } - delete (*it); } document->commitTransaction(); } diff --git a/src/Mod/Mesh/Gui/SegmentationBestFit.cpp b/src/Mod/Mesh/Gui/SegmentationBestFit.cpp index 212f7fd28b..f8419d160b 100644 --- a/src/Mod/Mesh/Gui/SegmentationBestFit.cpp +++ b/src/Mod/Mesh/Gui/SegmentationBestFit.cpp @@ -382,7 +382,7 @@ void SegmentationBestFit::accept() MeshCore::MeshSegmentAlgorithm finder(kernel); - std::vector segm; + std::vector segm; if (ui->groupBoxCyl->isChecked()) { MeshCore::AbstractSurfaceFit* fitter; if (cylinderParameter.size() == 7) { @@ -395,7 +395,7 @@ void SegmentationBestFit::accept() else { fitter = new MeshCore::CylinderSurfaceFit; } - segm.push_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment + segm.emplace_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment (fitter, kernel, ui->numCyl->value(), ui->tolCyl->value())); } if (ui->groupBoxSph->isChecked()) { @@ -409,7 +409,7 @@ void SegmentationBestFit::accept() else { fitter = new MeshCore::SphereSurfaceFit; } - segm.push_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment + segm.emplace_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment (fitter, kernel, ui->numSph->value(), ui->tolSph->value())); } if (ui->groupBoxPln->isChecked()) { @@ -423,7 +423,7 @@ void SegmentationBestFit::accept() else { fitter = new MeshCore::PlaneSurfaceFit; } - segm.push_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment + segm.emplace_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment (fitter, kernel, ui->numPln->value(), ui->tolPln->value())); } finder.FindSegments(segm); @@ -438,7 +438,7 @@ void SegmentationBestFit::accept() std::string labelname = "Segments "; labelname += myMesh->Label.getValue(); group->Label.setValue(labelname); - for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { + for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { const std::vector& data = (*it)->GetSegments(); for (std::vector::const_iterator jt = data.begin(); jt != data.end(); ++jt) { Mesh::MeshObject* segment = mesh->meshFromSegment(*jt); @@ -452,7 +452,6 @@ void SegmentationBestFit::accept() label << feaSegm->Label.getValue() << " (" << (*it)->GetType() << ")"; feaSegm->Label.setValue(label.str()); } - delete (*it); } document->commitTransaction(); } From 3d2fb0127e12b463781edb183559009fec6052d6 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sun, 2 Feb 2020 14:04:22 -0600 Subject: [PATCH 09/28] Draft: new Draft_OrthoArray command It replaces the older `Draft_Array` command, and provides a task panel to select the properties, similar to the `Draft_PolarArray` and `Draft_CircularArray` commands. It can also create `App::Links` directly from this task panel, so it also replaces the `Draft_LinkArray` introduced by the LinkMerge. --- src/Mod/Arch/InitGui.py | 1 + src/Mod/Draft/CMakeLists.txt | 4 + src/Mod/Draft/InitGui.py | 1 + src/Mod/Draft/Resources/Draft.qrc | 1 + .../Resources/ui/TaskPanel_OrthoArray.ui | 441 ++++++++++++++++++ src/Mod/Draft/draftguitools/gui_arrays.py | 2 +- src/Mod/Draft/draftguitools/gui_orthoarray.py | 142 ++++++ src/Mod/Draft/draftobjects/orthoarray.py | 60 +++ .../Draft/drafttaskpanels/task_orthoarray.py | 347 ++++++++++++++ .../draftviewproviders/view_orthoarray.py | 43 ++ 10 files changed, 1041 insertions(+), 1 deletion(-) create mode 100644 src/Mod/Draft/Resources/ui/TaskPanel_OrthoArray.ui create mode 100644 src/Mod/Draft/draftguitools/gui_orthoarray.py create mode 100644 src/Mod/Draft/draftobjects/orthoarray.py create mode 100644 src/Mod/Draft/drafttaskpanels/task_orthoarray.py create mode 100644 src/Mod/Draft/draftviewproviders/view_orthoarray.py diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 07962ad989..53d154c1b9 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -51,6 +51,7 @@ class ArchWorkbench(FreeCADGui.Workbench): import DraftGui from draftguitools import gui_circulararray from draftguitools import gui_polararray + from draftguitools import gui_orthoarray from draftguitools import gui_arrays import Arch_rc import Arch diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index 31e6e30e64..ae6a91f934 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -60,12 +60,14 @@ SET(Draft_utilities SET(Draft_objects draftobjects/__init__.py draftobjects/circulararray.py + draftobjects/orthoarray.py draftobjects/polararray.py ) SET(Draft_view_providers draftviewproviders/__init__.py draftviewproviders/view_circulararray.py + draftviewproviders/view_orthoarray.py draftviewproviders/view_polararray.py ) @@ -73,6 +75,7 @@ SET(Draft_GUI_tools draftguitools/__init__.py draftguitools/gui_base.py draftguitools/gui_circulararray.py + draftguitools/gui_orthoarray.py draftguitools/gui_polararray.py draftguitools/gui_arrays.py ) @@ -80,6 +83,7 @@ SET(Draft_GUI_tools SET(Draft_task_panels drafttaskpanels/__init__.py drafttaskpanels/task_circulararray.py + drafttaskpanels/task_orthoarray.py drafttaskpanels/task_polararray.py ) diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index cace902269..d864f31af4 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -82,6 +82,7 @@ class DraftWorkbench(FreeCADGui.Workbench): import DraftFillet from draftguitools import gui_circulararray from draftguitools import gui_polararray + from draftguitools import gui_orthoarray from draftguitools import gui_arrays FreeCADGui.addLanguagePath(":/translations") FreeCADGui.addIconPath(":/icons") diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc index 0156b55822..0eef2df32e 100644 --- a/src/Mod/Draft/Resources/Draft.qrc +++ b/src/Mod/Draft/Resources/Draft.qrc @@ -152,6 +152,7 @@ ui/preferences-oca.ui ui/preferences-svg.ui ui/TaskPanel_CircularArray.ui + ui/TaskPanel_OrthoArray.ui ui/TaskPanel_PolarArray.ui ui/TaskSelectPlane.ui ui/TaskShapeString.ui diff --git a/src/Mod/Draft/Resources/ui/TaskPanel_OrthoArray.ui b/src/Mod/Draft/Resources/ui/TaskPanel_OrthoArray.ui new file mode 100644 index 0000000000..52541fe2f9 --- /dev/null +++ b/src/Mod/Draft/Resources/ui/TaskPanel_OrthoArray.ui @@ -0,0 +1,441 @@ + + + DraftOrthoArrayTaskPanel + + + + 0 + 0 + 440 + 883 + + + + + 0 + 0 + + + + + 250 + 0 + + + + Orthogonal array + + + + + + + 0 + 0 + + + + + + + + + + Distance between the elements in the Z direction. Normally, only the Z value is necessary; the other two values can give an additional shift in their respective directions. + + + Interval Z + + + + + + + + Z + + + + + + + Y + + + + + + + X + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + 100.000000000000000 + + + + + + + + + Reset the distances + + + Reset Z + + + + + + + + + + + + If checked, the resulting objects in the array will be fused if they touch each other + + + Fuse + + + + + + + If checked, the resulting objects in the array will be Links instead of simple copies + + + Use Links + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Number of elements in the array in the specified direction, including a copy of the original object. The number must be at least 1 in each direction. + + + Number of elements + + + + + + + + X + + + + + + + Z + + + + + + + Y + + + + + + + 1 + + + 2 + + + + + + + 1 + + + 2 + + + + + + + 1 + + + 1 + + + + + + + + + + + + (Placeholder for the icon) + + + + + + + Distance between the elements in the X direction. Normally, only the X value is necessary; the other two values can give an additional shift in their respective directions. + + + Interval X + + + + + + + + Z + + + + + + + + 0 + 0 + + + + + + + 100.000000000000000 + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + X + + + + + + + Y + + + + + + + + + Reset the distances + + + Reset X + + + + + + + + + + Distance between the elements in the Y direction. Normally, only the Y value is necessary; the other two values can give an additional shift in their respective directions. + + + Interval Y + + + + + + + + X + + + + + + + Y + + + + + + + Z + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + 100.000000000000000 + + + + + + + + 0 + 0 + + + + + + + + + + + + + Reset the distances + + + Reset Y + + + + + + + + + + + + + + Gui::InputField + QLineEdit +
Gui/InputField.h
+
+
+ + input_X_x + input_X_y + input_X_z + button_reset_X + checkbox_fuse + checkbox_link + + + +
diff --git a/src/Mod/Draft/draftguitools/gui_arrays.py b/src/Mod/Draft/draftguitools/gui_arrays.py index c0048c2e78..49a7f096f5 100644 --- a/src/Mod/Draft/draftguitools/gui_arrays.py +++ b/src/Mod/Draft/draftguitools/gui_arrays.py @@ -35,7 +35,7 @@ class ArrayGroupCommand: def GetCommands(self): """Tuple of array commands.""" - return tuple(["Draft_Array", "Draft_LinkArray", + return tuple(["Draft_OrthoArray", "Draft_PolarArray", "Draft_CircularArray", "Draft_PathArray", "Draft_PathLinkArray", "Draft_PointArray"]) diff --git a/src/Mod/Draft/draftguitools/gui_orthoarray.py b/src/Mod/Draft/draftguitools/gui_orthoarray.py new file mode 100644 index 0000000000..b7c0551f3b --- /dev/null +++ b/src/Mod/Draft/draftguitools/gui_orthoarray.py @@ -0,0 +1,142 @@ +"""Provide the Draft OrthoArray tool.""" +## @package gui_orthoarray +# \ingroup DRAFT +# \brief Provide the Draft OrthoArray tool. + +# *************************************************************************** +# * (c) 2020 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD as App +import FreeCADGui as Gui +import Draft +import DraftGui +import Draft_rc +from . import gui_base +from drafttaskpanels import task_orthoarray + + +if App.GuiUp: + from PySide.QtCore import QT_TRANSLATE_NOOP + # import DraftTools + from draftutils.translate import translate + # from DraftGui import displayExternal + from pivy import coin +else: + def QT_TRANSLATE_NOOP(context, text): + return text + + def translate(context, text): + return text + + +def _tr(text): + """Translate the text with the context set.""" + return translate("Draft", text) + + +# So the resource file doesn't trigger errors from code checkers (flake8) +True if Draft_rc.__name__ else False + + +class GuiCommandOrthoArray(gui_base.GuiCommandBase): + """Gui command for the OrthoArray tool.""" + + def __init__(self): + super().__init__() + self.command_name = "OrthoArray" + # self.location = None + self.mouse_event = None + self.view = None + # self.callback_move = None + self.callback_click = None + self.ui = None + self.point = App.Vector() + + def GetResources(self): + """Set icon, menu and tooltip.""" + _msg = ("Creates copies of a selected object, " + "and places the copies in an orthogonal pattern.\n" + "The properties of the array can be further modified after " + "the new object is created, including turning it into " + "a different type of array.") + d = {'Pixmap': 'Draft_Array', + 'MenuText': QT_TRANSLATE_NOOP("Draft", "Array"), + 'ToolTip': QT_TRANSLATE_NOOP("Draft", _msg)} + return d + + def Activated(self): + """Execute this when the command is called. + + We add callbacks that connect the 3D view with + the widgets of the task panel. + """ + # self.location = coin.SoLocation2Event.getClassTypeId() + self.mouse_event = coin.SoMouseButtonEvent.getClassTypeId() + self.view = Draft.get3DView() + # self.callback_move = \ + # self.view.addEventCallbackPivy(self.location, self.move) + self.callback_click = \ + self.view.addEventCallbackPivy(self.mouse_event, self.click) + + self.ui = task_orthoarray.TaskPanelOrthoArray() + # The calling class (this one) is saved in the object + # of the interface, to be able to call a function from within it. + self.ui.source_command = self + # Gui.Control.showDialog(self.ui) + DraftGui.todo.delay(Gui.Control.showDialog, self.ui) + + def click(self, event_cb=None): + """Run callback for when the mouse pointer clicks on the 3D view. + + It should act as if the Enter key was pressed, or the OK button + was pressed in the task panel. + """ + if event_cb: + event = event_cb.getEvent() + if (event.getState() != coin.SoMouseButtonEvent.DOWN + or event.getButton() != coin.SoMouseButtonEvent.BUTTON1): + return + if self.ui and self.point: + # The accept function of the interface + # should call the completed function + # of the calling class (this one). + self.ui.accept() + + def completed(self): + """Run when the command is terminated. + + We should remove the callbacks that were added to the 3D view + and then close the task panel. + """ + # self.view.removeEventCallbackPivy(self.location, + # self.callback_move) + self.view.removeEventCallbackPivy(self.mouse_event, + self.callback_click) + if Gui.Control.activeDialog(): + Gui.Snapper.off() + Gui.Control.closeDialog() + super().finish() + + +if App.GuiUp: + Gui.addCommand('Draft_OrthoArray', GuiCommandOrthoArray()) diff --git a/src/Mod/Draft/draftobjects/orthoarray.py b/src/Mod/Draft/draftobjects/orthoarray.py new file mode 100644 index 0000000000..f8d415f614 --- /dev/null +++ b/src/Mod/Draft/draftobjects/orthoarray.py @@ -0,0 +1,60 @@ +"""Provide the object code for Draft Array.""" +## @package orthoarray +# \ingroup DRAFT +# \brief Provide the object code for Draft Array. + +# *************************************************************************** +# * (c) 2020 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD as App +import Draft + + +def make_ortho_array(obj, + v_x=App.Vector(10, 0, 0), + v_y=App.Vector(0, 10, 0), + v_z=App.Vector(0, 0, 10), + n_x=2, + n_y=2, + n_z=1, + use_link=False): + """Create an orthogonal array from the given object.""" + obj = Draft.makeArray(obj, + arg1=v_x, arg2=v_y, arg3=v_z, + arg4=n_x, arg5=n_y, arg6=n_z, + useLink=use_link) + return obj + + +def make_ortho_array2(obj, + v_x=App.Vector(10, 0, 0), + v_y=App.Vector(0, 10, 0), + n_x=2, + n_y=2, + use_link=False): + """Create a 2D orthogonal array from the given object.""" + obj = Draft.makeArray(obj, + arg1=v_x, arg2=v_y, + arg3=n_x, arg4=n_y, + useLink=use_link) + return obj diff --git a/src/Mod/Draft/drafttaskpanels/task_orthoarray.py b/src/Mod/Draft/drafttaskpanels/task_orthoarray.py new file mode 100644 index 0000000000..170be5e810 --- /dev/null +++ b/src/Mod/Draft/drafttaskpanels/task_orthoarray.py @@ -0,0 +1,347 @@ +"""Provide the task panel for the Draft OrthoArray tool.""" +## @package task_orthoarray +# \ingroup DRAFT +# \brief Provide the task panel for the Draft OrthoArray tool. + +# *************************************************************************** +# * (c) 2020 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD as App +import FreeCADGui as Gui +# import Draft +import Draft_rc +import DraftVecUtils + +import PySide.QtGui as QtGui +from PySide.QtCore import QT_TRANSLATE_NOOP +# import DraftTools +from draftutils.translate import translate +# from DraftGui import displayExternal + +_Quantity = App.Units.Quantity + + +def _Msg(text, end="\n"): + """Print message with newline.""" + App.Console.PrintMessage(text + end) + + +def _Wrn(text, end="\n"): + """Print warning with newline.""" + App.Console.PrintWarning(text + end) + + +def _tr(text): + """Translate with the context set.""" + return translate("Draft", text) + + +# So the resource file doesn't trigger errors from code checkers (flake8) +True if Draft_rc else False + + +class TaskPanelOrthoArray: + """TaskPanel for the OrthoArray command. + + The names of the widgets are defined in the `.ui` file. + In this class all those widgets are automatically created + under the name `self.form.` + + The `.ui` file may use special FreeCAD widgets such as + `Gui::InputField` (based on `QLineEdit`) and + `Gui::QuantitySpinBox` (based on `QAbstractSpinBox`). + See the Doxygen documentation of the corresponding files in `src/Gui/`, + for example, `InputField.h` and `QuantitySpinBox.h`. + """ + + def __init__(self): + ui_file = ":/ui/TaskPanel_OrthoArray.ui" + self.form = Gui.PySideUic.loadUi(ui_file) + self.name = self.form.windowTitle() + + icon_name = "Draft_Array" + svg = ":/icons/" + icon_name + pix = QtGui.QPixmap(svg) + icon = QtGui.QIcon.fromTheme(icon_name, QtGui.QIcon(svg)) + self.form.setWindowIcon(icon) + self.form.label_icon.setPixmap(pix.scaled(32, 32)) + + start_x = _Quantity(100.0, App.Units.Length) + start_y = start_x + start_z = start_x + start_zero = _Quantity(0.0, App.Units.Length) + length_unit = start_x.getUserPreferred()[2] + + self.form.input_X_x.setProperty('rawValue', start_x.Value) + self.form.input_X_x.setProperty('unit', length_unit) + self.form.input_X_y.setProperty('rawValue', start_zero.Value) + self.form.input_X_y.setProperty('unit', length_unit) + self.form.input_X_z.setProperty('rawValue', start_zero.Value) + self.form.input_X_z.setProperty('unit', length_unit) + + self.form.input_Y_x.setProperty('rawValue', start_zero.Value) + self.form.input_Y_x.setProperty('unit', length_unit) + self.form.input_Y_y.setProperty('rawValue', start_y.Value) + self.form.input_Y_y.setProperty('unit', length_unit) + self.form.input_Y_z.setProperty('rawValue', start_zero.Value) + self.form.input_Y_z.setProperty('unit', length_unit) + + self.form.input_Z_x.setProperty('rawValue', start_zero.Value) + self.form.input_Z_x.setProperty('unit', length_unit) + self.form.input_Z_y.setProperty('rawValue', start_zero.Value) + self.form.input_Z_y.setProperty('unit', length_unit) + self.form.input_Z_z.setProperty('rawValue', start_z.Value) + self.form.input_Z_z.setProperty('unit', length_unit) + + self.v_X = App.Vector(100, 0, 0) + self.v_Y = App.Vector(0, 100, 0) + self.v_Z = App.Vector(0, 0, 100) + + # Old style for Qt4, avoid! + # QtCore.QObject.connect(self.form.button_reset, + # QtCore.SIGNAL("clicked()"), + # self.reset_point) + # New style for Qt5 + self.form.button_reset_X.clicked.connect(lambda: self.reset_v("X")) + self.form.button_reset_Y.clicked.connect(lambda: self.reset_v("Y")) + self.form.button_reset_Z.clicked.connect(lambda: self.reset_v("Z")) + + self.n_X = 2 + self.n_Y = 2 + self.n_Z = 1 + + self.form.spinbox_n_X.setValue(self.n_X) + self.form.spinbox_n_Y.setValue(self.n_Y) + self.form.spinbox_n_Z.setValue(self.n_Z) + + self.valid_input = False + + # When the checkbox changes, change the fuse value + self.fuse = False + self.form.checkbox_fuse.stateChanged.connect(self.set_fuse) + + self.use_link = False + self.form.checkbox_link.stateChanged.connect(self.set_link) + + def accept(self): + """Execute when clicking the OK button.""" + selection = Gui.Selection.getSelection() + n_X = self.form.spinbox_n_X.value() + n_Y = self.form.spinbox_n_Y.value() + n_Z = self.form.spinbox_n_Z.value() + self.valid_input = self.validate_input(selection, + n_X, + n_Y, + n_Z) + if self.valid_input: + self.create_object(selection) + self.print_messages(selection) + self.finish() + + def validate_input(self, selection, n_X, n_Y, n_Z): + """Check that the input is valid.""" + if not selection: + _Wrn(_tr("At least one element must be selected")) + return False + if n_X < 1 or n_Y < 1 or n_Z < 1: + _Wrn(_tr("Number of elements must be at least 1")) + return False + # Todo: each of the elements of the selection could be tested, + # not only the first one. + obj = selection[0] + if obj.isDerivedFrom("App::FeaturePython"): + _Wrn(_tr("Selection is not suitable for array")) + _Wrn(_tr("Object:") + " {0} ({1})".format(obj.Label, obj.TypeId)) + return False + return True + + def create_object(self, selection): + """Create the actual object.""" + self.v_X, self.v_Y, self.v_Z = self.set_intervals() + self.n_X, self.n_Y, self.n_Z = self.set_numbers() + + if len(selection) == 1: + sel_obj = selection[0] + else: + # This can be changed so a compound of multiple + # selected objects is produced + sel_obj = selection[0] + + self.fuse = self.form.checkbox_fuse.isChecked() + self.use_link = self.form.checkbox_link.isChecked() + + # This creates the object immediately + # obj = Draft.makeArray(sel_obj, + # self.v_X, self.v_Y, self.v_Z, + # self.n_X, self.n_Y, self.n_Z) + # if obj: + # obj.Fuse = self.fuse + + # Instead, we build the commands to execute through the parent + # of this class, the GuiCommand. + # This is needed to schedule geometry manipulation + # that would crash Coin3D if done in the event callback. + _cmd = "obj = Draft.makeArray(" + _cmd += "FreeCAD.ActiveDocument." + sel_obj.Name + ", " + _cmd += "arg1=" + DraftVecUtils.toString(self.v_X) + ", " + _cmd += "arg2=" + DraftVecUtils.toString(self.v_Y) + ", " + _cmd += "arg3=" + DraftVecUtils.toString(self.v_Z) + ", " + _cmd += "arg4=" + str(self.n_X) + ", " + _cmd += "arg5=" + str(self.n_Y) + ", " + _cmd += "arg6=" + str(self.n_Z) + ", " + _cmd += "useLink=" + str(self.use_link) + _cmd += ")" + + _cmd_list = ["FreeCADGui.addModule('Draft')", + _cmd, + "obj.Fuse = " + str(self.fuse), + "Draft.autogroup(obj)", + "FreeCAD.ActiveDocument.recompute()"] + self.source_command.commit("Ortho array", _cmd_list) + + def set_numbers(self): + """Assign the number of elements.""" + self.n_X = self.form.spinbox_n_X.value() + self.n_Y = self.form.spinbox_n_Y.value() + self.n_Z = self.form.spinbox_n_Z.value() + return self.n_X, self.n_Y, self.n_Z + + def set_intervals(self): + """Assign the interval vectors.""" + v_X_x_str = self.form.input_X_x.text() + v_X_y_str = self.form.input_X_y.text() + v_X_z_str = self.form.input_X_z.text() + self.v_X = App.Vector(_Quantity(v_X_x_str).Value, + _Quantity(v_X_y_str).Value, + _Quantity(v_X_z_str).Value) + + v_Y_x_str = self.form.input_Y_x.text() + v_Y_y_str = self.form.input_Y_y.text() + v_Y_z_str = self.form.input_Y_z.text() + self.v_Y = App.Vector(_Quantity(v_Y_x_str).Value, + _Quantity(v_Y_y_str).Value, + _Quantity(v_Y_z_str).Value) + + v_Z_x_str = self.form.input_X_x.text() + v_Z_y_str = self.form.input_X_y.text() + v_Z_z_str = self.form.input_X_z.text() + self.v_Z = App.Vector(_Quantity(v_Z_x_str).Value, + _Quantity(v_Z_y_str).Value, + _Quantity(v_Z_z_str).Value) + return self.v_X, self.v_Y, self.v_Z + + def reset_v(self, interval): + """Reset the interval to zero distance.""" + if interval == "X": + self.form.input_X_x.setProperty('rawValue', 100) + self.form.input_X_y.setProperty('rawValue', 0) + self.form.input_X_z.setProperty('rawValue', 0) + _Msg(_tr("Interval X reset:") + + " ({0}, {1}, {2})".format(self.v_X.x, + self.v_X.y, + self.v_X.z)) + elif interval == "Y": + self.form.input_Y_x.setProperty('rawValue', 0) + self.form.input_Y_y.setProperty('rawValue', 100) + self.form.input_Y_z.setProperty('rawValue', 0) + _Msg(_tr("Interval Y reset:") + + " ({0}, {1}, {2})".format(self.v_Y.x, + self.v_Y.y, + self.v_Y.z)) + elif interval == "Z": + self.form.input_Z_x.setProperty('rawValue', 0) + self.form.input_Z_y.setProperty('rawValue', 0) + self.form.input_Z_z.setProperty('rawValue', 100) + _Msg(_tr("Interval Z reset:") + + " ({0}, {1}, {2})".format(self.v_Z.x, + self.v_Z.y, + self.v_Z.z)) + + self.n_X, self.n_Y, self.n_Z = self.set_intervals() + + def print_fuse_state(self): + """Print the state translated.""" + if self.fuse: + translated_state = QT_TRANSLATE_NOOP("Draft", "True") + else: + translated_state = QT_TRANSLATE_NOOP("Draft", "False") + _Msg(_tr("Fuse:") + " {}".format(translated_state)) + + def set_fuse(self): + """Run callback when the fuse checkbox changes.""" + self.fuse = self.form.checkbox_fuse.isChecked() + self.print_fuse_state() + + def print_link_state(self): + """Print the state translated.""" + if self.use_link: + translated_state = QT_TRANSLATE_NOOP("Draft", "True") + else: + translated_state = QT_TRANSLATE_NOOP("Draft", "False") + _Msg(_tr("Use Link object:") + " {}".format(translated_state)) + + def set_link(self): + """Run callback when the link checkbox changes.""" + self.use_link = self.form.checkbox_link.isChecked() + self.print_link_state() + + def print_messages(self, selection): + """Print messages about the operation.""" + if len(selection) == 1: + sel_obj = selection[0] + else: + # This can be changed so a compound of multiple + # selected objects is produced + sel_obj = selection[0] + _Msg("{}".format(16*"-")) + _Msg("{}".format(self.name)) + _Msg(_tr("Object:") + " {}".format(sel_obj.Label)) + _Msg(_tr("Number of X elements:") + " {}".format(self.n_X)) + _Msg(_tr("Interval X:") + + " ({0}, {1}, {2})".format(self.v_X.x, + self.v_X.y, + self.v_X.z)) + _Msg(_tr("Number of Y elements:") + " {}".format(self.n_Y)) + _Msg(_tr("Interval Y:") + + " ({0}, {1}, {2})".format(self.v_Y.x, + self.v_Y.y, + self.v_Y.z)) + _Msg(_tr("Number of Z elements:") + " {}".format(self.n_Z)) + _Msg(_tr("Interval Z:") + + " ({0}, {1}, {2})".format(self.v_Z.x, + self.v_Z.y, + self.v_Z.z)) + self.print_fuse_state() + self.print_link_state() + + def reject(self): + """Run when clicking the Cancel button.""" + _Msg(_tr("Aborted:") + " {}".format(self.name)) + self.finish() + + def finish(self): + """Run at the end after OK or Cancel.""" + # App.ActiveDocument.commitTransaction() + Gui.ActiveDocument.resetEdit() + # Runs the parent command to complete the call + self.source_command.completed() diff --git a/src/Mod/Draft/draftviewproviders/view_orthoarray.py b/src/Mod/Draft/draftviewproviders/view_orthoarray.py new file mode 100644 index 0000000000..461475a557 --- /dev/null +++ b/src/Mod/Draft/draftviewproviders/view_orthoarray.py @@ -0,0 +1,43 @@ +"""Provide the view provider code for Draft Array.""" +## @package view_orthoarray +# \ingroup DRAFT +# \brief Provide the view provider code for Draft Array. + +# *************************************************************************** +# * (c) 2020 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import Draft +import Draft_rc +ViewProviderDraftArray = Draft._ViewProviderDraftArray + +# So the resource file doesn't trigger errors from code checkers (flake8) +True if Draft_rc else False + + +class ViewProviderOrthoArray(ViewProviderDraftArray): + + def __init__(self, vobj): + super().__init__(self, vobj) + + def getIcon(self): + return ":/icons/Draft_Array" From 9b7211d02c612186654dd601ec0282e273fc84b2 Mon Sep 17 00:00:00 2001 From: carlopav Date: Sat, 29 Feb 2020 14:34:36 +0100 Subject: [PATCH 10/28] [Draft] Edit bugfix: closed wire check for point lying in the face plane https://forum.freecadweb.org/viewtopic.php?f=23&t=43414&p=372524#p372524 --- src/Mod/Draft/DraftEdit.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Mod/Draft/DraftEdit.py b/src/Mod/Draft/DraftEdit.py index 49ebd89997..80e9a373e4 100644 --- a/src/Mod/Draft/DraftEdit.py +++ b/src/Mod/Draft/DraftEdit.py @@ -2,6 +2,7 @@ #*************************************************************************** #* Copyright (c) 2009, 2010 Yorik van Havre * #* Copyright (c) 2009, 2010 Ken Cline * +#* Copyright (c) 2019, 2020 Carlo Pavan * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -1118,17 +1119,19 @@ class Edit(): return if Draft.getType(obj) in ["BezCurve"]: pts = self.recomputePointsBezier(obj,pts,nodeIndex,v,obj.Degree,moveTrackers=False) - # check that the new point lies on the plane of the wire - import DraftGeomUtils, DraftVecUtils + if obj.Closed: - n = DraftGeomUtils.getNormal(obj.Shape) - dv = editPnt.sub(pts[nodeIndex]) - rn = DraftVecUtils.project(dv,n) - if dv.Length: - editPnt = editPnt.add(rn.negative()) + # check that the new point lies on the plane of the wire + if hasattr(obj.Shape,"normalAt"): + normal = obj.Shape.normalAt(0,0) + point_on_plane = obj.Shape.Vertexes[0].Point + print(v) + v.projectToPlane(point_on_plane, normal) + print(v) + editPnt = obj.getGlobalPlacement().inverse().multVec(v) pts[nodeIndex] = editPnt obj.Points = pts - #self.trackers[obj.Name][nodeIndex].set(v) + self.trackers[obj.Name][nodeIndex].set(v) def recomputePointsBezier(self,obj,pts,idx,v,degree,moveTrackers=True): From 130e16a6fdc6918132549f6e33dcf6cf1ac4dc8c Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 3 Mar 2020 16:46:34 +0100 Subject: [PATCH 11/28] ReverseEngineering: implement mesh segmentation workflow --- src/Mod/Mesh/App/Core/Segmentation.cpp | 38 +++ src/Mod/Mesh/App/Core/Segmentation.h | 5 + src/Mod/ReverseEngineering/Gui/CMakeLists.txt | 4 + src/Mod/ReverseEngineering/Gui/Command.cpp | 91 +++++++ .../ReverseEngineering/Gui/Segmentation.cpp | 254 ++++++++++++++++++ src/Mod/ReverseEngineering/Gui/Segmentation.h | 78 ++++++ .../ReverseEngineering/Gui/Segmentation.ui | 115 ++++++++ src/Mod/ReverseEngineering/Gui/Workbench.cpp | 26 +- 8 files changed, 603 insertions(+), 8 deletions(-) create mode 100644 src/Mod/ReverseEngineering/Gui/Segmentation.cpp create mode 100644 src/Mod/ReverseEngineering/Gui/Segmentation.h create mode 100644 src/Mod/ReverseEngineering/Gui/Segmentation.ui diff --git a/src/Mod/Mesh/App/Core/Segmentation.cpp b/src/Mod/Mesh/App/Core/Segmentation.cpp index c0f693fee5..a77b80fbe3 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.cpp +++ b/src/Mod/Mesh/App/Core/Segmentation.cpp @@ -171,6 +171,21 @@ float PlaneSurfaceFit::GetDistanceToSurface(const Base::Vector3f& pnt) const return fitter->GetDistanceToPlane(pnt); } +Base::Vector3f PlaneSurfaceFit::Project(const Base::Vector3f& pt) const +{ + Base::Vector3f prj(pt); + if (!fitter) { + prj.ProjectToPlane(basepoint, normal); + } + else { + Base::Vector3f base = fitter->GetBase(); + Base::Vector3f norm = fitter->GetNormal(); + prj.ProjectToPlane(base, norm); + } + + return prj; +} + // -------------------------------------------------------- CylinderSurfaceFit::CylinderSurfaceFit() @@ -257,6 +272,12 @@ float CylinderSurfaceFit::GetDistanceToSurface(const Base::Vector3f& pnt) const return (dist - radius); } +Base::Vector3f CylinderSurfaceFit::Project(const Base::Vector3f& pt) const +{ + //TODO + return pt; +} + // -------------------------------------------------------- SphereSurfaceFit::SphereSurfaceFit() @@ -332,6 +353,12 @@ float SphereSurfaceFit::GetDistanceToSurface(const Base::Vector3f& pnt) const return (dist - radius); } +Base::Vector3f SphereSurfaceFit::Project(const Base::Vector3f& pt) const +{ + //TODO + return pt; +} + // -------------------------------------------------------- MeshDistanceGenericSurfaceFitSegment::MeshDistanceGenericSurfaceFitSegment(AbstractSurfaceFit* fit, @@ -383,6 +410,17 @@ void MeshDistanceGenericSurfaceFitSegment::AddFacet(const MeshFacet& face) fitter->AddTriangle(triangle); } +std::vector MeshDistanceGenericSurfaceFitSegment::Project(const std::vector& pts) const +{ + std::vector prj; + prj.reserve(pts.size()); + for (const auto it : pts) { + prj.push_back(fitter->Project(it)); + } + + return prj; +} + // -------------------------------------------------------- bool MeshCurvaturePlanarSegment::TestFacet (const MeshFacet &rclFacet) const diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h index e1fe5d28d8..6b4d16132c 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.h +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -99,6 +99,7 @@ public: virtual bool Done() const = 0; virtual float Fit() = 0; virtual float GetDistanceToSurface(const Base::Vector3f&) const = 0; + virtual Base::Vector3f Project(const Base::Vector3f&) const = 0; }; class MeshExport PlaneSurfaceFit : public AbstractSurfaceFit @@ -114,6 +115,7 @@ public: bool Done() const; float Fit(); float GetDistanceToSurface(const Base::Vector3f&) const; + Base::Vector3f Project(const Base::Vector3f&) const; private: Base::Vector3f basepoint; @@ -134,6 +136,7 @@ public: bool Done() const; float Fit(); float GetDistanceToSurface(const Base::Vector3f&) const; + Base::Vector3f Project(const Base::Vector3f&) const; private: Base::Vector3f basepoint; @@ -155,6 +158,7 @@ public: bool Done() const; float Fit(); float GetDistanceToSurface(const Base::Vector3f&) const; + Base::Vector3f Project(const Base::Vector3f&) const; private: Base::Vector3f center; @@ -173,6 +177,7 @@ public: void Initialize(unsigned long); bool TestInitialFacet(unsigned long) const; void AddFacet(const MeshFacet& rclFacet); + std::vector Project(const std::vector&) const; protected: AbstractSurfaceFit* fitter; diff --git a/src/Mod/ReverseEngineering/Gui/CMakeLists.txt b/src/Mod/ReverseEngineering/Gui/CMakeLists.txt index a8c9948010..fca294202e 100644 --- a/src/Mod/ReverseEngineering/Gui/CMakeLists.txt +++ b/src/Mod/ReverseEngineering/Gui/CMakeLists.txt @@ -31,6 +31,7 @@ endif() set(ReenGui_MOC_HDRS FitBSplineSurface.h Poisson.h + Segmentation.h ) fc_wrap_cpp(ReenGui_MOC_SRCS ${ReenGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${ReenGui_MOC_SRCS}) @@ -38,6 +39,7 @@ SOURCE_GROUP("Moc" FILES ${ReenGui_MOC_SRCS}) set(Dialogs_UIC_SRCS FitBSplineSurface.ui Poisson.ui + Segmentation.ui ) if(BUILD_QT5) @@ -53,6 +55,8 @@ SET(Dialogs_SRCS FitBSplineSurface.h Poisson.cpp Poisson.h + Segmentation.cpp + Segmentation.h ) SOURCE_GROUP("Dialogs" FILES ${Dialogs_SRCS}) diff --git a/src/Mod/ReverseEngineering/Gui/Command.cpp b/src/Mod/ReverseEngineering/Gui/Command.cpp index 43f0f4d1ec..840950e25f 100644 --- a/src/Mod/ReverseEngineering/Gui/Command.cpp +++ b/src/Mod/ReverseEngineering/Gui/Command.cpp @@ -25,6 +25,9 @@ #ifndef _PreComp_ # include # include +# include +# include +# include #endif #include @@ -34,7 +37,9 @@ #include #include #include +#include +#include #include #include #include @@ -47,6 +52,7 @@ #include "../App/ApproxSurface.h" #include "FitBSplineSurface.h" #include "Poisson.h" +#include "Segmentation.h" using namespace std; @@ -186,6 +192,89 @@ bool CmdApproxPlane::isActive(void) return false; } +DEF_STD_CMD_A(CmdSegmentation) + +CmdSegmentation::CmdSegmentation() + : Command("Reen_Segmentation") +{ + sAppModule = "Reen"; + sGroup = QT_TR_NOOP("Reverse Engineering"); + sMenuText = QT_TR_NOOP("Create mesh segments..."); + sToolTipText = QT_TR_NOOP("Create mesh segments"); + sWhatsThis = "Reen_Segmentation"; + sStatusTip = sToolTipText; +} + +void CmdSegmentation::activated(int) +{ + std::vector objs = Gui::Selection().getObjectsOfType(); + Mesh::Feature* mesh = static_cast(objs.front()); + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (!dlg) { + dlg = new ReverseEngineeringGui::TaskSegmentation(mesh); + } + Gui::Control().showDialog(dlg); +} + +bool CmdSegmentation::isActive(void) +{ + if (Gui::Control().activeDialog()) + return false; + return Gui::Selection().countObjectsOfType + (Mesh::Feature::getClassTypeId()) == 1; +} + +DEF_STD_CMD_A(CmdMeshBoundary) + +CmdMeshBoundary::CmdMeshBoundary() + : Command("Reen_MeshBoundary") +{ + sAppModule = "Reen"; + sGroup = QT_TR_NOOP("Reverse Engineering"); + sMenuText = QT_TR_NOOP("Wire from mesh..."); + sToolTipText = QT_TR_NOOP("Create wire from mesh"); + sWhatsThis = "Reen_Segmentation"; + sStatusTip = sToolTipText; +} + +void CmdMeshBoundary::activated(int) +{ + std::vector objs = Gui::Selection().getObjectsOfType(); + App::Document* document = App::GetApplication().getActiveDocument(); + document->openTransaction("Wire from mesh"); + for (auto it : objs) { + const Mesh::MeshObject& mesh = it->Mesh.getValue(); + std::list > bounds; + MeshCore::MeshAlgorithm algo(mesh.getKernel()); + algo.GetMeshBorders(bounds); + + BRep_Builder builder; + TopoDS_Compound compound; + builder.MakeCompound(compound); + + for (auto bt = bounds.begin(); bt != bounds.end(); ++bt) { + BRepBuilderAPI_MakePolygon mkPoly; + for (std::vector::reverse_iterator it = bt->rbegin(); it != bt->rend(); ++it) { + mkPoly.Add(gp_Pnt(it->x,it->y,it->z)); + } + if (mkPoly.IsDone()) { + builder.Add(compound, mkPoly.Wire()); + } + } + + Part::Feature* shapeFea = static_cast(document->addObject("Part::Feature", "Wires from mesh")); + shapeFea->Shape.setValue(compound); + + } + document->commitTransaction(); +} + +bool CmdMeshBoundary::isActive(void) +{ + return Gui::Selection().countObjectsOfType + (Mesh::Feature::getClassTypeId()) > 0; +} + DEF_STD_CMD_A(CmdPoissonReconstruction) CmdPoissonReconstruction::CmdPoissonReconstruction() @@ -277,6 +366,8 @@ void CreateReverseEngineeringCommands(void) Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdApproxSurface()); rcCmdMgr.addCommand(new CmdApproxPlane()); + rcCmdMgr.addCommand(new CmdSegmentation()); + rcCmdMgr.addCommand(new CmdMeshBoundary()); rcCmdMgr.addCommand(new CmdPoissonReconstruction()); rcCmdMgr.addCommand(new CmdViewTriangulation()); } diff --git a/src/Mod/ReverseEngineering/Gui/Segmentation.cpp b/src/Mod/ReverseEngineering/Gui/Segmentation.cpp new file mode 100644 index 0000000000..831f63023d --- /dev/null +++ b/src/Mod/ReverseEngineering/Gui/Segmentation.cpp @@ -0,0 +1,254 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +#endif + +#include "Segmentation.h" +#include "ui_Segmentation.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ReverseEngineeringGui; + +Segmentation::Segmentation(Mesh::Feature* mesh, QWidget* parent, Qt::WindowFlags fl) + : QWidget(parent, fl) + , ui(new Ui_Segmentation) + , myMesh(mesh) +{ + ui->setupUi(this); + ui->numPln->setRange(1, INT_MAX); + ui->numPln->setValue(100); + + ui->checkBoxSmooth->setChecked(false); +} + +Segmentation::~Segmentation() +{ +} + +void Segmentation::accept() +{ + if (myMesh.expired()) + return; + + Gui::WaitCursor wc; + bool createUnused = ui->createUnused->isChecked(); + bool createCompound = ui->createCompound->isChecked(); + BRep_Builder builder; + TopoDS_Compound compound; + builder.MakeCompound(compound); + + const Mesh::MeshObject* mesh = myMesh.get()->Mesh.getValuePtr(); + // make a copy because we might smooth the mesh before + MeshCore::MeshKernel kernel = mesh->getKernel(); + MeshCore::MeshAlgorithm algo(kernel); + + if (ui->checkBoxSmooth->isChecked()) { + MeshCore::LaplaceSmoothing smoother(kernel); + smoother.Smooth(ui->smoothSteps->value()); + } + + MeshCore::MeshSegmentAlgorithm finder(kernel); + MeshCore::MeshCurvature meshCurv(kernel); + meshCurv.ComputePerVertex(); + + std::vector segm; + if (ui->groupBoxPln->isChecked()) { + segm.emplace_back(new MeshCore::MeshCurvaturePlanarSegment + (meshCurv.GetCurvature(), ui->numPln->value(), ui->curvTolPln->value())); + } + finder.FindSegments(segm); + + // For each planar segment compute a plane and use this then for a more accurate 2nd segmentation + std::vector segmSurf; + for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { + const std::vector& data = (*it)->GetSegments(); + for (std::vector::const_iterator jt = data.begin(); jt != data.end(); ++jt) { + std::vector indexes = kernel.GetFacetPoints(*jt); + MeshCore::PlaneFit fit; + fit.AddPoints(kernel.GetPoints(indexes)); + if (fit.Fit() < FLOAT_MAX) { + Base::Vector3f base = fit.GetBase(); + Base::Vector3f axis = fit.GetNormal(); + MeshCore::AbstractSurfaceFit* fitter = new MeshCore::PlaneSurfaceFit(base, axis); + segmSurf.emplace_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment + (fitter, kernel, ui->numPln->value(), ui->distToPln->value())); + } + } + } + finder.FindSegments(segmSurf); + + App::Document* document = App::GetApplication().getActiveDocument(); + document->openTransaction("Segmentation"); + + std::string internalname = "Segments_"; + internalname += myMesh->getNameInDocument(); + + App::DocumentObjectGroup* group = static_cast(document->addObject + ("App::DocumentObjectGroup", internalname.c_str())); + std::string labelname = "Segments "; + labelname += myMesh->Label.getValue(); + group->Label.setValue(labelname); + + std::vector failures; + algo.SetFacetFlag(MeshCore::MeshFacet::TMP0); + + for (std::vector::iterator it = segmSurf.begin(); it != segmSurf.end(); ++it) { + const std::vector& data = (*it)->GetSegments(); + std::shared_ptr genSegm = std::dynamic_pointer_cast + (*it); + + for (std::vector::const_iterator jt = data.begin(); jt != data.end(); ++jt) { + // reset flag for facets of segment + algo.ResetFacetsFlag(*jt, MeshCore::MeshFacet::TMP0); + + Mesh::MeshObject* segment = mesh->meshFromSegment(*jt); + Mesh::Feature* feaSegm = static_cast(group->addObject("Mesh::Feature", "Segment")); + Mesh::MeshObject* feaMesh = feaSegm->Mesh.startEditing(); + feaMesh->swap(*segment); + feaSegm->Mesh.finishEditing(); + delete segment; + + std::stringstream label; + label << feaSegm->Label.getValue() << " (" << (*it)->GetType() << ")"; + feaSegm->Label.setValue(label.str()); + + if (createCompound) { + std::list > bounds; + algo.GetFacetBorders(*jt, bounds); + + std::vector wires; + for (auto bt = bounds.begin(); bt != bounds.end(); ++bt) { + // project the points onto the surface + auto prj = genSegm->Project(*bt); + BRepBuilderAPI_MakePolygon mkPoly; + for (std::vector::reverse_iterator it = prj.rbegin(); it != prj.rend(); ++it) { + mkPoly.Add(gp_Pnt(it->x,it->y,it->z)); + } + if (mkPoly.IsDone()) { + wires.push_back(mkPoly.Wire()); + } + } + + try { + TopoDS_Shape shape = Part::FaceMakerCheese::makeFace(wires); + if (!shape.IsNull()) { + builder.Add(compound, shape); + } + else { + failures.push_back(feaSegm); + Base::Console().Warning("Failed to create face from %s\n", feaSegm->Label.getValue()); + } + } + catch (Standard_Failure&) { + failures.push_back(feaSegm); + Base::Console().Error("Fatal failure to create face from %s\n", feaSegm->Label.getValue()); + } + } + } + } + + if (createUnused) { + // collect all facets that don't have set the flag TMP0 + std::vector unusedFacets; + algo.GetFacetsFlag(unusedFacets, MeshCore::MeshFacet::TMP0); + + if (!unusedFacets.empty()) { + std::unique_ptr segment(mesh->meshFromSegment(unusedFacets)); + Mesh::Feature* feaSegm = static_cast(group->addObject("Mesh::Feature", "Unused")); + Mesh::MeshObject* feaMesh = feaSegm->Mesh.startEditing(); + feaMesh->swap(*segment); + feaSegm->Mesh.finishEditing(); + } + } + if (createCompound) { + Part::Feature* shapeFea = static_cast(group->addObject("Part::Feature", "Compound")); + shapeFea->Shape.setValue(compound); + + // create a sub-group where to move the problematic segments + if (!failures.empty()) { + App::DocumentObjectGroup* subgroup = static_cast(group->addObject + ("App::DocumentObjectGroup", "Failed")); + failures = group->removeObjects(failures); + subgroup->Group.setValues(failures); + } + } + + document->commitTransaction(); +} + +void Segmentation::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + QWidget::changeEvent(e); +} + +// --------------------------------------- + +/* TRANSLATOR MeshGui::TaskRemoveComponents */ + +TaskSegmentation::TaskSegmentation(Mesh::Feature* mesh) +{ + widget = new Segmentation(mesh); + taskbox = new Gui::TaskView::TaskBox( + QPixmap(), widget->windowTitle(), false, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskSegmentation::~TaskSegmentation() +{ + // automatically deleted in the sub-class +} + +bool TaskSegmentation::accept() +{ + widget->accept(); + return true; +} + +#include "moc_Segmentation.cpp" diff --git a/src/Mod/ReverseEngineering/Gui/Segmentation.h b/src/Mod/ReverseEngineering/Gui/Segmentation.h new file mode 100644 index 0000000000..ea9771d2ac --- /dev/null +++ b/src/Mod/ReverseEngineering/Gui/Segmentation.h @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef REVERSEENGINEERINGGUI_SEGMENTATION_H +#define REVERSEENGINEERINGGUI_SEGMENTATION_H + +#include +#include +#include +#include +#include + +// forward declarations +namespace Mesh { class Feature; } + +namespace ReverseEngineeringGui { +class Ui_Segmentation; + +class Segmentation : public QWidget +{ + Q_OBJECT + +public: + Segmentation(Mesh::Feature* mesh, QWidget* parent = 0, Qt::WindowFlags fl = 0); + ~Segmentation(); + void accept(); + +protected: + void changeEvent(QEvent *e); + +private: + std::unique_ptr ui; + App::DocumentObjectWeakPtrT myMesh; +}; + +/** + * Embed the panel into a task dialog. + */ +class TaskSegmentation : public Gui::TaskView::TaskDialog +{ +public: + TaskSegmentation(Mesh::Feature* mesh); + ~TaskSegmentation(); + +public: + bool accept(); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; } + +private: + Segmentation* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} + +#endif // REVERSEENGINEERINGGUI_SEGMENTATION_H diff --git a/src/Mod/ReverseEngineering/Gui/Segmentation.ui b/src/Mod/ReverseEngineering/Gui/Segmentation.ui new file mode 100644 index 0000000000..4c9926b48b --- /dev/null +++ b/src/Mod/ReverseEngineering/Gui/Segmentation.ui @@ -0,0 +1,115 @@ + + + ReverseEngineeringGui::Segmentation + + + + 0 + 0 + 343 + 242 + + + + Mesh segmentation + + + + + + 3 + + + + + + + Create compound + + + + + + + Smooth mesh + + + true + + + + + + + Plane + + + true + + + + + + Curvature tolerance + + + + + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + Distance to plane + + + + + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + Minimum number of faces + + + + + + + 100000 + + + 100 + + + + + + + + + + Create mesh from unused triangles + + + + + + + + diff --git a/src/Mod/ReverseEngineering/Gui/Workbench.cpp b/src/Mod/ReverseEngineering/Gui/Workbench.cpp index a6ac472aaf..d5f5845f59 100644 --- a/src/Mod/ReverseEngineering/Gui/Workbench.cpp +++ b/src/Mod/ReverseEngineering/Gui/Workbench.cpp @@ -50,13 +50,13 @@ Workbench::~Workbench() Gui::MenuItem* Workbench::setupMenuBar() const { - Gui::MenuItem* root = StdWorkbench::setupMenuBar(); - Gui::MenuItem* item = root->findItem("&Windows"); - Gui::MenuItem* reen = new Gui::MenuItem; - root->insertItem(item, reen); - reen->setCommand("&REEN"); - *reen << "Reen_ApproxPlane" - << "Reen_ApproxSurface"; + Gui::MenuItem* root = StdWorkbench::setupMenuBar(); + Gui::MenuItem* item = root->findItem("&Windows"); + Gui::MenuItem* reen = new Gui::MenuItem; + root->insertItem(item, reen); + reen->setCommand("&REEN"); + *reen << "Reen_ApproxPlane" + << "Reen_ApproxSurface"; Gui::MenuItem *reconstruct = new Gui::MenuItem(); reconstruct->setCommand("Surface reconstruction"); @@ -64,7 +64,17 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Reen_ViewTriangulation"; *reen << reconstruct; - return root; + Gui::MenuItem *segm = new Gui::MenuItem(); + segm->setCommand("Segmentation"); + *segm << "Mesh_RemeshGmsh" + << "Mesh_VertexCurvature" + << "Mesh_CurvatureInfo" + << "Separator" + << "Reen_Segmentation" + << "Reen_MeshBoundary"; + *reen << segm; + + return root; } Gui::ToolBarItem* Workbench::setupToolBars() const From 175e7f2069c28e961428be3e6947a977734c5d80 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:23 +0100 Subject: [PATCH 12/28] FEM: Python base constraint view provider, extend methods --- .../ViewProviderFemConstraint.py | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py b/src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py index 348032f690..11ac8ee76e 100644 --- a/src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py +++ b/src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py @@ -47,6 +47,8 @@ class ViewProxy(object): def attach(self, vobj): default = coin.SoGroup() vobj.addDisplayMode(default, "Default") + self.Object = vobj.Object + self.ViewObject = vobj def getDisplayModes(self, obj): "Return a list of display modes." @@ -59,11 +61,27 @@ class ViewProxy(object): def setDisplayMode(self, mode): return mode - def setEdit(self, vobj, mode=0): - # needs to be overwritten if task panel exists - # avoid edit mode by return False - # https://forum.freecadweb.org/viewtopic.php?t=12139&start=10#p161062 - return False + def setEdit(self, vobj, mode=0, TaskPanel=None, hide_mesh=True): + if TaskPanel is None: + # avoid edit mode by return False + # https://forum.freecadweb.org/viewtopic.php?t=12139&start=10#p161062 + return False + if hide_mesh is True: + # hide all FEM meshes and VTK FemPostPipeline objects + for o in vobj.Object.Document.Objects: + if ( + o.isDerivedFrom("Fem::FemMeshObject") + or o.isDerivedFrom("Fem::FemPostPipeline") + ): + o.ViewObject.hide() + # show task panel + task = TaskPanel(vobj.Object) + FreeCADGui.Control.showDialog(task) + return True + + def unsetEdit(self, vobj, mode=0): + FreeCADGui.Control.closeDialog() + return True def doubleClicked(self, vobj): guidoc = FreeCADGui.getDocument(vobj.Object.Document) @@ -77,3 +95,9 @@ class ViewProxy(object): QMessageBox.critical(None, "Error in tree view", message) FreeCAD.Console.PrintError(message + "\n") return True + + def __getstate__(self): + return None + + def __setstate__(self, state): + return None From 6ccc140a1dc764733f0a275b9962ae1f8805e7f4 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:25 +0100 Subject: [PATCH 13/28] FEM: use python base constraint class, constraint self weight --- .../_ViewProviderFemConstraintSelfWeight.py | 44 +------------------ .../femobjects/_FemConstraintSelfWeight.py | 14 +++--- 2 files changed, 10 insertions(+), 48 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintSelfWeight.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintSelfWeight.py index ad13c98de8..2c7e4a75e7 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintSelfWeight.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintSelfWeight.py @@ -28,51 +28,11 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM Constraint SelfWeight ViewProvider -import FreeCAD -import FreeCADGui -import FemGui # needed to display the icons in TreeView - -False if FemGui.__name__ else True # flake8, dummy FemGui usage +from . import ViewProviderFemConstraint -class _ViewProviderFemConstraintSelfWeight: +class _ViewProviderFemConstraintSelfWeight(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemConstraintSelfWeight object" - def __init__(self, vobj): - vobj.Proxy = self def getIcon(self): return ":/icons/fem-constraint-selfweight.svg" - - def attach(self, vobj): - self.ViewObject = vobj - self.Object = vobj.Object - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - - def setEdit(self, vobj, mode=0): - # avoid edit mode by return False - # https://forum.freecadweb.org/viewtopic.php?t=12139&start=10#p161062 - return False - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None diff --git a/src/Mod/Fem/femobjects/_FemConstraintSelfWeight.py b/src/Mod/Fem/femobjects/_FemConstraintSelfWeight.py index b22e843467..d302690a65 100644 --- a/src/Mod/Fem/femobjects/_FemConstraintSelfWeight.py +++ b/src/Mod/Fem/femobjects/_FemConstraintSelfWeight.py @@ -27,10 +27,17 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM constraint self weight object +from . import FemConstraint -class _FemConstraintSelfWeight: + +class _FemConstraintSelfWeight(FemConstraint.Proxy): "The FemConstraintSelfWeight object" + + Type = "Fem::ConstraintSelfWeight" + def __init__(self, obj): + super(_FemConstraintSelfWeight, self).__init__(obj) + obj.addProperty( "App::PropertyFloat", "Gravity_x", @@ -52,8 +59,3 @@ class _FemConstraintSelfWeight: obj.Gravity_x = 0.0 obj.Gravity_y = 0.0 obj.Gravity_z = -1.0 - obj.Proxy = self - self.Type = "Fem::ConstraintSelfWeight" - - def execute(self, obj): - return From d4f60113c6fffe5d3ed188437e5079da6e6c44f0 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:25 +0100 Subject: [PATCH 14/28] FEM: use python base constraint class, material non linear --- ...wProviderFemMaterialMechanicalNonlinear.py | 54 +------------------ .../_FemMaterialMechanicalNonlinear.py | 13 ++--- 2 files changed, 9 insertions(+), 58 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialMechanicalNonlinear.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialMechanicalNonlinear.py index e56539e5d7..7bc328d810 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialMechanicalNonlinear.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialMechanicalNonlinear.py @@ -28,61 +28,11 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _ViewProviderFemMaterialMechanicalNonlinear -import FreeCAD -import FreeCADGui -import FemGui # needed to display the icons in TreeView - -from pivy import coin - -False if FemGui.__name__ else True # flake8, dummy FemGui usage +from . import ViewProviderFemConstraint -class _ViewProviderFemMaterialMechanicalNonlinear: +class _ViewProviderFemMaterialMechanicalNonlinear(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemMaterialMechanicalNonlinear object" - def __init__(self, vobj): - vobj.Proxy = self def getIcon(self): return ":/icons/fem-material-nonlinear.svg" - - def attach(self, vobj): - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def getDefaultDisplayMode(self): - return "Default" - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - - def setEdit(self, vobj, mode=0): - # avoid edit mode by return False - # https://forum.freecadweb.org/viewtopic.php?t=12139&start=10#p161062 - return False - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None diff --git a/src/Mod/Fem/femobjects/_FemMaterialMechanicalNonlinear.py b/src/Mod/Fem/femobjects/_FemMaterialMechanicalNonlinear.py index 7e29c18702..79bc8e73e1 100644 --- a/src/Mod/Fem/femobjects/_FemMaterialMechanicalNonlinear.py +++ b/src/Mod/Fem/femobjects/_FemMaterialMechanicalNonlinear.py @@ -27,12 +27,16 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FEM nonlinear mechanical material object +from . import FemConstraint -class _FemMaterialMechanicalNonlinear: + +class _FemMaterialMechanicalNonlinear(FemConstraint.Proxy): "The FemMaterialMechanicalNonlinear object" + + Type = "Fem::MaterialMechanicalNonlinear" + def __init__(self, obj): - obj.Proxy = self - self.Type = "Fem::MaterialMechanicalNonlinear" + super(_FemMaterialMechanicalNonlinear, self).__init__(obj) obj.addProperty( "App::PropertyLink", @@ -74,6 +78,3 @@ class _FemMaterialMechanicalNonlinear: "Set stress and strain for yield point three, separated by a comma." ) obj.YieldPoint3 = "" - - def execute(self, obj): - return From 0aad1a01649f4b5492b97efed04fe97276da76f6 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:29 +0100 Subject: [PATCH 15/28] FEM: use python base constraint class, constraint tie --- .../_ViewProviderFemConstraintTie.py | 66 +++---------------- src/Mod/Fem/femobjects/_FemConstraintTie.py | 14 ++-- 2 files changed, 16 insertions(+), 64 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintTie.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintTie.py index 7006e83a01..982ee37798 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintTie.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintTie.py @@ -30,76 +30,26 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # for the panel from PySide import QtCore, QtGui from . import FemSelectionWidgets -False if FemGui.__name__ else True # flake8, dummy FemGui usage - -class _ViewProviderFemConstraintTie: +class _ViewProviderFemConstraintTie(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemConstraintTie object" - def __init__(self, vobj): - vobj.Proxy = self - def getIcon(self): return ":/icons/fem-constraint-tie.svg" - def attach(self, vobj): - from pivy import coin - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def getDefaultDisplayMode(self): - return "Default" - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - def setEdit(self, vobj, mode=0): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemConstraintTie(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemConstraintTie + ) class _TaskPanelFemConstraintTie: diff --git a/src/Mod/Fem/femobjects/_FemConstraintTie.py b/src/Mod/Fem/femobjects/_FemConstraintTie.py index 820b966852..e785dd8382 100644 --- a/src/Mod/Fem/femobjects/_FemConstraintTie.py +++ b/src/Mod/Fem/femobjects/_FemConstraintTie.py @@ -27,18 +27,20 @@ __url__ = "https://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM constraint tie object +from . import FemConstraint -class _FemConstraintTie: + +class _FemConstraintTie(FemConstraint.Proxy): "The FemConstraintTie object" + + Type = "Fem::ConstraintTie" + def __init__(self, obj): + super(_FemConstraintTie, self).__init__(obj) + obj.addProperty( "App::PropertyLength", "Tolerance", "Geometry", "set max gap between tied faces" ) - obj.Proxy = self - self.Type = "Fem::ConstraintTie" - - def execute(self, obj): - return From a00dddffe75f046f8f77c2606f8bcfd6448ed43f Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:31 +0100 Subject: [PATCH 16/28] FEM: use python base constraint class, shell thickness --- .../_ViewProviderFemElementGeometry2D.py | 67 +++---------------- .../Fem/femobjects/_FemElementGeometry2D.py | 14 ++-- 2 files changed, 17 insertions(+), 64 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py index e84ab93fcb..d289ded278 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py @@ -30,76 +30,27 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView + +from . import ViewProviderFemConstraint # for the panel from PySide import QtCore from . import FemSelectionWidgets -False if FemGui.__name__ else True # flake8, dummy FemGui usage - -class _ViewProviderFemElementGeometry2D: +class _ViewProviderFemElementGeometry2D(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemElementGeometry2D object" - def __init__(self, vobj): - vobj.Proxy = self - def getIcon(self): return ":/icons/fem-element-geometry-2d.svg" - def attach(self, vobj): - from pivy import coin - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def getDefaultDisplayMode(self): - return "Default" - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - def setEdit(self, vobj, mode=0): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemElementGeometry2D(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemElementGeometry2D + ) class _TaskPanelFemElementGeometry2D: diff --git a/src/Mod/Fem/femobjects/_FemElementGeometry2D.py b/src/Mod/Fem/femobjects/_FemElementGeometry2D.py index 70edbbaf8b..ee677cb60d 100644 --- a/src/Mod/Fem/femobjects/_FemElementGeometry2D.py +++ b/src/Mod/Fem/femobjects/_FemElementGeometry2D.py @@ -27,10 +27,17 @@ __url__ = "https://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM element geometry 2D object +from . import FemConstraint -class _FemElementGeometry2D: + +class _FemElementGeometry2D(FemConstraint.Proxy): "The FemElementGeometry2D object" + + Type = "Fem::ElementGeometry2D" + def __init__(self, obj): + super(_FemElementGeometry2D, self).__init__(obj) + obj.addProperty( "App::PropertyLength", "Thickness", @@ -43,8 +50,3 @@ class _FemElementGeometry2D: "ShellThickness", "List of shell thickness shapes" ) - obj.Proxy = self - self.Type = "Fem::ElementGeometry2D" - - def execute(self, obj): - return From ab2c0a39d7259a8992d831aedc581113cafd41ea Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:33 +0100 Subject: [PATCH 17/28] FEM: use python base constraint class, beam section --- .../_ViewProviderFemElementGeometry1D.py | 66 +++---------------- .../Fem/femobjects/_FemElementGeometry1D.py | 11 ++-- 2 files changed, 13 insertions(+), 64 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py index 2ead71f9b2..025956c32f 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py @@ -30,77 +30,27 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # for the panel from femobjects import _FemElementGeometry1D from PySide import QtCore from . import FemSelectionWidgets -False if FemGui.__name__ else True # flake8, dummy FemGui usage - -class _ViewProviderFemElementGeometry1D: +class _ViewProviderFemElementGeometry1D(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemElementGeometry1D object" - def __init__(self, vobj): - vobj.Proxy = self - def getIcon(self): return ":/icons/fem-element-geometry-1d.svg" - def attach(self, vobj): - from pivy import coin - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def getDefaultDisplayMode(self): - return "Default" - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - def setEdit(self, vobj, mode=0): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemElementGeometry1D(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemElementGeometry1D + ) class _TaskPanelFemElementGeometry1D: diff --git a/src/Mod/Fem/femobjects/_FemElementGeometry1D.py b/src/Mod/Fem/femobjects/_FemElementGeometry1D.py index 15ae40352b..480c912774 100644 --- a/src/Mod/Fem/femobjects/_FemElementGeometry1D.py +++ b/src/Mod/Fem/femobjects/_FemElementGeometry1D.py @@ -27,13 +27,17 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM element geometry 1D object +from . import FemConstraint -class _FemElementGeometry1D: + +class _FemElementGeometry1D(FemConstraint.Proxy): "The FemElementGeometry1D object" + Type = "Fem::ElementGeometry1D" known_beam_types = ["Rectangular", "Circular", "Pipe"] def __init__(self, obj): + super(_FemElementGeometry1D, self).__init__(obj) obj.addProperty( "App::PropertyLength", "RectWidth", @@ -78,8 +82,3 @@ class _FemElementGeometry1D: ) obj.SectionType = _FemElementGeometry1D.known_beam_types obj.SectionType = "Rectangular" - obj.Proxy = self - self.Type = "Fem::ElementGeometry1D" - - def execute(self, obj): - return From 974ab58b9bdcf23221e01ba62cf5f4aa137d1eae Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:35 +0100 Subject: [PATCH 18/28] FEM: use python base constraint class, fluid section --- .../_ViewProviderFemElementFluid1D.py | 66 +++---------------- src/Mod/Fem/femobjects/_FemElementFluid1D.py | 11 ++-- 2 files changed, 13 insertions(+), 64 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py index c3cfd2e8ef..53ad586ee0 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py @@ -32,7 +32,7 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # for the panel from femobjects import _FemElementFluid1D @@ -40,70 +40,20 @@ from PySide import QtCore from PySide import QtGui from . import FemSelectionWidgets -False if FemGui.__name__ else True # flake8, dummy FemGui usage - -class _ViewProviderFemElementFluid1D: +class _ViewProviderFemElementFluid1D(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemElementFluid1D object" - def __init__(self, vobj): - vobj.Proxy = self - def getIcon(self): return ":/icons/fem-element-fluid-1d.svg" - def attach(self, vobj): - from pivy import coin - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def getDefaultDisplayMode(self): - return "Default" - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - def setEdit(self, vobj, mode=0): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemElementFluid1D(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemElementFluid1D + ) class _TaskPanelFemElementFluid1D: diff --git a/src/Mod/Fem/femobjects/_FemElementFluid1D.py b/src/Mod/Fem/femobjects/_FemElementFluid1D.py index 1c161332c7..44a030ce6d 100644 --- a/src/Mod/Fem/femobjects/_FemElementFluid1D.py +++ b/src/Mod/Fem/femobjects/_FemElementFluid1D.py @@ -28,10 +28,13 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _FemElementFluid1D +from . import FemConstraint -class _FemElementFluid1D: + +class _FemElementFluid1D(FemConstraint.Proxy): "The FemElementFluid1D object" + Type = "Fem::ElementFluid1D" known_fluid_types = ["Liquid"] # "Gas", "Open Channel" are not implemented in ccx writer # known_fluid_types = ["Liquid", "Gas", "Open Channel"] @@ -52,6 +55,7 @@ class _FemElementFluid1D: known_channel_types = ["NONE"] def __init__(self, obj): + super(_FemElementFluid1D, self).__init__(obj) obj.addProperty( "App::PropertyLinkSubList", "References", @@ -309,8 +313,3 @@ class _FemElementFluid1D: obj.OutletPressureActive = True obj.InletFlowRateActive = False obj.OutletFlowRateActive = False - obj.Proxy = self - self.Type = "Fem::ElementFluid1D" - - def execute(self, obj): - return From 83880da9218b86fac1eaac125a7141b3190dd17d Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:37 +0100 Subject: [PATCH 19/28] FEM: use python base constraint class, beam rotation --- .../_ViewProviderFemElementRotation1D.py | 70 +++---------------- .../Fem/femobjects/_FemElementRotation1D.py | 12 ++-- 2 files changed, 14 insertions(+), 68 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py index 4e8dbe422a..dba68203da 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py @@ -30,84 +30,30 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # for the panel from PySide import QtCore from . import FemSelectionWidgets -False if FemGui.__name__ else True # flake8, dummy FemGui usage - -class _ViewProviderFemElementRotation1D: +class _ViewProviderFemElementRotation1D(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemElementRotation1D object" - def __init__(self, vobj): - vobj.Proxy = self def getIcon(self): return ":/icons/fem-element-rotation-1d.svg" - def attach(self, vobj): - from pivy import coin - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def getDefaultDisplayMode(self): - return "Default" - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - """ # do not activate the task panel, since rotation with reference shapes is not yet supported def setEdit(self, vobj, mode=0): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemElementRotation1D(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemElementRotation1D + ) """ - def setEdit(self, vobj, mode=0): - # avoid edit mode by return False - # https://forum.freecadweb.org/viewtopic.php?t=12139&start=10#p161062 - return False - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None - class _TaskPanelFemElementRotation1D: """The TaskPanel for editing References property of FemElementRotation1D objects""" diff --git a/src/Mod/Fem/femobjects/_FemElementRotation1D.py b/src/Mod/Fem/femobjects/_FemElementRotation1D.py index a62cec292a..19c18855a3 100644 --- a/src/Mod/Fem/femobjects/_FemElementRotation1D.py +++ b/src/Mod/Fem/femobjects/_FemElementRotation1D.py @@ -27,11 +27,16 @@ __url__ = "https://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM element rotation 1D object +from . import FemConstraint -class _FemElementRotation1D: + +class _FemElementRotation1D(FemConstraint.Proxy): "The FemElementRotation1D object" + Type = "Fem::ElementRotation1D" + def __init__(self, obj): + super(_FemElementRotation1D, self).__init__(obj) obj.addProperty( "App::PropertyAngle", "Rotation", @@ -44,8 +49,3 @@ class _FemElementRotation1D: "BeamRotation", "List of beam rotation shapes" ) - obj.Proxy = self - self.Type = "Fem::ElementRotation1D" - - def execute(self, obj): - return From 659da19739268cac49a45d0d96a7785ab0da00d9 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:39 +0100 Subject: [PATCH 20/28] FEM: use python base constraint class, material reinforced --- .../_ViewProviderFemMaterialReinforced.py | 68 +++---------------- .../Fem/femobjects/_FemMaterialReinforced.py | 13 ++-- 2 files changed, 15 insertions(+), 66 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py index a3555d6a5b..4b99cdbed5 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py @@ -29,7 +29,7 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # task panel @@ -38,76 +38,24 @@ from PySide import QtCore from PySide import QtGui import sys -False if False else FemGui.__name__ # flake8, dummy FemGui usage, returns "FemGui" if sys.version_info.major >= 3: unicode = str -class _ViewProviderFemMaterialReinforced: +class _ViewProviderFemMaterialReinforced(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemMaterialReinfocement object" - def __init__(self, vobj): - vobj.Proxy = self def getIcon(self): return ":/icons/fem-material-reinforced.svg" - def attach(self, vobj): - from pivy import coin - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - def setEdit(self, vobj, mode=0): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemMaterialReinforced(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = ( - "Active Task Dialog found! " - "Please close this one before opening a new one!" - ) - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemMaterialReinforced + ) class _TaskPanelFemMaterialReinforced: diff --git a/src/Mod/Fem/femobjects/_FemMaterialReinforced.py b/src/Mod/Fem/femobjects/_FemMaterialReinforced.py index aa8d56cad8..5e8e0feeaa 100644 --- a/src/Mod/Fem/femobjects/_FemMaterialReinforced.py +++ b/src/Mod/Fem/femobjects/_FemMaterialReinforced.py @@ -27,10 +27,16 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _FemMaterialReinforced +from . import FemConstraint -class _FemMaterialReinforced: + +class _FemMaterialReinforced(FemConstraint.Proxy): "The FemMaterialReinforced object" + + Type = "Fem::MaterialReinforced" + def __init__(self, obj): + super(_FemMaterialReinforced, self).__init__(obj) obj.addProperty( "App::PropertyLinkSubList", "References", @@ -51,8 +57,3 @@ class _FemMaterialReinforced: ) obj.Category = ["Solid"] obj.Category = "Solid" - obj.Proxy = self - self.Type = "Fem::MaterialReinforced" - - def execute(self, obj): - return From 5ea922c8b519f80d20d433a6adec91d28a8af265 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:41 +0100 Subject: [PATCH 21/28] FEM: use python base constraint class, material obj --- .../femguiobjects/_ViewProviderFemMaterial.py | 60 +++---------------- src/Mod/Fem/femobjects/_FemMaterial.py | 13 ++-- 2 files changed, 16 insertions(+), 57 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py index 8ee7910c9c..ea27cd51e6 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py @@ -30,7 +30,7 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # for the panel from FreeCAD import Units @@ -39,66 +39,24 @@ from PySide import QtCore from PySide import QtGui import sys -False if FemGui.__name__ else True # flake8, dummy FemGui usage if sys.version_info.major >= 3: unicode = str -class _ViewProviderFemMaterial: +class _ViewProviderFemMaterial(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemMaterial object" - def __init__(self, vobj): - vobj.Proxy = self - def getIcon(self): return ":/icons/fem-material.svg" - def attach(self, vobj): - self.ViewObject = vobj - self.Object = vobj.Object - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - - def setEdit(self, vobj, mode): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemMaterial(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode): - FreeCADGui.Control.closeDialog() - return True - - # overwrite the doubleClicked of material object python to make sure no other Material taskd - # (and thus no selection observer) is still active - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + def setEdit(self, vobj, mode=0): + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemMaterial + ) class _TaskPanelFemMaterial: diff --git a/src/Mod/Fem/femobjects/_FemMaterial.py b/src/Mod/Fem/femobjects/_FemMaterial.py index eb661163f0..16fe442e08 100644 --- a/src/Mod/Fem/femobjects/_FemMaterial.py +++ b/src/Mod/Fem/femobjects/_FemMaterial.py @@ -27,10 +27,16 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FEM material +from . import FemConstraint -class _FemMaterial: + +class _FemMaterial(FemConstraint.Proxy): "The FEM Material object" + + Type = "Fem::Material" + def __init__(self, obj): + super(_FemMaterial, self).__init__(obj) obj.addProperty( "App::PropertyLinkSubList", "References", @@ -44,8 +50,3 @@ class _FemMaterial: "Material type: fluid or solid" ) obj.Category = ["Solid", "Fluid"] # used in TaskPanel - obj.Proxy = self - self.Type = "Fem::Material" - - def execute(self, obj): - return From 85712261bc27aa140cec7f9e353189f648e58639 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:43 +0100 Subject: [PATCH 22/28] FEM: use python base constraint class, mesh boundary layer --- .../_ViewProviderFemMeshBoundaryLayer.py | 66 +++---------------- src/Mod/Fem/femobjects/FemConstraint.py | 2 +- .../Fem/femobjects/_FemMeshBoundaryLayer.py | 21 ++---- 3 files changed, 16 insertions(+), 73 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py index 50a020305e..115597236f 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py @@ -30,76 +30,26 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # for the panel from PySide import QtCore from . import FemSelectionWidgets -False if FemGui.__name__ else True # flake8, dummy FemGui usage - -class _ViewProviderFemMeshBoundaryLayer: +class _ViewProviderFemMeshBoundaryLayer(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemMeshBoundaryLayer object" - def __init__(self, vobj): - vobj.Proxy = self - def getIcon(self): return ":/icons/fem-femmesh-boundary-layer.svg" - def attach(self, vobj): - from pivy import coin - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def getDefaultDisplayMode(self): - return "Default" - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - def setEdit(self, vobj, mode=0): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemMeshBoundaryLayer(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemMeshBoundaryLayer + ) class _TaskPanelFemMeshBoundaryLayer: diff --git a/src/Mod/Fem/femobjects/FemConstraint.py b/src/Mod/Fem/femobjects/FemConstraint.py index 70e98fc907..3adc69d944 100644 --- a/src/Mod/Fem/femobjects/FemConstraint.py +++ b/src/Mod/Fem/femobjects/FemConstraint.py @@ -32,6 +32,6 @@ class Proxy(object): BaseType = "Fem::ConstraintPython" def __init__(self, obj): - obj.Proxy = self + obj.Proxy = self # link between App::DocumentObject to this object ## @} diff --git a/src/Mod/Fem/femobjects/_FemMeshBoundaryLayer.py b/src/Mod/Fem/femobjects/_FemMeshBoundaryLayer.py index 55e4bdcce1..b9eaa39568 100644 --- a/src/Mod/Fem/femobjects/_FemMeshBoundaryLayer.py +++ b/src/Mod/Fem/femobjects/_FemMeshBoundaryLayer.py @@ -27,13 +27,16 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FEM mesh boundary layer object +from . import FemConstraint -class _FemMeshBoundaryLayer: + +class _FemMeshBoundaryLayer(FemConstraint.Proxy): "The FemMeshBoundaryLayer object" + + Type = "Fem::FemMeshBoundaryLayer" + def __init__(self, obj): - self.Type = "Fem::FemMeshBoundaryLayer" - self.Object = obj # keep a ref to the DocObj for nonGui usage - obj.Proxy = self # link between App::DocumentObject to this object + super(_FemMeshBoundaryLayer, self).__init__(obj) obj.addProperty( "App::PropertyInteger", @@ -67,13 +70,3 @@ class _FemMeshBoundaryLayer: "MeshBoundaryLayerShapes", "List of FEM mesh region shapes" ) - - def execute(self, obj): - return - - def __getstate__(self): - return self.Type - - def __setstate__(self, state): - if state: - self.Type = state From 0e029666e3f87ad32da76ab3732a5285b9fd2676 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:45 +0100 Subject: [PATCH 23/28] FEM: use python base constraint class, mesh group --- .../_ViewProviderFemMeshGroup.py | 65 +++---------------- src/Mod/Fem/femobjects/_FemMeshGroup.py | 13 ++-- 2 files changed, 15 insertions(+), 63 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py index 7200073cfa..6a1f6ba055 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py @@ -30,75 +30,26 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # for the panel from PySide import QtCore from . import FemSelectionWidgets -False if FemGui.__name__ else True # flake8, dummy FemGui usage - -class _ViewProviderFemMeshGroup: +class _ViewProviderFemMeshGroup(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemMeshGroup object" - def __init__(self, vobj): - vobj.Proxy = self def getIcon(self): return ":/icons/fem-femmesh-from-shape.svg" - def attach(self, vobj): - from pivy import coin - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def getDefaultDisplayMode(self): - return "Default" - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - def setEdit(self, vobj, mode=0): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemMeshGroup(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemMeshGroup + ) class _TaskPanelFemMeshGroup: diff --git a/src/Mod/Fem/femobjects/_FemMeshGroup.py b/src/Mod/Fem/femobjects/_FemMeshGroup.py index 7e3fe3012c..cf2954ca9d 100644 --- a/src/Mod/Fem/femobjects/_FemMeshGroup.py +++ b/src/Mod/Fem/femobjects/_FemMeshGroup.py @@ -27,10 +27,16 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _FemMeshGroup +from . import FemConstraint -class _FemMeshGroup: + +class _FemMeshGroup(FemConstraint.Proxy): "The FemMeshGroup object" + + Type = "Fem::FemMeshGroup" + def __init__(self, obj): + super(_FemMeshGroup, self).__init__(obj) obj.addProperty( "App::PropertyBool", "UseLabel", @@ -43,8 +49,3 @@ class _FemMeshGroup: "MeshGroupShapes", "List of FEM mesh group shapes" ) - obj.Proxy = self - self.Type = "Fem::FemMeshGroup" - - def execute(self, obj): - return From 95a411d95aa840670c34abdc0bcea014414ad5a3 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:47 +0100 Subject: [PATCH 24/28] FEM: use python base constraint class, mesh region --- .../_ViewProviderFemMeshRegion.py | 66 +++---------------- src/Mod/Fem/femobjects/_FemMeshRegion.py | 13 ++-- 2 files changed, 15 insertions(+), 64 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py index 9e4995dad0..14a355dc56 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py @@ -30,76 +30,26 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # for the panel from PySide import QtCore from . import FemSelectionWidgets -False if FemGui.__name__ else True # flake8, dummy FemGui usage - -class _ViewProviderFemMeshRegion: +class _ViewProviderFemMeshRegion(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemMeshRegion object" - def __init__(self, vobj): - vobj.Proxy = self - def getIcon(self): return ":/icons/fem-femmesh-region.svg" - def attach(self, vobj): - from pivy import coin - self.ViewObject = vobj - self.Object = vobj.Object - self.standard = coin.SoGroup() - vobj.addDisplayMode(self.standard, "Default") - - def getDisplayModes(self, obj): - return ["Default"] - - def getDefaultDisplayMode(self): - return "Default" - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - def setEdit(self, vobj, mode=0): - # hide all meshes - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject"): - o.ViewObject.hide() - # show task panel - taskd = _TaskPanelFemMeshRegion(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemMeshRegion + ) class _TaskPanelFemMeshRegion: diff --git a/src/Mod/Fem/femobjects/_FemMeshRegion.py b/src/Mod/Fem/femobjects/_FemMeshRegion.py index 639cefe874..13c489ffbf 100644 --- a/src/Mod/Fem/femobjects/_FemMeshRegion.py +++ b/src/Mod/Fem/femobjects/_FemMeshRegion.py @@ -27,10 +27,16 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _FemMeshRegion +from . import FemConstraint -class _FemMeshRegion: + +class _FemMeshRegion(FemConstraint.Proxy): "The FemMeshRegion object" + + Type = "Fem::FemMeshRegion" + def __init__(self, obj): + super(_FemMeshRegion, self).__init__(obj) obj.addProperty( "App::PropertyLength", "CharacteristicLength", @@ -43,8 +49,3 @@ class _FemMeshRegion: "MeshRegionShapes", "List of FEM mesh region shapes" ) - obj.Proxy = self - self.Type = "Fem::FemMeshRegion" - - def execute(self, obj): - return From 36118fb59e93e8deb9af8382e837c0bb8671ecbf Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:49 +0100 Subject: [PATCH 25/28] FEM: use python base constraint class, result mechanical --- .../_ViewProviderFemResultMechanical.py | 60 +++---------------- .../Fem/femobjects/_FemResultMechanical.py | 11 ++-- 2 files changed, 16 insertions(+), 55 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py index ee1d88b0ed..b5cf9527c4 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py @@ -30,7 +30,7 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui # needed to display the icons in TreeView +from . import ViewProviderFemConstraint # for the panel import femresult.resulttools as resulttools @@ -42,70 +42,28 @@ import numpy as np import matplotlib.pyplot as plt -False if FemGui.__name__ else True # flake8, dummy FemGui usage - - -class _ViewProviderFemResultMechanical: +class _ViewProviderFemResultMechanical(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemResultObject Python derived FemResult class" - def __init__(self, vobj): - vobj.Proxy = self - def getIcon(self): """after load from FCStd file, self.icon does not exist, return constant path instead""" return ":/icons/fem-post-result-show.svg" - def attach(self, vobj): - self.ViewObject = vobj - self.Object = vobj.Object - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - - def doubleClicked(self, vobj): - guidoc = FreeCADGui.getDocument(vobj.Object.Document) - # check if another VP is in edit mode - # https://forum.freecadweb.org/viewtopic.php?t=13077#p104702 - if not guidoc.getInEdit(): - guidoc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - def setEdit(self, vobj, mode=0): - if hasattr(self.Object, "Mesh") and self.Object.Mesh: - hide_femmeshes_postpiplines() - # only show the FEM result mesh - self.Object.Mesh.ViewObject.show() - taskd = _TaskPanelFemResultShow(self.Object) - taskd.obj = vobj.Object - FreeCADGui.Control.showDialog(taskd) - return True - else: - error_message = "FEM: Result object has no appropriate FEM mesh.\n" - FreeCAD.Console.PrintError(error_message) - from PySide import QtGui - QtGui.QMessageBox.critical(None, "No result object", error_message) - return False + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemResultShow, + ) + # overwrite unsetEdit, because the mesh result obj needs to be hided on task panel exit def unsetEdit(self, vobj, mode=0): FreeCADGui.Control.closeDialog() # hide the mesh after result viewing is finished, but do not reset the coloring self.Object.Mesh.ViewObject.hide() return True - def __getstate__(self): - return None - - def __setstate__(self, state): - return None - def claimChildren(self): return [self.Object.Mesh] # claimChildren needs to return a list ! diff --git a/src/Mod/Fem/femobjects/_FemResultMechanical.py b/src/Mod/Fem/femobjects/_FemResultMechanical.py index ddfbc3b36d..d42e7b34a5 100644 --- a/src/Mod/Fem/femobjects/_FemResultMechanical.py +++ b/src/Mod/Fem/femobjects/_FemResultMechanical.py @@ -27,14 +27,17 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD DocumentObject class to hold mechanical results in FEM workbench +from . import FemConstraint -class _FemResultMechanical(): + +class _FemResultMechanical(FemConstraint.Proxy): """The Fem::_FemResultMechanical's Proxy python type, add result specific properties """ + + Type = "Fem::FemResultMechanical" + def __init__(self, obj): - self.Type = "Fem::FemResultMechanical" - self.Object = obj # keep a ref to the DocObj for nonGui usage - obj.Proxy = self # link between App::DocumentObject to this object + super(_FemResultMechanical, self).__init__(obj) obj.addProperty( "App::PropertyString", From 62fa28fc639f151bd85e20cd4a7965cbc316473d Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:51 +0100 Subject: [PATCH 26/28] FEM: use python base constraint class, mesh result mesh --- .../_ViewProviderFemMeshResult.py | 22 +++---------------- src/Mod/Fem/femobjects/_FemMeshResult.py | 20 +++++------------ 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py index c86c76711c..68a857303b 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py @@ -28,27 +28,11 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _ViewProviderFemMeshResult +from . import ViewProviderFemConstraint -class _ViewProviderFemMeshResult: + +class _ViewProviderFemMeshResult(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemMeshResult object" - def __init__(self, vobj): - vobj.Proxy = self def getIcon(self): return ":/icons/fem-femmesh-result.svg" - - def attach(self, vobj): - self.ViewObject = vobj - self.Object = vobj.Object - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None diff --git a/src/Mod/Fem/femobjects/_FemMeshResult.py b/src/Mod/Fem/femobjects/_FemMeshResult.py index 192da0d98d..248cecea0e 100644 --- a/src/Mod/Fem/femobjects/_FemMeshResult.py +++ b/src/Mod/Fem/femobjects/_FemMeshResult.py @@ -27,22 +27,14 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _FemMeshResult +from . import FemConstraint -class _FemMeshResult(): + +class _FemMeshResult(FemConstraint.Proxy): """The Fem::FemMeshObject's Proxy python type, add Result specific object type """ + Type = "Fem::FemMeshResult" + def __init__(self, obj): - self.Type = "Fem::FemMeshResult" - self.Object = obj # keep a ref to the DocObj for nonGui usage - obj.Proxy = self # link between App::DocumentObject to this object - - def execute(self, obj): - return - - def __getstate__(self): - return self.Type - - def __setstate__(self, state): - if state: - self.Type = state + super(_FemMeshResult, self).__init__(obj) From 65b5cb7f386db3996bd7fca957de2f49e9f629d7 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:54 +0100 Subject: [PATCH 27/28] FEM: use python base constraint class, solver calculix --- .../_ViewProviderFemSolverCalculix.py | 48 ++++--------------- src/Mod/Fem/femobjects/_FemSolverCalculix.py | 21 +++----- 2 files changed, 16 insertions(+), 53 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py index 9d96719da5..f40238bd5a 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py @@ -30,7 +30,7 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -import FemGui +from . import ViewProviderFemConstraint # for the panel from PySide import QtCore @@ -45,50 +45,20 @@ if sys.version_info.major >= 3: return str(text) -class _ViewProviderFemSolverCalculix: +class _ViewProviderFemSolverCalculix(ViewProviderFemConstraint.ViewProxy): "A View Provider for the FemSolverCalculix object" - def __init__(self, vobj): - vobj.Proxy = self - def getIcon(self): return ":/icons/fem-solver-standard.svg" - def attach(self, vobj): - self.ViewObject = vobj - self.Object = vobj.Object - - def updateData(self, obj, prop): - return - - def onChanged(self, vobj, prop): - return - def setEdit(self, vobj, mode=0): - taskd = _TaskPanelFemSolverCalculix(self.Object) - FreeCADGui.Control.showDialog(taskd) - return True - - def unsetEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - return True - - def doubleClicked(self, vobj): - doc = FreeCADGui.getDocument(vobj.Object.Document) - if not doc.getInEdit(): - doc.setEdit(vobj.Object.Name) - else: - from PySide.QtGui import QMessageBox - message = "Active Task Dialog found! Please close this one before opening a new one!" - QMessageBox.critical(None, "Error in tree view", message) - FreeCAD.Console.PrintError(message + "\n") - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + ViewProviderFemConstraint.ViewProxy.setEdit( + self, + vobj, + mode, + _TaskPanelFemSolverCalculix, + hide_mesh=False + ) class _TaskPanelFemSolverCalculix: diff --git a/src/Mod/Fem/femobjects/_FemSolverCalculix.py b/src/Mod/Fem/femobjects/_FemSolverCalculix.py index 999d1b56d6..cca0264e76 100644 --- a/src/Mod/Fem/femobjects/_FemSolverCalculix.py +++ b/src/Mod/Fem/femobjects/_FemSolverCalculix.py @@ -30,14 +30,17 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from femsolver.calculix.solver import ANALYSIS_TYPES +from . import FemConstraint -class _FemSolverCalculix(): + +class _FemSolverCalculix(FemConstraint.Proxy): """The Fem::FemSolver's Proxy python type, add solver specific properties """ + + Type = "Fem::FemSolverCalculixCcxTools" + def __init__(self, obj): - self.Type = "Fem::FemSolverCalculixCcxTools" - self.Object = obj # keep a ref to the DocObj for nonGui usage - obj.Proxy = self # link between App::DocumentObject to this object + super(_FemSolverCalculix, self).__init__(obj) # not needed ATM # fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") @@ -273,13 +276,3 @@ class _FemSolverCalculix(): ) dimout = ccx_prefs.GetBool("BeamShellOutput", False) obj.BeamShellResultOutput3D = dimout - - def execute(self, obj): - return - - def __getstate__(self): - return self.Type - - def __setstate__(self, state): - if state: - self.Type = state From 9c0d0e94c60a8f93c70231fd793ac5a99fe6a914 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 3 Mar 2020 21:04:56 +0100 Subject: [PATCH 28/28] FEM: Python objects and guiobjects, code formating --- .../Fem/femguiobjects/FemSelectionWidgets.py | 1 - .../ViewProviderFemConstraint.py | 1 - ...iderFemConstraintElectrostaticPotential.py | 1 - .../_ViewProviderFemConstraintFlowVelocity.py | 1 - ...roviderFemConstraintInitialFlowVelocity.py | 1 - .../_ViewProviderFemConstraintSelfWeight.py | 5 ++- .../_ViewProviderFemConstraintTie.py | 22 ++++++---- .../_ViewProviderFemElementFluid1D.py | 19 +++++---- .../_ViewProviderFemElementGeometry1D.py | 19 +++++---- .../_ViewProviderFemElementGeometry2D.py | 18 ++++---- .../_ViewProviderFemElementRotation1D.py | 18 ++++---- .../femguiobjects/_ViewProviderFemMaterial.py | 27 +++++++----- ...wProviderFemMaterialMechanicalNonlinear.py | 5 ++- .../_ViewProviderFemMaterialReinforced.py | 21 ++++++---- .../_ViewProviderFemMeshBoundaryLayer.py | 19 +++++---- .../_ViewProviderFemMeshGroup.py | 19 +++++---- .../_ViewProviderFemMeshRegion.py | 19 +++++---- .../_ViewProviderFemMeshResult.py | 5 ++- .../_ViewProviderFemResultMechanical.py | 36 ++++++++-------- .../_ViewProviderFemSolverCalculix.py | 30 ++++++++------ .../_FemConstraintBodyHeatSource.py | 1 + .../femobjects/_FemConstraintSelfWeight.py | 7 +++- src/Mod/Fem/femobjects/_FemConstraintTie.py | 6 ++- src/Mod/Fem/femobjects/_FemElementFluid1D.py | 41 ++++++++++++++++++- .../Fem/femobjects/_FemElementGeometry1D.py | 12 +++++- .../Fem/femobjects/_FemElementGeometry2D.py | 5 ++- .../Fem/femobjects/_FemElementRotation1D.py | 6 ++- src/Mod/Fem/femobjects/_FemMaterial.py | 8 +++- .../_FemMaterialMechanicalNonlinear.py | 4 +- .../Fem/femobjects/_FemMaterialReinforced.py | 8 +++- .../Fem/femobjects/_FemMeshBoundaryLayer.py | 6 +-- src/Mod/Fem/femobjects/_FemMeshGroup.py | 6 ++- src/Mod/Fem/femobjects/_FemMeshRegion.py | 6 ++- src/Mod/Fem/femobjects/_FemMeshResult.py | 3 +- .../Fem/femobjects/_FemResultMechanical.py | 23 ++--------- 35 files changed, 267 insertions(+), 162 deletions(-) diff --git a/src/Mod/Fem/femguiobjects/FemSelectionWidgets.py b/src/Mod/Fem/femguiobjects/FemSelectionWidgets.py index 3479207684..4d771556d7 100644 --- a/src/Mod/Fem/femguiobjects/FemSelectionWidgets.py +++ b/src/Mod/Fem/femguiobjects/FemSelectionWidgets.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2017 Markus Hovorka * # * Copyright (c) 2018 Bernd Hahnebach * # * * diff --git a/src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py b/src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py index 11ac8ee76e..21923bfc92 100644 --- a/src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py +++ b/src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2017 Markus Hovorka * # * Copyright (c) 2018 Bernd Hahnebach * # * * diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintElectrostaticPotential.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintElectrostaticPotential.py index cc1f3bac35..78299882aa 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintElectrostaticPotential.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintElectrostaticPotential.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2017 Markus Hovorka * # * * # * This program is free software; you can redistribute it and/or modify * diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintFlowVelocity.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintFlowVelocity.py index f8f012f7d1..401c0da39d 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintFlowVelocity.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintFlowVelocity.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2017 Markus Hovorka * # * * # * This program is free software; you can redistribute it and/or modify * diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintInitialFlowVelocity.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintInitialFlowVelocity.py index 5262150101..7a14bc8464 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintInitialFlowVelocity.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintInitialFlowVelocity.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2017 Markus Hovorka * # * * # * This program is free software; you can redistribute it and/or modify * diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintSelfWeight.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintSelfWeight.py index 2c7e4a75e7..439413b5a0 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintSelfWeight.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintSelfWeight.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2016 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -32,7 +31,9 @@ from . import ViewProviderFemConstraint class _ViewProviderFemConstraintSelfWeight(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemConstraintSelfWeight object" + """ + A View Provider for the FemConstraintSelfWeight object" + """ def getIcon(self): return ":/icons/fem-constraint-selfweight.svg" diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintTie.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintTie.py index 982ee37798..5fcd865e84 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintTie.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemConstraintTie.py @@ -1,6 +1,5 @@ # *************************************************************************** -# * * -# * Copyright (c) 2015 Bernd Hahnebach * +# * Copyright (c) 2020 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -30,15 +29,18 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -from . import ViewProviderFemConstraint -# for the panel -from PySide import QtCore, QtGui +from PySide import QtCore +from PySide import QtGui + from . import FemSelectionWidgets +from . import ViewProviderFemConstraint class _ViewProviderFemConstraintTie(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemConstraintTie object" + """ + A View Provider for the FemConstraintTie object + """ def getIcon(self): return ":/icons/fem-constraint-tie.svg" @@ -48,12 +50,14 @@ class _ViewProviderFemConstraintTie(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemConstraintTie + _TaskPanel ) -class _TaskPanelFemConstraintTie: - """The TaskPanel for editing References property of FemConstraintTie objects""" +class _TaskPanel: + """ + The TaskPanel for editing References property of FemConstraintTie objects + """ def __init__(self, obj): diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py index 53ad586ee0..6c3742b562 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2016 Ofentse Kgoa * # * Copyright (c) 2018 Bernd Hahnebach * # * Based on the FemElementGeometry1D by Bernd Hahnebach * @@ -32,17 +31,19 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -from . import ViewProviderFemConstraint -# for the panel -from femobjects import _FemElementFluid1D from PySide import QtCore from PySide import QtGui + from . import FemSelectionWidgets +from . import ViewProviderFemConstraint +from femobjects import _FemElementFluid1D class _ViewProviderFemElementFluid1D(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemElementFluid1D object" + """ + A View Provider for the FemElementFluid1D object + """ def getIcon(self): return ":/icons/fem-element-fluid-1d.svg" @@ -52,12 +53,14 @@ class _ViewProviderFemElementFluid1D(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemElementFluid1D + _TaskPanel ) -class _TaskPanelFemElementFluid1D: - """The TaskPanel for editing References property of FemElementFluid1D objects""" +class _TaskPanel: + """ + The TaskPanel for editing References property of FemElementFluid1D objects + """ def __init__(self, obj): diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py index 025956c32f..4c92d806c6 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2015 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -30,16 +29,18 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -from . import ViewProviderFemConstraint -# for the panel -from femobjects import _FemElementGeometry1D from PySide import QtCore + from . import FemSelectionWidgets +from . import ViewProviderFemConstraint +from femobjects import _FemElementGeometry1D class _ViewProviderFemElementGeometry1D(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemElementGeometry1D object" + """ + A View Provider for the FemElementGeometry1D object + """ def getIcon(self): return ":/icons/fem-element-geometry-1d.svg" @@ -49,12 +50,14 @@ class _ViewProviderFemElementGeometry1D(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemElementGeometry1D + _TaskPanel ) -class _TaskPanelFemElementGeometry1D: - """The TaskPanel for editing References property of FemElementGeometry1D objects""" +class _TaskPanel: + """ + The TaskPanel for editing References property of FemElementGeometry1D objects + """ def __init__(self, obj): diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py index d289ded278..8af3f1667e 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2015 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -31,15 +30,16 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -from . import ViewProviderFemConstraint - -# for the panel from PySide import QtCore + from . import FemSelectionWidgets +from . import ViewProviderFemConstraint class _ViewProviderFemElementGeometry2D(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemElementGeometry2D object" + """ + A View Provider for the FemElementGeometry2D object + """ def getIcon(self): return ":/icons/fem-element-geometry-2d.svg" @@ -49,12 +49,14 @@ class _ViewProviderFemElementGeometry2D(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemElementGeometry2D + _TaskPanel ) -class _TaskPanelFemElementGeometry2D: - """The TaskPanel for editing References property of FemElementGeometry2D objects""" +class _TaskPanel: + """ + The TaskPanel for editing References property of FemElementGeometry2D objects + """ def __init__(self, obj): diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py index dba68203da..5765968d48 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2017 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -30,15 +29,17 @@ __url__ = "http://www.freecadweb.org" import FreeCAD import FreeCADGui -from . import ViewProviderFemConstraint -# for the panel from PySide import QtCore + from . import FemSelectionWidgets +from . import ViewProviderFemConstraint class _ViewProviderFemElementRotation1D(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemElementRotation1D object" + """ + A View Provider for the FemElementRotation1D object + """ def getIcon(self): return ":/icons/fem-element-rotation-1d.svg" @@ -50,13 +51,16 @@ class _ViewProviderFemElementRotation1D(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemElementRotation1D + _TaskPanel ) """ -class _TaskPanelFemElementRotation1D: - """The TaskPanel for editing References property of FemElementRotation1D objects""" +class _TaskPanel: + """ + The TaskPanel for editing References property of FemElementRotation1D objects + """ + def __init__(self, obj): self.obj = obj diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py index ea27cd51e6..707801e020 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py @@ -28,16 +28,17 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _ViewProviderFemMaterial -import FreeCAD -import FreeCADGui -from . import ViewProviderFemConstraint +import sys -# for the panel -from FreeCAD import Units -from . import FemSelectionWidgets from PySide import QtCore from PySide import QtGui -import sys + +import FreeCAD +import FreeCADGui +from FreeCAD import Units + +from . import FemSelectionWidgets +from . import ViewProviderFemConstraint if sys.version_info.major >= 3: @@ -45,7 +46,9 @@ if sys.version_info.major >= 3: class _ViewProviderFemMaterial(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemMaterial object" + """ + A View Provider for the FemMaterial object + """ def getIcon(self): return ":/icons/fem-material.svg" @@ -55,12 +58,14 @@ class _ViewProviderFemMaterial(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemMaterial + _TaskPanel ) -class _TaskPanelFemMaterial: - """The editmode TaskPanel for FemMaterial objects""" +class _TaskPanel: + """ + The editmode TaskPanel for FemMaterial objects + """ def __init__(self, obj): diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialMechanicalNonlinear.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialMechanicalNonlinear.py index 7bc328d810..db495692cb 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialMechanicalNonlinear.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialMechanicalNonlinear.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2016 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -32,7 +31,9 @@ from . import ViewProviderFemConstraint class _ViewProviderFemMaterialMechanicalNonlinear(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemMaterialMechanicalNonlinear object" + """ + A View Provider for the FemMaterialMechanicalNonlinear object + """ def getIcon(self): return ":/icons/fem-material-nonlinear.svg" diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py index 4b99cdbed5..4eeb4018ed 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMaterialReinforced.py @@ -27,16 +27,15 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _ViewProviderFemMaterialReinforced +import sys + import FreeCAD import FreeCADGui -from . import ViewProviderFemConstraint - -# task panel -# from . import FemSelectionWidgets from PySide import QtCore from PySide import QtGui -import sys + +from . import ViewProviderFemConstraint if sys.version_info.major >= 3: @@ -44,7 +43,9 @@ if sys.version_info.major >= 3: class _ViewProviderFemMaterialReinforced(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemMaterialReinfocement object" + """ + A View Provider for the FemMaterialReinfocement object + """ def getIcon(self): return ":/icons/fem-material-reinforced.svg" @@ -54,12 +55,14 @@ class _ViewProviderFemMaterialReinforced(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemMaterialReinforced + _TaskPanel ) -class _TaskPanelFemMaterialReinforced: - """The editmode TaskPanel for FemMaterialReinforced objects""" +class _TaskPanel: + """ + The editmode TaskPanel for FemMaterialReinforced objects + """ if sys.version_info.major >= 3: unicode = str diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py index 115597236f..905cdb280b 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2016 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -28,17 +27,19 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _ViewProviderFemMeshBoundaryLayer +from PySide import QtCore + import FreeCAD import FreeCADGui -from . import ViewProviderFemConstraint -# for the panel -from PySide import QtCore from . import FemSelectionWidgets +from . import ViewProviderFemConstraint class _ViewProviderFemMeshBoundaryLayer(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemMeshBoundaryLayer object" + """ + A View Provider for the FemMeshBoundaryLayer object + """ def getIcon(self): return ":/icons/fem-femmesh-boundary-layer.svg" @@ -48,12 +49,14 @@ class _ViewProviderFemMeshBoundaryLayer(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemMeshBoundaryLayer + _TaskPanel ) -class _TaskPanelFemMeshBoundaryLayer: - """The TaskPanel for editing References property of FemMeshBoundaryLayer objects""" +class _TaskPanel: + """ + The TaskPanel for editing References property of FemMeshBoundaryLayer objects + """ def __init__(self, obj): diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py index 6a1f6ba055..7fc38f7483 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2016 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -28,17 +27,19 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _ViewProviderFemMeshGroup +from PySide import QtCore + import FreeCAD import FreeCADGui -from . import ViewProviderFemConstraint -# for the panel -from PySide import QtCore from . import FemSelectionWidgets +from . import ViewProviderFemConstraint class _ViewProviderFemMeshGroup(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemMeshGroup object" + """ + A View Provider for the FemMeshGroup object + """ def getIcon(self): return ":/icons/fem-femmesh-from-shape.svg" @@ -48,12 +49,14 @@ class _ViewProviderFemMeshGroup(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemMeshGroup + _TaskPanel ) -class _TaskPanelFemMeshGroup: - """The TaskPanel for editing References property of FemMeshGroup objects""" +class _TaskPanel: + """ + The TaskPanel for editing References property of FemMeshGroup objects + """ def __init__(self, obj): diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py index 14a355dc56..9242e51c7c 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2016 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -28,17 +27,19 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _ViewProviderFemMeshRegion +from PySide import QtCore + import FreeCAD import FreeCADGui -from . import ViewProviderFemConstraint -# for the panel -from PySide import QtCore from . import FemSelectionWidgets +from . import ViewProviderFemConstraint class _ViewProviderFemMeshRegion(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemMeshRegion object" + """ + A View Provider for the FemMeshRegion object + """ def getIcon(self): return ":/icons/fem-femmesh-region.svg" @@ -48,12 +49,14 @@ class _ViewProviderFemMeshRegion(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemMeshRegion + _TaskPanel ) -class _TaskPanelFemMeshRegion: - """The TaskPanel for editing References property of FemMeshRegion objects""" +class _TaskPanel: + """ + The TaskPanel for editing References property of FemMeshRegion objects + """ def __init__(self, obj): diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py index 68a857303b..a0099cbc54 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2017 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -32,7 +31,9 @@ from . import ViewProviderFemConstraint class _ViewProviderFemMeshResult(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemMeshResult object" + """ + A View Provider for the FemMeshResult object + """ def getIcon(self): return ":/icons/fem-femmesh-result.svg" diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py index b5cf9527c4..d0fd37ae0f 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py @@ -1,6 +1,6 @@ # *************************************************************************** -# * * # * Copyright (c) 2015 Qingfeng Xia * +# * Copyright (c) 2016 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -28,22 +28,25 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD ViewProvider for mechanical ResultObjectPython in FEM workbench -import FreeCAD -import FreeCADGui -from . import ViewProviderFemConstraint +import matplotlib.pyplot as plt +import numpy as np -# for the panel -import femresult.resulttools as resulttools from PySide import QtCore from PySide import QtGui from PySide.QtCore import Qt from PySide.QtGui import QApplication -import numpy as np -import matplotlib.pyplot as plt + +import FreeCAD +import FreeCADGui + +from . import ViewProviderFemConstraint +import femresult.resulttools as resulttools class _ViewProviderFemResultMechanical(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemResultObject Python derived FemResult class" + """ + A View Provider for the FemResultObject Python derived FemResult class + """ def getIcon(self): """after load from FCStd file, self.icon does not exist, return constant path instead""" @@ -54,7 +57,7 @@ class _ViewProviderFemResultMechanical(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemResultShow, + _TaskPanel, ) # overwrite unsetEdit, because the mesh result obj needs to be hided on task panel exit @@ -78,8 +81,10 @@ class _ViewProviderFemResultMechanical(ViewProviderFemConstraint.ViewProxy): return True -class _TaskPanelFemResultShow: - """The task panel for the post-processing""" +class _TaskPanel: + """ + The task panel for the post-processing + """ def __init__(self, obj): self.result_obj = obj @@ -671,13 +676,6 @@ class _TaskPanelFemResultShow: # helper -def hide_femmeshes_postpiplines(): - # hide all visible FEM mesh objects and VTK FemPostPipeline objects - for o in FreeCAD.ActiveDocument.Objects: - if o.isDerivedFrom("Fem::FemMeshObject") or o.isDerivedFrom("Fem::FemPostPipeline"): - o.ViewObject.hide() - - def hide_parts_constraints(): from FemGui import getActiveAnalysis fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") diff --git a/src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py b/src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py index f40238bd5a..2a84c6be58 100644 --- a/src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py +++ b/src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py @@ -1,5 +1,4 @@ # *************************************************************************** -# * * # * Copyright (c) 2015 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -28,25 +27,30 @@ __url__ = "http://www.freecadweb.org" # \ingroup FEM # \brief FreeCAD FEM _ViewProviderFemSolverCalculix -import FreeCAD -import FreeCADGui -from . import ViewProviderFemConstraint +import os +import sys +import time -# for the panel from PySide import QtCore from PySide import QtGui from PySide.QtCore import Qt from PySide.QtGui import QApplication -import os -import time -import sys + +import FreeCAD +import FreeCADGui + +import FemGui +from . import ViewProviderFemConstraint + if sys.version_info.major >= 3: def unicode(text, *args): return str(text) class _ViewProviderFemSolverCalculix(ViewProviderFemConstraint.ViewProxy): - "A View Provider for the FemSolverCalculix object" + """ + A View Provider for the FemSolverCalculix object + """ def getIcon(self): return ":/icons/fem-solver-standard.svg" @@ -56,13 +60,15 @@ class _ViewProviderFemSolverCalculix(ViewProviderFemConstraint.ViewProxy): self, vobj, mode, - _TaskPanelFemSolverCalculix, + _TaskPanel, hide_mesh=False ) -class _TaskPanelFemSolverCalculix: - """The TaskPanel for CalculiX ccx tools solver object""" +class _TaskPanel: + """ + The TaskPanel for CalculiX ccx tools solver object + """ def __init__(self, solver_object): self.form = FreeCADGui.PySideUic.loadUi( diff --git a/src/Mod/Fem/femobjects/_FemConstraintBodyHeatSource.py b/src/Mod/Fem/femobjects/_FemConstraintBodyHeatSource.py index 460919101f..be05769f76 100644 --- a/src/Mod/Fem/femobjects/_FemConstraintBodyHeatSource.py +++ b/src/Mod/Fem/femobjects/_FemConstraintBodyHeatSource.py @@ -36,6 +36,7 @@ class Proxy(FemConstraint.Proxy): def __init__(self, obj): super(Proxy, self).__init__(obj) + obj.addProperty( "App::PropertyFloat", "HeatSource", diff --git a/src/Mod/Fem/femobjects/_FemConstraintSelfWeight.py b/src/Mod/Fem/femobjects/_FemConstraintSelfWeight.py index d302690a65..c4db174bf8 100644 --- a/src/Mod/Fem/femobjects/_FemConstraintSelfWeight.py +++ b/src/Mod/Fem/femobjects/_FemConstraintSelfWeight.py @@ -31,7 +31,9 @@ from . import FemConstraint class _FemConstraintSelfWeight(FemConstraint.Proxy): - "The FemConstraintSelfWeight object" + """ + The FemConstraintSelfWeight object" + """ Type = "Fem::ConstraintSelfWeight" @@ -44,18 +46,21 @@ class _FemConstraintSelfWeight(FemConstraint.Proxy): "Gravity", "Gravity direction: set the x-component of the normalized gravity vector" ) + obj.addProperty( "App::PropertyFloat", "Gravity_y", "Gravity", "Gravity direction: set the y-component of the normalized gravity vector" ) + obj.addProperty( "App::PropertyFloat", "Gravity_z", "Gravity", "Gravity direction: set the z-component of the normalized gravity vector" ) + obj.Gravity_x = 0.0 obj.Gravity_y = 0.0 obj.Gravity_z = -1.0 diff --git a/src/Mod/Fem/femobjects/_FemConstraintTie.py b/src/Mod/Fem/femobjects/_FemConstraintTie.py index e785dd8382..5322497b1c 100644 --- a/src/Mod/Fem/femobjects/_FemConstraintTie.py +++ b/src/Mod/Fem/femobjects/_FemConstraintTie.py @@ -1,5 +1,5 @@ # *************************************************************************** -# * Copyright (c) 2015 Bernd Hahnebach * +# * Copyright (c) 2020 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -31,7 +31,9 @@ from . import FemConstraint class _FemConstraintTie(FemConstraint.Proxy): - "The FemConstraintTie object" + """ + The FemConstraintTie object + """ Type = "Fem::ConstraintTie" diff --git a/src/Mod/Fem/femobjects/_FemElementFluid1D.py b/src/Mod/Fem/femobjects/_FemElementFluid1D.py index 44a030ce6d..3d80b35b9d 100644 --- a/src/Mod/Fem/femobjects/_FemElementFluid1D.py +++ b/src/Mod/Fem/femobjects/_FemElementFluid1D.py @@ -1,5 +1,6 @@ # *************************************************************************** # * Copyright (c) 2016 Ofentse Kgoa * +# * Copyright (c) 2018 Bernd Hahnebach * # * Based on the FemElementGeometry1D by Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * @@ -32,9 +33,12 @@ from . import FemConstraint class _FemElementFluid1D(FemConstraint.Proxy): - "The FemElementFluid1D object" + """ + The FemElementFluid1D object + """ Type = "Fem::ElementFluid1D" + known_fluid_types = ["Liquid"] # "Gas", "Open Channel" are not implemented in ccx writer # known_fluid_types = ["Liquid", "Gas", "Open Channel"] @@ -56,42 +60,49 @@ class _FemElementFluid1D(FemConstraint.Proxy): def __init__(self, obj): super(_FemElementFluid1D, self).__init__(obj) + obj.addProperty( "App::PropertyLinkSubList", "References", "FluidSection", "List of fluid section shapes" ) + obj.addProperty( "App::PropertyEnumeration", "SectionType", "FluidSection", "select fluid section type" ) + obj.addProperty( "App::PropertyEnumeration", "LiquidSectionType", "LiquidSection", "select liquid section type" ) + obj.addProperty( "App::PropertyArea", "ManningArea", "LiquidManning", "set area of the manning fluid section" ) + obj.addProperty( "App::PropertyLength", "ManningRadius", "LiquidManning", "set hydraulic radius of manning fluid section" ) + obj.addProperty( "App::PropertyFloat", "ManningCoefficient", "LiquidManning", "set coefficient of manning fluid section" ) + obj.addProperty( "App::PropertyArea", "EnlargeArea1", @@ -104,168 +115,196 @@ class _FemElementFluid1D(FemConstraint.Proxy): "LiquidEnlargement", "set enlarged area of enlargement fluid section" ) + obj.addProperty( "App::PropertyArea", "ContractArea1", "LiquidContraction", "set initial area of the contraction fluid section" ) + obj.addProperty( "App::PropertyArea", "ContractArea2", "LiquidContraction", "set contracted area of contraction fluid section" ) + obj.addProperty( "App::PropertyFloat", "InletPressure", "LiquidInlet", "set inlet pressure for fluid section" ) + obj.addProperty( "App::PropertyFloat", "OutletPressure", "LiquidOutlet", "set outlet pressure for fluid section" ) + obj.addProperty( "App::PropertyFloat", "InletFlowRate", "LiquidInlet", "set inlet mass flow rate for fluid section" ) + obj.addProperty( "App::PropertyFloat", "OutletFlowRate", "LiquidOutlet", "set outlet mass flow rate for fluid section" ) + obj.addProperty( "App::PropertyBool", "InletPressureActive", "LiquidInlet", "activates or deactivates inlet pressure for fluid section" ) + obj.addProperty( "App::PropertyBool", "OutletPressureActive", "LiquidOutlet", "activates or deactivates outlet pressure for fluid section" ) + obj.addProperty( "App::PropertyBool", "InletFlowRateActive", "LiquidInlet", "activates or deactivates inlet flow rate for fluid section" ) + obj.addProperty( "App::PropertyBool", "OutletFlowRateActive", "LiquidOutlet", "activates or deactivates outlet flow rate for fluid section" ) + obj.addProperty( "App::PropertyArea", "EntrancePipeArea", "LiquidEntrance", "set the pipe area of the entrance fluid section" ) + obj.addProperty( "App::PropertyArea", "EntranceArea", "LiquidEntrance", "set the entrance area of the entrance fluid section" ) + obj.addProperty( "App::PropertyArea", "DiaphragmPipeArea", "LiquidDiaphragm", "set the pipe area of the diaphragm fluid section" ) + obj.addProperty( "App::PropertyArea", "DiaphragmArea", "LiquidDiaphragm", "set the diaphragm area of the diaphragm fluid section" ) + obj.addProperty( "App::PropertyArea", "BendPipeArea", "LiquidBend", "set pipe area of the bend fluid section" ) + obj.addProperty( "App::PropertyFloat", "BendRadiusDiameter", "LiquidBend", "set ratio of bend radius over pipe diameter of the bend fluid section" ) + obj.addProperty( "App::PropertyFloat", "BendAngle", "LiquidBend", "set bend angle of the bend fluid section" ) + obj.addProperty( "App::PropertyFloat", "BendLossCoefficient", "LiquidBend", "set loss coefficient of the bend fluid section" ) + obj.addProperty( "App::PropertyArea", "GateValvePipeArea", "LiquidGateValve", "set pipe area of the gate valve fluid section" ) + obj.addProperty( "App::PropertyFloat", "GateValveClosingCoeff", "LiquidGateValve", "set closing coefficient of the gate valve fluid section" ) + obj.addProperty( "App::PropertyFloatList", "PumpFlowRate", "LiquidPump", "set the pump characteristic flow rate of the pump fluid section" ) + obj.addProperty( "App::PropertyFloatList", "PumpHeadLoss", "LiquidPump", "set the pump characteristic head loss of the pump fluid section" ) + obj.addProperty( "App::PropertyArea", "ColebrookeArea", "LiquidColebrooke", "set pipe area of the colebrooke fluid section" ) + obj.addProperty( "App::PropertyLength", "ColebrookeRadius", "LiquidColebrooke", "set hydraulic radius of the colebrooke fluid section" ) + obj.addProperty( "App::PropertyLength", "ColebrookeGrainDiameter", "LiquidColebrooke", "set grain diameter of the colebrooke fluid section" ) + obj.addProperty( "App::PropertyFloat", "ColebrookeFormFactor", "LiquidColebrooke", "set coefficient of the colebrooke fluid section" ) + obj.addProperty( "App::PropertyEnumeration", "GasSectionType", "GasSection", "select gas section type" ) + obj.addProperty( "App::PropertyEnumeration", "ChannelSectionType", diff --git a/src/Mod/Fem/femobjects/_FemElementGeometry1D.py b/src/Mod/Fem/femobjects/_FemElementGeometry1D.py index 480c912774..d1bfd97d61 100644 --- a/src/Mod/Fem/femobjects/_FemElementGeometry1D.py +++ b/src/Mod/Fem/femobjects/_FemElementGeometry1D.py @@ -31,54 +31,64 @@ from . import FemConstraint class _FemElementGeometry1D(FemConstraint.Proxy): - "The FemElementGeometry1D object" + """ + The FemElementGeometry1D object + """ Type = "Fem::ElementGeometry1D" known_beam_types = ["Rectangular", "Circular", "Pipe"] def __init__(self, obj): super(_FemElementGeometry1D, self).__init__(obj) + obj.addProperty( "App::PropertyLength", "RectWidth", "RectBeamSection", "set width of the rectangular beam elements" ) + obj.addProperty( "App::PropertyLength", "RectHeight", "RectBeamSection", "set height of therectangular beam elements" ) + obj.addProperty( "App::PropertyLength", "CircDiameter", "CircBeamSection", "set diameter of the circular beam elements" ) + obj.addProperty( "App::PropertyLength", "PipeDiameter", "PipeBeamSection", "set outer diameter of the pipe beam elements" ) + obj.addProperty( "App::PropertyLength", "PipeThickness", "PipeBeamSection", "set thickness of the pipe beam elements" ) + obj.addProperty( "App::PropertyEnumeration", "SectionType", "BeamSection", "select beam section type" ) + obj.addProperty( "App::PropertyLinkSubList", "References", "BeamSection", "List of beam section shapes" ) + obj.SectionType = _FemElementGeometry1D.known_beam_types obj.SectionType = "Rectangular" diff --git a/src/Mod/Fem/femobjects/_FemElementGeometry2D.py b/src/Mod/Fem/femobjects/_FemElementGeometry2D.py index ee677cb60d..3dcd64ff97 100644 --- a/src/Mod/Fem/femobjects/_FemElementGeometry2D.py +++ b/src/Mod/Fem/femobjects/_FemElementGeometry2D.py @@ -31,7 +31,9 @@ from . import FemConstraint class _FemElementGeometry2D(FemConstraint.Proxy): - "The FemElementGeometry2D object" + """ + The FemElementGeometry2D object + """ Type = "Fem::ElementGeometry2D" @@ -44,6 +46,7 @@ class _FemElementGeometry2D(FemConstraint.Proxy): "ShellThickness", "set thickness of the shell elements" ) + obj.addProperty( "App::PropertyLinkSubList", "References", diff --git a/src/Mod/Fem/femobjects/_FemElementRotation1D.py b/src/Mod/Fem/femobjects/_FemElementRotation1D.py index 19c18855a3..3ab4bc4cbc 100644 --- a/src/Mod/Fem/femobjects/_FemElementRotation1D.py +++ b/src/Mod/Fem/femobjects/_FemElementRotation1D.py @@ -31,18 +31,22 @@ from . import FemConstraint class _FemElementRotation1D(FemConstraint.Proxy): - "The FemElementRotation1D object" + """ + The FemElementRotation1D object + """ Type = "Fem::ElementRotation1D" def __init__(self, obj): super(_FemElementRotation1D, self).__init__(obj) + obj.addProperty( "App::PropertyAngle", "Rotation", "BeamRotation", "Set the rotation of beam elements" ) + obj.addProperty( "App::PropertyLinkSubList", "References", diff --git a/src/Mod/Fem/femobjects/_FemMaterial.py b/src/Mod/Fem/femobjects/_FemMaterial.py index 16fe442e08..7673de94cd 100644 --- a/src/Mod/Fem/femobjects/_FemMaterial.py +++ b/src/Mod/Fem/femobjects/_FemMaterial.py @@ -1,5 +1,6 @@ # *************************************************************************** # * Copyright (c) 2013 Juergen Riegel * +# * Copyright (c) 2016 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -31,22 +32,27 @@ from . import FemConstraint class _FemMaterial(FemConstraint.Proxy): - "The FEM Material object" + """ + The FEM Material object + """ Type = "Fem::Material" def __init__(self, obj): super(_FemMaterial, self).__init__(obj) + obj.addProperty( "App::PropertyLinkSubList", "References", "Material", "List of material shapes" ) + obj.addProperty( "App::PropertyEnumeration", "Category", "Material", "Material type: fluid or solid" ) + obj.Category = ["Solid", "Fluid"] # used in TaskPanel diff --git a/src/Mod/Fem/femobjects/_FemMaterialMechanicalNonlinear.py b/src/Mod/Fem/femobjects/_FemMaterialMechanicalNonlinear.py index 79bc8e73e1..9981bdae6a 100644 --- a/src/Mod/Fem/femobjects/_FemMaterialMechanicalNonlinear.py +++ b/src/Mod/Fem/femobjects/_FemMaterialMechanicalNonlinear.py @@ -31,7 +31,9 @@ from . import FemConstraint class _FemMaterialMechanicalNonlinear(FemConstraint.Proxy): - "The FemMaterialMechanicalNonlinear object" + """ + The FemMaterialMechanicalNonlinear object + """ Type = "Fem::MaterialMechanicalNonlinear" diff --git a/src/Mod/Fem/femobjects/_FemMaterialReinforced.py b/src/Mod/Fem/femobjects/_FemMaterialReinforced.py index 5e8e0feeaa..86877f95cc 100644 --- a/src/Mod/Fem/femobjects/_FemMaterialReinforced.py +++ b/src/Mod/Fem/femobjects/_FemMaterialReinforced.py @@ -31,29 +31,35 @@ from . import FemConstraint class _FemMaterialReinforced(FemConstraint.Proxy): - "The FemMaterialReinforced object" + """ + The FemMaterialReinforced object + """ Type = "Fem::MaterialReinforced" def __init__(self, obj): super(_FemMaterialReinforced, self).__init__(obj) + obj.addProperty( "App::PropertyLinkSubList", "References", "Material", "List of material shapes" ) + obj.addProperty( "App::PropertyMap", "Reinforcement", "Composites", "Reinforcement material properties" ) + obj.addProperty( "App::PropertyEnumeration", "Category", "Material", "Matrix material properties" ) + obj.Category = ["Solid"] obj.Category = "Solid" diff --git a/src/Mod/Fem/femobjects/_FemMeshBoundaryLayer.py b/src/Mod/Fem/femobjects/_FemMeshBoundaryLayer.py index b9eaa39568..fb31002c96 100644 --- a/src/Mod/Fem/femobjects/_FemMeshBoundaryLayer.py +++ b/src/Mod/Fem/femobjects/_FemMeshBoundaryLayer.py @@ -31,7 +31,9 @@ from . import FemConstraint class _FemMeshBoundaryLayer(FemConstraint.Proxy): - "The FemMeshBoundaryLayer object" + """ + The FemMeshBoundaryLayer object + """ Type = "Fem::FemMeshBoundaryLayer" @@ -44,7 +46,6 @@ class _FemMeshBoundaryLayer(FemConstraint.Proxy): "MeshBoundaryLayerProperties", "set number of inflation layers for this boundary" ) - obj.NumberOfLayers = 3 obj.addProperty( @@ -61,7 +62,6 @@ class _FemMeshBoundaryLayer(FemConstraint.Proxy): "MeshBoundaryLayerProperties", "set growth rate of inflation layers for smooth transition" ) - obj.GrowthRate = 1.5 obj.addProperty( diff --git a/src/Mod/Fem/femobjects/_FemMeshGroup.py b/src/Mod/Fem/femobjects/_FemMeshGroup.py index cf2954ca9d..88668fff1b 100644 --- a/src/Mod/Fem/femobjects/_FemMeshGroup.py +++ b/src/Mod/Fem/femobjects/_FemMeshGroup.py @@ -31,18 +31,22 @@ from . import FemConstraint class _FemMeshGroup(FemConstraint.Proxy): - "The FemMeshGroup object" + """ + The FemMeshGroup object + """ Type = "Fem::FemMeshGroup" def __init__(self, obj): super(_FemMeshGroup, self).__init__(obj) + obj.addProperty( "App::PropertyBool", "UseLabel", "MeshGroupProperties", "The identifier used for export (True: Label, False: Name)" ) + obj.addProperty( "App::PropertyLinkSubList", "References", diff --git a/src/Mod/Fem/femobjects/_FemMeshRegion.py b/src/Mod/Fem/femobjects/_FemMeshRegion.py index 13c489ffbf..ce7fcd5805 100644 --- a/src/Mod/Fem/femobjects/_FemMeshRegion.py +++ b/src/Mod/Fem/femobjects/_FemMeshRegion.py @@ -31,18 +31,22 @@ from . import FemConstraint class _FemMeshRegion(FemConstraint.Proxy): - "The FemMeshRegion object" + """ + The FemMeshRegion object + """ Type = "Fem::FemMeshRegion" def __init__(self, obj): super(_FemMeshRegion, self).__init__(obj) + obj.addProperty( "App::PropertyLength", "CharacteristicLength", "MeshRegionProperties", "set characteristic length of FEM elements for this region" ) + obj.addProperty( "App::PropertyLinkSubList", "References", diff --git a/src/Mod/Fem/femobjects/_FemMeshResult.py b/src/Mod/Fem/femobjects/_FemMeshResult.py index 248cecea0e..9390442f1a 100644 --- a/src/Mod/Fem/femobjects/_FemMeshResult.py +++ b/src/Mod/Fem/femobjects/_FemMeshResult.py @@ -31,7 +31,8 @@ from . import FemConstraint class _FemMeshResult(FemConstraint.Proxy): - """The Fem::FemMeshObject's Proxy python type, add Result specific object type + """ + The Fem::FemMeshObject's Proxy python type, add Result specific object type """ Type = "Fem::FemMeshResult" diff --git a/src/Mod/Fem/femobjects/_FemResultMechanical.py b/src/Mod/Fem/femobjects/_FemResultMechanical.py index d42e7b34a5..ca04a489b6 100644 --- a/src/Mod/Fem/femobjects/_FemResultMechanical.py +++ b/src/Mod/Fem/femobjects/_FemResultMechanical.py @@ -1,5 +1,6 @@ # *************************************************************************** # * Copyright (c) 2016 Qingfeng Xia * +# * Copyright (c) 2016 Bernd Hahnebach * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -31,7 +32,8 @@ from . import FemConstraint class _FemResultMechanical(FemConstraint.Proxy): - """The Fem::_FemResultMechanical's Proxy python type, add result specific properties + """ + The Fem::_FemResultMechanical's Proxy python type, add result specific properties """ Type = "Fem::FemResultMechanical" @@ -292,18 +294,6 @@ class _FemResultMechanical(FemConstraint.Proxy): zero_list = 26 * [0] obj.Stats = zero_list - # standard Feature methods - def execute(self, obj): - """"this method is executed on object creation and - whenever the document is recomputed" - update Part or Mesh should NOT lead to recomputation - of the analysis automatically, time consuming - """ - return - - def onChanged(self, obj, prop): - return - def onDocumentRestored(self, obj): # migrate old result objects, because property "StressValues" # was renamed to "vonMises" in commit 8b68ab7 @@ -325,10 +315,3 @@ class _FemResultMechanical(FemConstraint.Proxy): for i in range(12, -1, -1): del temp[3 * i + 1] obj.Stats = temp - - def __getstate__(self): - return self.Type - - def __setstate__(self, state): - if state: - self.Type = state