From 8a8d5f0a3f502013897c2f67aa7a6c9dcca78abe Mon Sep 17 00:00:00 2001 From: Dubstar_04 Date: Tue, 20 Aug 2019 20:34:47 +0100 Subject: [PATCH 01/23] Seperate ToolTable and Tool implementations Seperate the tooltable and tool implementations. --- src/Mod/Path/App/AppPath.cpp | 1 + src/Mod/Path/App/CMakeLists.txt | 3 + src/Mod/Path/App/PropertyTool.h | 2 +- src/Mod/Path/App/Tool.cpp | 264 ++++++++++++++++++++++++ src/Mod/Path/App/Tool.h | 105 ++++++++++ src/Mod/Path/App/ToolPy.xml | 2 +- src/Mod/Path/App/ToolPyImp.cpp | 304 ++++++++++++++++++++++++++++ src/Mod/Path/App/Tooltable.cpp | 234 +-------------------- src/Mod/Path/App/Tooltable.h | 74 +------ src/Mod/Path/App/TooltablePyImp.cpp | 271 +------------------------ 10 files changed, 684 insertions(+), 576 deletions(-) create mode 100644 src/Mod/Path/App/Tool.cpp create mode 100644 src/Mod/Path/App/Tool.h create mode 100644 src/Mod/Path/App/ToolPyImp.cpp diff --git a/src/Mod/Path/App/AppPath.cpp b/src/Mod/Path/App/AppPath.cpp index 026968c503..2e93cd169b 100644 --- a/src/Mod/Path/App/AppPath.cpp +++ b/src/Mod/Path/App/AppPath.cpp @@ -34,6 +34,7 @@ #include "CommandPy.h" #include "Path.h" #include "PathPy.h" +#include "Tool.h" #include "Tooltable.h" #include "ToolPy.h" #include "TooltablePy.h" diff --git a/src/Mod/Path/App/CMakeLists.txt b/src/Mod/Path/App/CMakeLists.txt index 2ef5835eac..32fc5b19ae 100644 --- a/src/Mod/Path/App/CMakeLists.txt +++ b/src/Mod/Path/App/CMakeLists.txt @@ -43,6 +43,7 @@ SET(Python_SRCS PathPy.xml PathPyImp.cpp ToolPy.xml + ToolPyImp.cpp TooltablePy.xml TooltablePyImp.cpp FeaturePathCompoundPy.xml @@ -65,6 +66,8 @@ SET(Path_SRCS Command.h Path.cpp Path.h + Tool.cpp + Tool.h Tooltable.cpp Tooltable.h PropertyPath.cpp diff --git a/src/Mod/Path/App/PropertyTool.h b/src/Mod/Path/App/PropertyTool.h index 85e1756fe9..706e4fae6b 100644 --- a/src/Mod/Path/App/PropertyTool.h +++ b/src/Mod/Path/App/PropertyTool.h @@ -24,7 +24,7 @@ #ifndef PROPERTYTOOL_H #define PROPERTYTOOL_H -#include "Tooltable.h" +#include "Tool.h" #include namespace Path diff --git a/src/Mod/Path/App/Tool.cpp b/src/Mod/Path/App/Tool.cpp new file mode 100644 index 0000000000..62a571d821 --- /dev/null +++ b/src/Mod/Path/App/Tool.cpp @@ -0,0 +1,264 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net) 2014 * + * * + * 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_ + +#endif +#include +#include +#include +#include "Tool.h" + +using namespace Base; +using namespace Path; + + +// TOOL + + +TYPESYSTEM_SOURCE(Path::Tool , Base::Persistence); + +// Constructors & destructors + +Tool::Tool(const char* name, + ToolType type, + ToolMaterial /*material*/, + double diameter, + double lengthoffset, + double flatradius, + double cornerradius, + double cuttingedgeangle, + double cuttingedgeheight) +:Name(name),Type(type),Material(MATUNDEFINED),Diameter(diameter),LengthOffset(lengthoffset), +FlatRadius(flatradius),CornerRadius(cornerradius),CuttingEdgeAngle(cuttingedgeangle), +CuttingEdgeHeight(cuttingedgeheight) +{ +} + +Tool::Tool() +{ + Type = UNDEFINED; + Material = MATUNDEFINED; + Diameter = 0; + LengthOffset = 0; + FlatRadius = 0; + CornerRadius = 0; + CuttingEdgeAngle = 180; + CuttingEdgeHeight = 0; +} + +Tool::~Tool() +{ +} + +// Reimplemented from base class + +unsigned int Tool::getMemSize (void) const +{ + return 0; +} + +void Tool::Save (Writer &writer) const +{ + writer.Stream() << writer.ind() << "" << std::endl; +} + +void Tool::Restore(XMLReader &reader) +{ + reader.readElement("Tool"); + Name = reader.getAttribute("name"); + Diameter = reader.hasAttribute("diameter") ? (double) reader.getAttributeAsFloat("diameter") : 0.0; + LengthOffset = reader.hasAttribute("length") ? (double) reader.getAttributeAsFloat("length") : 0.0; + FlatRadius = reader.hasAttribute("flat") ? (double) reader.getAttributeAsFloat("flat") : 0.0; + CornerRadius = reader.hasAttribute("corner") ? (double) reader.getAttributeAsFloat("corner") : 0.0; + CuttingEdgeAngle = reader.hasAttribute("angle") ? (double) reader.getAttributeAsFloat("angle") : 180.0; + CuttingEdgeHeight = reader.hasAttribute("height") ? (double) reader.getAttributeAsFloat("height") : 0.0; + std::string type = reader.hasAttribute("type") ? reader.getAttribute("type") : ""; + std::string mat = reader.hasAttribute("mat") ? reader.getAttribute("mat") : ""; + + Type = getToolType(type); + Material = getToolMaterial(mat); + + +} + +const std::vector Tool::ToolTypes(void) +{ + std::vector toolTypes(13); + toolTypes[0] ="EndMill"; + toolTypes[1] ="Drill"; + toolTypes[2] ="CenterDrill"; + toolTypes[3] ="CounterSink"; + toolTypes[4] ="CounterBore"; + toolTypes[5] ="FlyCutter"; + toolTypes[6] ="Reamer"; + toolTypes[7] ="Tap"; + toolTypes[8] ="SlotCutter"; + toolTypes[9] ="BallEndMill"; + toolTypes[10] ="ChamferMill"; + toolTypes[11] ="CornerRound"; + toolTypes[12] ="Engraver"; + return toolTypes; + +} + +const std::vector Tool::ToolMaterials(void) +{ + std::vector toolMat(7); + toolMat[0] ="Carbide"; + toolMat[1] ="HighSpeedSteel"; + toolMat[2] ="HighCarbonToolSteel"; + toolMat[3] ="CastAlloy"; + toolMat[4] ="Ceramics"; + toolMat[5] ="Diamond"; + toolMat[6] ="Sialon"; + return toolMat; + +} + +Tool::ToolType Tool::getToolType(std::string type) +{ + Tool::ToolType Type; + if(type=="EndMill") + Type = Tool::ENDMILL; + else if(type=="Drill") + Type = Tool::DRILL; + else if(type=="CenterDrill") + Type = Tool::CENTERDRILL; + else if(type=="CounterSink") + Type = Tool::COUNTERSINK; + else if(type=="CounterBore") + Type = Tool::COUNTERBORE; + else if(type=="FlyCutter") + Type = Tool::FLYCUTTER; + else if(type=="Reamer") + Type = Tool::REAMER; + else if(type=="Tap") + Type = Tool::TAP; + else if(type=="SlotCutter") + Type = Tool::SLOTCUTTER; + else if(type=="BallEndMill") + Type = Tool::BALLENDMILL; + else if(type=="ChamferMill") + Type = Tool::CHAMFERMILL; + else if(type=="CornerRound") + Type = Tool::CORNERROUND; + else if(type=="Engraver") + Type = Tool::ENGRAVER; + else + Type = Tool::UNDEFINED; + + return Type; +} + +Tool::ToolMaterial Tool::getToolMaterial(std::string mat) +{ + Tool::ToolMaterial Material; + if(mat=="Carbide") + Material = Tool::CARBIDE; + else if(mat=="HighSpeedSteel") + Material = Tool::HIGHSPEEDSTEEL; + else if(mat=="HighCarbonToolSteel") + Material = Tool::HIGHCARBONTOOLSTEEL; + else if(mat=="CastAlloy") + Material = Tool::CASTALLOY; + else if(mat=="Ceramics") + Material = Tool::CERAMICS; + else if(mat=="Diamond") + Material = Tool::DIAMOND; + else if(mat=="Sialon") + Material = Tool::SIALON; + else + Material = Tool::MATUNDEFINED; + + return Material; +} + +const char* Tool::TypeName(Tool::ToolType typ) { + switch (typ) { + case Tool::DRILL: + return "Drill"; + case Tool::CENTERDRILL: + return "CenterDrill"; + case Tool::COUNTERSINK: + return "CounterSink"; + case Tool::COUNTERBORE: + return "CounterBore"; + case Tool::FLYCUTTER: + return "FlyCutter"; + case Tool::REAMER: + return "Reamer"; + case Tool::TAP: + return "Tap"; + case Tool::ENDMILL: + return "EndMill"; + case Tool::SLOTCUTTER: + return "SlotCutter"; + case Tool::BALLENDMILL: + return "BallEndMill"; + case Tool::CHAMFERMILL: + return "ChamferMill"; + case Tool::CORNERROUND: + return "CornerRound"; + case Tool::ENGRAVER: + return "Engraver"; + case Tool::UNDEFINED: + return "Undefined"; + } + return "Undefined"; +} + +const char* Tool::MaterialName(Tool::ToolMaterial mat) +{ + switch (mat) { + case Tool::HIGHSPEEDSTEEL: + return "HighSpeedSteel"; + case Tool::CARBIDE: + return "Carbide"; + case Tool::HIGHCARBONTOOLSTEEL: + return "HighCarbonToolSteel"; + case Tool::CASTALLOY: + return "CastAlloy"; + case Tool::CERAMICS: + return "Ceramics"; + case Tool::DIAMOND: + return "Diamond"; + case Tool::SIALON: + return "Sialon"; + case Tool::MATUNDEFINED: + return "Undefined"; + } + return "Undefined"; +} \ No newline at end of file diff --git a/src/Mod/Path/App/Tool.h b/src/Mod/Path/App/Tool.h new file mode 100644 index 0000000000..f06ef2bb35 --- /dev/null +++ b/src/Mod/Path/App/Tool.h @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net) 2014 * + * * + * 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 PATH_TOOL_H +#define PATH_TOOL_H + +#include +#include +#include +#include + +namespace Path +{ + + /** The representation of a single tool */ + class PathExport Tool : public Base::Persistence + { + TYPESYSTEM_HEADER(); + + public: + enum ToolType { + UNDEFINED, + DRILL, + CENTERDRILL, + COUNTERSINK, + COUNTERBORE, + FLYCUTTER, + REAMER, + TAP, + ENDMILL, + SLOTCUTTER, + BALLENDMILL, + CHAMFERMILL, + CORNERROUND, + ENGRAVER }; + + enum ToolMaterial { + MATUNDEFINED, + HIGHSPEEDSTEEL, + HIGHCARBONTOOLSTEEL, + CASTALLOY, + CARBIDE, + CERAMICS, + DIAMOND, + SIALON }; + + //constructors + Tool(); + Tool(const char* name, + ToolType type=Tool::UNDEFINED, + ToolMaterial material=Tool::MATUNDEFINED, + double diameter=10.0, + double lengthoffset=100, + double flatradius=0, + double cornerradius=0, + double cuttingedgeangle=0, + double cuttingedgeheight=0); + ~Tool(); + + // from base class + virtual unsigned int getMemSize (void) const; + virtual void Save (Base::Writer &/*writer*/) const; + virtual void Restore(Base::XMLReader &/*reader*/); + + // attributes + std::string Name; + ToolType Type; + ToolMaterial Material; + double Diameter; + double LengthOffset; + double FlatRadius; + double CornerRadius; + double CuttingEdgeAngle; + double CuttingEdgeHeight; + + static const std::vector ToolTypes(void); + static const std::vector ToolMaterials(void); + static const char* TypeName(ToolType typ); + static ToolType getToolType(std::string type); + static ToolMaterial getToolMaterial(std::string mat); + static const char* MaterialName(ToolMaterial mat); + }; +} //namespace Path + +#endif // PATH_TOOL_H diff --git a/src/Mod/Path/App/ToolPy.xml b/src/Mod/Path/App/ToolPy.xml index 0f515c8491..94e56525d3 100644 --- a/src/Mod/Path/App/ToolPy.xml +++ b/src/Mod/Path/App/ToolPy.xml @@ -5,7 +5,7 @@ Name="ToolPy" Twin="Tool" TwinPointer="Tool" - Include="Mod/Path/App/Tooltable.h" + Include="Mod/Path/App/Tool.h" Namespace="Path" FatherInclude="Base/PersistencePy.h" FatherNamespace="Base" diff --git a/src/Mod/Path/App/ToolPyImp.cpp b/src/Mod/Path/App/ToolPyImp.cpp new file mode 100644 index 0000000000..57d4e87d95 --- /dev/null +++ b/src/Mod/Path/App/ToolPyImp.cpp @@ -0,0 +1,304 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net) 2014 * + * * + * 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" +#include "Base/Reader.h" +#include "Mod/Path/App/Tool.h" +#include "Mod/Path/App/Tooltable.h" + +// inclusion of the generated files (generated out of ToolPy.xml and TooltablePy.xml) +#include "ToolPy.h" +#include "ToolPy.cpp" +//#include "TooltablePy.h" +//#include "TooltablePy.cpp" + +using namespace Path; + +#if PY_MAJOR_VERSION >= 3 +# define PYSTRING_FROMSTRING(str) PyUnicode_FromString(str) +# define PYINT_TYPE PyLong_Type +# define PYINT_FROMLONG(l) PyLong_FromLong(l) +# define PYINT_ASLONG(o) PyLong_AsLong(o) +#else +# define PYSTRING_FROMSTRING(str) PyString_FromString(str) +# define PYINT_TYPE PyInt_Type +# define PYINT_FROMLONG(l) PyInt_FromLong(l) +# define PYINT_ASLONG(o) PyInt_AsLong(o) +#endif + + +// returns a string which represents the object e.g. when printed in python +std::string ToolPy::representation(void) const +{ + std::stringstream str; + str.precision(5); + str << "Tool "; + str << getToolPtr()->Name; + return str.str(); +} + +PyObject *ToolPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper +{ + // create a new instance of ToolPy and the Twin object + return new ToolPy(new Tool); +} + +// constructor method +int ToolPy::PyInit(PyObject* args, PyObject* kwd) +{ + char *name="Default tool"; + char *type = "Undefined"; + char *mat = "Undefined"; + PyObject *dia = 0; + PyObject *len = 0; + PyObject *fla = 0; + PyObject *cor = 0; + PyObject *ang = 0; + PyObject *hei = 0; + int version = 1; + + static char *kwlist[] = {"name", "tooltype", "material", "diameter", "lengthOffset", "flatRadius", "cornerRadius", "cuttingEdgeAngle", "cuttingEdgeHeight" , "version", NULL}; + + PyObject *dict = 0; + if (!kwd && (PyObject_TypeCheck(args, &PyDict_Type) || PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict))) { + static PyObject *arg = PyTuple_New(0); + if (PyObject_TypeCheck(args, &PyDict_Type)) { + dict = args; + } + if (!PyArg_ParseTupleAndKeywords(arg, dict, "|sssOOOOOOi", kwlist, &name, &type, &mat, &dia, &len, &fla, &cor, &ang, &hei, &version)) { + return -1; + } + } else { + PyErr_Clear(); + if (!PyArg_ParseTupleAndKeywords(args, kwd, "|sssOOOOOO", kwlist, &name, &type, &mat, &dia, &len, &fla, &cor, &ang, &hei)) { + return -1; + } + } + + if (1 != version) { + PyErr_SetString(PyExc_TypeError, "Unsupported Tool template version"); + return -1; + } + + getToolPtr()->Name = name; + + std::string typeStr(type); + getToolPtr()->Type = Tool::getToolType(typeStr); + + std::string matStr(mat); + getToolPtr()->Material = Tool::getToolMaterial(matStr); + + getToolPtr()->Diameter = dia ? PyFloat_AsDouble(dia) : 0.0; + getToolPtr()->LengthOffset = len ? PyFloat_AsDouble(len) : 0.0; + getToolPtr()->FlatRadius = fla ? PyFloat_AsDouble(fla) : 0.0; + getToolPtr()->CornerRadius = cor ? PyFloat_AsDouble(cor) : 0.0; + getToolPtr()->CuttingEdgeAngle = ang ? PyFloat_AsDouble(ang) : 180.0; + getToolPtr()->CuttingEdgeHeight = hei ? PyFloat_AsDouble(hei) : 0.0; + + return 0; +} + +// attributes get/setters + +Py::String ToolPy::getName(void) const +{ + return Py::String(getToolPtr()->Name.c_str()); +} + +void ToolPy::setName(Py::String arg) +{ + std::string name = arg.as_std_string(); + getToolPtr()->Name = name; +} + +Py::String ToolPy::getToolType(void) const +{ + return Py::String(Tool::TypeName(getToolPtr()->Type)); +} + +void ToolPy::setToolType(Py::String arg) +{ + std::string typeStr(arg.as_std_string()); + getToolPtr()->Type = Tool::getToolType(typeStr); + +} + +Py::String ToolPy::getMaterial(void) const +{ + return Py::String(Tool::MaterialName(getToolPtr()->Material)); +} + +void ToolPy::setMaterial(Py::String arg) +{ + std::string matStr(arg.as_std_string()); + getToolPtr()->Material = Tool::getToolMaterial(matStr); +} + +Py::Float ToolPy::getDiameter(void) const +{ + return Py::Float(getToolPtr()->Diameter); +} + +void ToolPy::setDiameter(Py::Float arg) +{ + getToolPtr()->Diameter = arg.operator double(); +} + +Py::Float ToolPy::getLengthOffset(void) const +{ + return Py::Float(getToolPtr()->LengthOffset); +} + +void ToolPy::setLengthOffset(Py::Float arg) +{ + getToolPtr()->LengthOffset = arg.operator double(); +} + +Py::Float ToolPy::getFlatRadius(void) const +{ + return Py::Float(getToolPtr()->FlatRadius); +} + +void ToolPy::setFlatRadius(Py::Float arg) +{ + getToolPtr()->FlatRadius = arg.operator double(); +} + +Py::Float ToolPy::getCornerRadius(void) const +{ + return Py::Float(getToolPtr()->CornerRadius); +} + +void ToolPy::setCornerRadius(Py::Float arg) +{ + getToolPtr()->CornerRadius = arg.operator double(); +} + +Py::Float ToolPy::getCuttingEdgeAngle(void) const +{ + return Py::Float(getToolPtr()->CuttingEdgeAngle); +} + +void ToolPy::setCuttingEdgeAngle(Py::Float arg) +{ + getToolPtr()->CuttingEdgeAngle = arg.operator double(); +} + +Py::Float ToolPy::getCuttingEdgeHeight(void) const +{ + return Py::Float(getToolPtr()->CuttingEdgeHeight); +} + +void ToolPy::setCuttingEdgeHeight(Py::Float arg) +{ + getToolPtr()->CuttingEdgeHeight = arg.operator double(); +} + +// custom attributes get/set + +PyObject *ToolPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int ToolPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + +PyObject* ToolPy::copy(PyObject * args) +{ + if (PyArg_ParseTuple(args, "")) { + return new ToolPy(new Path::Tool(*getToolPtr())); + } + throw Py::TypeError("This method accepts no argument"); +} + +PyObject* ToolPy::setFromTemplate(PyObject * args) +{ + char *pstr = 0; + if (PyArg_ParseTuple(args, "s", &pstr)) { + // embed actual string in dummy tag so XMLReader can consume that on construction + std::ostringstream os; + os << "" << pstr << ""; + std::istringstream is(os.str()); + Base::XMLReader reader("", is); + getToolPtr()->Restore(reader); + Py_Return ; + } + + PyErr_Clear(); + if (!PyInit(args, 0)) { + Py_Return ; + } + + PyErr_SetString(PyExc_TypeError, "argument must be a string or dictionary"); + return 0; +} + +PyObject* ToolPy::templateAttrs(PyObject * args) +{ + if (!args || PyArg_ParseTuple(args, "")) { + PyObject *dict = PyDict_New(); + PyDict_SetItemString(dict, "version", PYINT_FROMLONG(1)); + PyDict_SetItemString(dict, "name", PYSTRING_FROMSTRING(getToolPtr()->Name.c_str())); + PyDict_SetItemString(dict, "tooltype",PYSTRING_FROMSTRING(Tool::TypeName(getToolPtr()->Type))); + PyDict_SetItemString(dict, "material", PYSTRING_FROMSTRING(Tool::MaterialName(getToolPtr()->Material))); + PyDict_SetItemString(dict, "diameter", PyFloat_FromDouble(getToolPtr()->Diameter)); + PyDict_SetItemString(dict, "lengthOffset", PyFloat_FromDouble(getToolPtr()->LengthOffset)); + PyDict_SetItemString(dict, "flatRadius", PyFloat_FromDouble(getToolPtr()->FlatRadius)); + PyDict_SetItemString(dict, "cornerRadius", PyFloat_FromDouble(getToolPtr()->CornerRadius)); + PyDict_SetItemString(dict, "cuttingEdgeAngle", PyFloat_FromDouble(getToolPtr()->CuttingEdgeAngle)); + PyDict_SetItemString(dict, "cuttingEdgeHeight", PyFloat_FromDouble(getToolPtr()->CuttingEdgeHeight)); + return dict; + } + throw Py::TypeError("This method accepts no argument"); +} + +PyObject* ToolPy::getToolTypes(PyObject * args) +{ + if (PyArg_ParseTuple(args, "")) { + std::vector toolTypes = Tool::ToolTypes(); + PyObject *list = PyList_New(0); + for(unsigned i = 0; i != toolTypes.size(); i++) { + + PyList_Append(list, PYSTRING_FROMSTRING(toolTypes[i].c_str())); + } + return list; + } + throw Py::TypeError("This method accepts no argument"); +} + +PyObject* ToolPy::getToolMaterials(PyObject * args) +{ + if (PyArg_ParseTuple(args, "")) { + std::vector toolMaterials = Tool::ToolMaterials(); + PyObject *list = PyList_New(0); + for(unsigned i = 0; i != toolMaterials.size(); i++) { + + PyList_Append(list, PYSTRING_FROMSTRING(toolMaterials[i].c_str())); + } + return list; + } + throw Py::TypeError("This method accepts no argument"); +} \ No newline at end of file diff --git a/src/Mod/Path/App/Tooltable.cpp b/src/Mod/Path/App/Tooltable.cpp index 85cfc89cd7..3fe036760a 100644 --- a/src/Mod/Path/App/Tooltable.cpp +++ b/src/Mod/Path/App/Tooltable.cpp @@ -31,242 +31,10 @@ #include #include "Tooltable.h" + using namespace Base; using namespace Path; - -// TOOL - - -TYPESYSTEM_SOURCE(Path::Tool , Base::Persistence); - -// Constructors & destructors - -Tool::Tool(const char* name, - ToolType type, - ToolMaterial /*material*/, - double diameter, - double lengthoffset, - double flatradius, - double cornerradius, - double cuttingedgeangle, - double cuttingedgeheight) -:Name(name),Type(type),Material(MATUNDEFINED),Diameter(diameter),LengthOffset(lengthoffset), -FlatRadius(flatradius),CornerRadius(cornerradius),CuttingEdgeAngle(cuttingedgeangle), -CuttingEdgeHeight(cuttingedgeheight) -{ -} - -Tool::Tool() -{ - Type = UNDEFINED; - Material = MATUNDEFINED; - Diameter = 0; - LengthOffset = 0; - FlatRadius = 0; - CornerRadius = 0; - CuttingEdgeAngle = 180; - CuttingEdgeHeight = 0; -} - -Tool::~Tool() -{ -} - -// Reimplemented from base class - -unsigned int Tool::getMemSize (void) const -{ - return 0; -} - -void Tool::Save (Writer &writer) const -{ - writer.Stream() << writer.ind() << "" << std::endl; -} - -void Tool::Restore(XMLReader &reader) -{ - reader.readElement("Tool"); - Name = reader.getAttribute("name"); - Diameter = reader.hasAttribute("diameter") ? (double) reader.getAttributeAsFloat("diameter") : 0.0; - LengthOffset = reader.hasAttribute("length") ? (double) reader.getAttributeAsFloat("length") : 0.0; - FlatRadius = reader.hasAttribute("flat") ? (double) reader.getAttributeAsFloat("flat") : 0.0; - CornerRadius = reader.hasAttribute("corner") ? (double) reader.getAttributeAsFloat("corner") : 0.0; - CuttingEdgeAngle = reader.hasAttribute("angle") ? (double) reader.getAttributeAsFloat("angle") : 180.0; - CuttingEdgeHeight = reader.hasAttribute("height") ? (double) reader.getAttributeAsFloat("height") : 0.0; - std::string type = reader.hasAttribute("type") ? reader.getAttribute("type") : ""; - std::string mat = reader.hasAttribute("mat") ? reader.getAttribute("mat") : ""; - - Type = getToolType(type); - Material = getToolMaterial(mat); - - -} - -const std::vector Tool::ToolTypes(void) -{ - std::vector toolTypes(13); - toolTypes[0] ="EndMill"; - toolTypes[1] ="Drill"; - toolTypes[2] ="CenterDrill"; - toolTypes[3] ="CounterSink"; - toolTypes[4] ="CounterBore"; - toolTypes[5] ="FlyCutter"; - toolTypes[6] ="Reamer"; - toolTypes[7] ="Tap"; - toolTypes[8] ="SlotCutter"; - toolTypes[9] ="BallEndMill"; - toolTypes[10] ="ChamferMill"; - toolTypes[11] ="CornerRound"; - toolTypes[12] ="Engraver"; - return toolTypes; - -} - -const std::vector Tool::ToolMaterials(void) -{ - std::vector toolMat(7); - toolMat[0] ="Carbide"; - toolMat[1] ="HighSpeedSteel"; - toolMat[2] ="HighCarbonToolSteel"; - toolMat[3] ="CastAlloy"; - toolMat[4] ="Ceramics"; - toolMat[5] ="Diamond"; - toolMat[6] ="Sialon"; - return toolMat; - -} - -Tool::ToolType Tool::getToolType(std::string type) -{ - Tool::ToolType Type; - if(type=="EndMill") - Type = Tool::ENDMILL; - else if(type=="Drill") - Type = Tool::DRILL; - else if(type=="CenterDrill") - Type = Tool::CENTERDRILL; - else if(type=="CounterSink") - Type = Tool::COUNTERSINK; - else if(type=="CounterBore") - Type = Tool::COUNTERBORE; - else if(type=="FlyCutter") - Type = Tool::FLYCUTTER; - else if(type=="Reamer") - Type = Tool::REAMER; - else if(type=="Tap") - Type = Tool::TAP; - else if(type=="SlotCutter") - Type = Tool::SLOTCUTTER; - else if(type=="BallEndMill") - Type = Tool::BALLENDMILL; - else if(type=="ChamferMill") - Type = Tool::CHAMFERMILL; - else if(type=="CornerRound") - Type = Tool::CORNERROUND; - else if(type=="Engraver") - Type = Tool::ENGRAVER; - else - Type = Tool::UNDEFINED; - - return Type; -} - -Tool::ToolMaterial Tool::getToolMaterial(std::string mat) -{ - Tool::ToolMaterial Material; - if(mat=="Carbide") - Material = Tool::CARBIDE; - else if(mat=="HighSpeedSteel") - Material = Tool::HIGHSPEEDSTEEL; - else if(mat=="HighCarbonToolSteel") - Material = Tool::HIGHCARBONTOOLSTEEL; - else if(mat=="CastAlloy") - Material = Tool::CASTALLOY; - else if(mat=="Ceramics") - Material = Tool::CERAMICS; - else if(mat=="Diamond") - Material = Tool::DIAMOND; - else if(mat=="Sialon") - Material = Tool::SIALON; - else - Material = Tool::MATUNDEFINED; - - return Material; -} - -const char* Tool::TypeName(Tool::ToolType typ) { - switch (typ) { - case Tool::DRILL: - return "Drill"; - case Tool::CENTERDRILL: - return "CenterDrill"; - case Tool::COUNTERSINK: - return "CounterSink"; - case Tool::COUNTERBORE: - return "CounterBore"; - case Tool::FLYCUTTER: - return "FlyCutter"; - case Tool::REAMER: - return "Reamer"; - case Tool::TAP: - return "Tap"; - case Tool::ENDMILL: - return "EndMill"; - case Tool::SLOTCUTTER: - return "SlotCutter"; - case Tool::BALLENDMILL: - return "BallEndMill"; - case Tool::CHAMFERMILL: - return "ChamferMill"; - case Tool::CORNERROUND: - return "CornerRound"; - case Tool::ENGRAVER: - return "Engraver"; - case Tool::UNDEFINED: - return "Undefined"; - } - return "Undefined"; -} - -const char* Tool::MaterialName(Tool::ToolMaterial mat) -{ - switch (mat) { - case Tool::HIGHSPEEDSTEEL: - return "HighSpeedSteel"; - case Tool::CARBIDE: - return "Carbide"; - case Tool::HIGHCARBONTOOLSTEEL: - return "HighCarbonToolSteel"; - case Tool::CASTALLOY: - return "CastAlloy"; - case Tool::CERAMICS: - return "Ceramics"; - case Tool::DIAMOND: - return "Diamond"; - case Tool::SIALON: - return "Sialon"; - case Tool::MATUNDEFINED: - return "Undefined"; - } - return "Undefined"; -} - -// TOOLTABLE - - - TYPESYSTEM_SOURCE(Path::Tooltable , Base::Persistence); Tooltable::Tooltable() diff --git a/src/Mod/Path/App/Tooltable.h b/src/Mod/Path/App/Tooltable.h index 450ea826b2..13a051704e 100644 --- a/src/Mod/Path/App/Tooltable.h +++ b/src/Mod/Path/App/Tooltable.h @@ -28,80 +28,10 @@ #include #include #include +#include "Tool.h" namespace Path -{ - - /** The representation of a single tool */ - class PathExport Tool : public Base::Persistence - { - TYPESYSTEM_HEADER(); - - public: - enum ToolType { - UNDEFINED, - DRILL, - CENTERDRILL, - COUNTERSINK, - COUNTERBORE, - FLYCUTTER, - REAMER, - TAP, - ENDMILL, - SLOTCUTTER, - BALLENDMILL, - CHAMFERMILL, - CORNERROUND, - ENGRAVER }; - - enum ToolMaterial { - MATUNDEFINED, - HIGHSPEEDSTEEL, - HIGHCARBONTOOLSTEEL, - CASTALLOY, - CARBIDE, - CERAMICS, - DIAMOND, - SIALON }; - - //constructors - Tool(); - Tool(const char* name, - ToolType type=Tool::UNDEFINED, - ToolMaterial material=Tool::MATUNDEFINED, - double diameter=10.0, - double lengthoffset=100, - double flatradius=0, - double cornerradius=0, - double cuttingedgeangle=0, - double cuttingedgeheight=0); - ~Tool(); - - // from base class - virtual unsigned int getMemSize (void) const; - virtual void Save (Base::Writer &/*writer*/) const; - virtual void Restore(Base::XMLReader &/*reader*/); - - // attributes - std::string Name; - ToolType Type; - ToolMaterial Material; - double Diameter; - double LengthOffset; - double FlatRadius; - double CornerRadius; - double CuttingEdgeAngle; - double CuttingEdgeHeight; - - static const std::vector ToolTypes(void); - static const std::vector ToolMaterials(void); - static const char* TypeName(ToolType typ); - static ToolType getToolType(std::string type); - static ToolMaterial getToolMaterial(std::string mat); - static const char* MaterialName(ToolMaterial mat); - }; - - /** The representation of a table of tools */ +{ /** The representation of a table of tools */ class PathExport Tooltable : public Base::Persistence { TYPESYSTEM_HEADER(); diff --git a/src/Mod/Path/App/TooltablePyImp.cpp b/src/Mod/Path/App/TooltablePyImp.cpp index 756ef0a23a..05bcb0bf91 100644 --- a/src/Mod/Path/App/TooltablePyImp.cpp +++ b/src/Mod/Path/App/TooltablePyImp.cpp @@ -23,231 +23,17 @@ #include "PreCompiled.h" #include "Base/Reader.h" +#include "Mod/Path/App/Tool.h" #include "Mod/Path/App/Tooltable.h" // inclusion of the generated files (generated out of ToolPy.xml and TooltablePy.xml) #include "ToolPy.h" -#include "ToolPy.cpp" +//#include "ToolPy.cpp" #include "TooltablePy.h" #include "TooltablePy.cpp" using namespace Path; - - -// ToolPy - - - -// returns a string which represents the object e.g. when printed in python -std::string ToolPy::representation(void) const -{ - std::stringstream str; - str.precision(5); - str << "Tool "; - str << getToolPtr()->Name; - return str.str(); -} - -PyObject *ToolPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper -{ - // create a new instance of ToolPy and the Twin object - return new ToolPy(new Tool); -} - -// constructor method -int ToolPy::PyInit(PyObject* args, PyObject* kwd) -{ - char *name="Default tool"; - char *type = "Undefined"; - char *mat = "Undefined"; - PyObject *dia = 0; - PyObject *len = 0; - PyObject *fla = 0; - PyObject *cor = 0; - PyObject *ang = 0; - PyObject *hei = 0; - int version = 1; - - static char *kwlist[] = {"name", "tooltype", "material", "diameter", "lengthOffset", "flatRadius", "cornerRadius", "cuttingEdgeAngle", "cuttingEdgeHeight" , "version", NULL}; - - PyObject *dict = 0; - if (!kwd && (PyObject_TypeCheck(args, &PyDict_Type) || PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict))) { - static PyObject *arg = PyTuple_New(0); - if (PyObject_TypeCheck(args, &PyDict_Type)) { - dict = args; - } - if (!PyArg_ParseTupleAndKeywords(arg, dict, "|sssOOOOOOi", kwlist, &name, &type, &mat, &dia, &len, &fla, &cor, &ang, &hei, &version)) { - return -1; - } - } else { - PyErr_Clear(); - if (!PyArg_ParseTupleAndKeywords(args, kwd, "|sssOOOOOO", kwlist, &name, &type, &mat, &dia, &len, &fla, &cor, &ang, &hei)) { - return -1; - } - } - - if (1 != version) { - PyErr_SetString(PyExc_TypeError, "Unsupported Tool template version"); - return -1; - } - - getToolPtr()->Name = name; - - std::string typeStr(type); - getToolPtr()->Type = Tool::getToolType(typeStr); - - std::string matStr(mat); - getToolPtr()->Material = Tool::getToolMaterial(matStr); - - getToolPtr()->Diameter = dia ? PyFloat_AsDouble(dia) : 0.0; - getToolPtr()->LengthOffset = len ? PyFloat_AsDouble(len) : 0.0; - getToolPtr()->FlatRadius = fla ? PyFloat_AsDouble(fla) : 0.0; - getToolPtr()->CornerRadius = cor ? PyFloat_AsDouble(cor) : 0.0; - getToolPtr()->CuttingEdgeAngle = ang ? PyFloat_AsDouble(ang) : 180.0; - getToolPtr()->CuttingEdgeHeight = hei ? PyFloat_AsDouble(hei) : 0.0; - - return 0; -} - -// attributes get/setters - -Py::String ToolPy::getName(void) const -{ - return Py::String(getToolPtr()->Name.c_str()); -} - -void ToolPy::setName(Py::String arg) -{ - std::string name = arg.as_std_string(); - getToolPtr()->Name = name; -} - -Py::String ToolPy::getToolType(void) const -{ - return Py::String(Tool::TypeName(getToolPtr()->Type)); -} - -void ToolPy::setToolType(Py::String arg) -{ - std::string typeStr(arg.as_std_string()); - getToolPtr()->Type = Tool::getToolType(typeStr); - -} - -Py::String ToolPy::getMaterial(void) const -{ - return Py::String(Tool::MaterialName(getToolPtr()->Material)); -} - -void ToolPy::setMaterial(Py::String arg) -{ - std::string matStr(arg.as_std_string()); - getToolPtr()->Material = Tool::getToolMaterial(matStr); -} - -Py::Float ToolPy::getDiameter(void) const -{ - return Py::Float(getToolPtr()->Diameter); -} - -void ToolPy::setDiameter(Py::Float arg) -{ - getToolPtr()->Diameter = arg.operator double(); -} - -Py::Float ToolPy::getLengthOffset(void) const -{ - return Py::Float(getToolPtr()->LengthOffset); -} - -void ToolPy::setLengthOffset(Py::Float arg) -{ - getToolPtr()->LengthOffset = arg.operator double(); -} - -Py::Float ToolPy::getFlatRadius(void) const -{ - return Py::Float(getToolPtr()->FlatRadius); -} - -void ToolPy::setFlatRadius(Py::Float arg) -{ - getToolPtr()->FlatRadius = arg.operator double(); -} - -Py::Float ToolPy::getCornerRadius(void) const -{ - return Py::Float(getToolPtr()->CornerRadius); -} - -void ToolPy::setCornerRadius(Py::Float arg) -{ - getToolPtr()->CornerRadius = arg.operator double(); -} - -Py::Float ToolPy::getCuttingEdgeAngle(void) const -{ - return Py::Float(getToolPtr()->CuttingEdgeAngle); -} - -void ToolPy::setCuttingEdgeAngle(Py::Float arg) -{ - getToolPtr()->CuttingEdgeAngle = arg.operator double(); -} - -Py::Float ToolPy::getCuttingEdgeHeight(void) const -{ - return Py::Float(getToolPtr()->CuttingEdgeHeight); -} - -void ToolPy::setCuttingEdgeHeight(Py::Float arg) -{ - getToolPtr()->CuttingEdgeHeight = arg.operator double(); -} - -// custom attributes get/set - -PyObject *ToolPy::getCustomAttributes(const char* /*attr*/) const -{ - return 0; -} - -int ToolPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) -{ - return 0; -} - -PyObject* ToolPy::copy(PyObject * args) -{ - if (PyArg_ParseTuple(args, "")) { - return new ToolPy(new Path::Tool(*getToolPtr())); - } - throw Py::TypeError("This method accepts no argument"); -} - -PyObject* ToolPy::setFromTemplate(PyObject * args) -{ - char *pstr = 0; - if (PyArg_ParseTuple(args, "s", &pstr)) { - // embed actual string in dummy tag so XMLReader can consume that on construction - std::ostringstream os; - os << "" << pstr << ""; - std::istringstream is(os.str()); - Base::XMLReader reader("", is); - getToolPtr()->Restore(reader); - Py_Return ; - } - - PyErr_Clear(); - if (!PyInit(args, 0)) { - Py_Return ; - } - - PyErr_SetString(PyExc_TypeError, "argument must be a string or dictionary"); - return 0; -} - #if PY_MAJOR_VERSION >= 3 # define PYSTRING_FROMSTRING(str) PyUnicode_FromString(str) # define PYINT_TYPE PyLong_Type @@ -260,59 +46,6 @@ PyObject* ToolPy::setFromTemplate(PyObject * args) # define PYINT_ASLONG(o) PyInt_AsLong(o) #endif -PyObject* ToolPy::templateAttrs(PyObject * args) -{ - if (!args || PyArg_ParseTuple(args, "")) { - PyObject *dict = PyDict_New(); - PyDict_SetItemString(dict, "version", PYINT_FROMLONG(1)); - PyDict_SetItemString(dict, "name", PYSTRING_FROMSTRING(getToolPtr()->Name.c_str())); - PyDict_SetItemString(dict, "tooltype",PYSTRING_FROMSTRING(Tool::TypeName(getToolPtr()->Type))); - PyDict_SetItemString(dict, "material", PYSTRING_FROMSTRING(Tool::MaterialName(getToolPtr()->Material))); - PyDict_SetItemString(dict, "diameter", PyFloat_FromDouble(getToolPtr()->Diameter)); - PyDict_SetItemString(dict, "lengthOffset", PyFloat_FromDouble(getToolPtr()->LengthOffset)); - PyDict_SetItemString(dict, "flatRadius", PyFloat_FromDouble(getToolPtr()->FlatRadius)); - PyDict_SetItemString(dict, "cornerRadius", PyFloat_FromDouble(getToolPtr()->CornerRadius)); - PyDict_SetItemString(dict, "cuttingEdgeAngle", PyFloat_FromDouble(getToolPtr()->CuttingEdgeAngle)); - PyDict_SetItemString(dict, "cuttingEdgeHeight", PyFloat_FromDouble(getToolPtr()->CuttingEdgeHeight)); - return dict; - } - throw Py::TypeError("This method accepts no argument"); -} - -PyObject* ToolPy::getToolTypes(PyObject * args) -{ - if (PyArg_ParseTuple(args, "")) { - std::vector toolTypes = Tool::ToolTypes(); - PyObject *list = PyList_New(0); - for(unsigned i = 0; i != toolTypes.size(); i++) { - - PyList_Append(list, PYSTRING_FROMSTRING(toolTypes[i].c_str())); - } - return list; - } - throw Py::TypeError("This method accepts no argument"); -} - -PyObject* ToolPy::getToolMaterials(PyObject * args) -{ - if (PyArg_ParseTuple(args, "")) { - std::vector toolMaterials = Tool::ToolMaterials(); - PyObject *list = PyList_New(0); - for(unsigned i = 0; i != toolMaterials.size(); i++) { - - PyList_Append(list, PYSTRING_FROMSTRING(toolMaterials[i].c_str())); - } - return list; - } - throw Py::TypeError("This method accepts no argument"); -} - - -// TooltablePy - - - - // returns a string which represents the object e.g. when printed in python std::string TooltablePy::representation(void) const { From 3876a5989d276708cfe8625f98799afb63784007 Mon Sep 17 00:00:00 2001 From: Dubstar_04 Date: Tue, 20 Aug 2019 20:41:53 +0100 Subject: [PATCH 02/23] Tidy up includes and whitespace --- src/Mod/Path/App/Tool.cpp | 6 ------ src/Mod/Path/App/Tool.h | 1 - src/Mod/Path/App/ToolPyImp.cpp | 2 -- src/Mod/Path/App/Tooltable.cpp | 1 - src/Mod/Path/App/TooltablePyImp.cpp | 1 - 5 files changed, 11 deletions(-) diff --git a/src/Mod/Path/App/Tool.cpp b/src/Mod/Path/App/Tool.cpp index 62a571d821..288626911e 100644 --- a/src/Mod/Path/App/Tool.cpp +++ b/src/Mod/Path/App/Tool.cpp @@ -20,7 +20,6 @@ * * ***************************************************************************/ - #include "PreCompiled.h" #ifndef _PreComp_ @@ -34,10 +33,6 @@ using namespace Base; using namespace Path; - -// TOOL - - TYPESYSTEM_SOURCE(Path::Tool , Base::Persistence); // Constructors & destructors @@ -74,7 +69,6 @@ Tool::~Tool() } // Reimplemented from base class - unsigned int Tool::getMemSize (void) const { return 0; diff --git a/src/Mod/Path/App/Tool.h b/src/Mod/Path/App/Tool.h index f06ef2bb35..c8a5690fc3 100644 --- a/src/Mod/Path/App/Tool.h +++ b/src/Mod/Path/App/Tool.h @@ -20,7 +20,6 @@ * * ***************************************************************************/ - #ifndef PATH_TOOL_H #define PATH_TOOL_H diff --git a/src/Mod/Path/App/ToolPyImp.cpp b/src/Mod/Path/App/ToolPyImp.cpp index 57d4e87d95..c075d2c786 100644 --- a/src/Mod/Path/App/ToolPyImp.cpp +++ b/src/Mod/Path/App/ToolPyImp.cpp @@ -29,8 +29,6 @@ // inclusion of the generated files (generated out of ToolPy.xml and TooltablePy.xml) #include "ToolPy.h" #include "ToolPy.cpp" -//#include "TooltablePy.h" -//#include "TooltablePy.cpp" using namespace Path; diff --git a/src/Mod/Path/App/Tooltable.cpp b/src/Mod/Path/App/Tooltable.cpp index 3fe036760a..a9351899e9 100644 --- a/src/Mod/Path/App/Tooltable.cpp +++ b/src/Mod/Path/App/Tooltable.cpp @@ -31,7 +31,6 @@ #include #include "Tooltable.h" - using namespace Base; using namespace Path; diff --git a/src/Mod/Path/App/TooltablePyImp.cpp b/src/Mod/Path/App/TooltablePyImp.cpp index 05bcb0bf91..8c346ebc08 100644 --- a/src/Mod/Path/App/TooltablePyImp.cpp +++ b/src/Mod/Path/App/TooltablePyImp.cpp @@ -28,7 +28,6 @@ // inclusion of the generated files (generated out of ToolPy.xml and TooltablePy.xml) #include "ToolPy.h" -//#include "ToolPy.cpp" #include "TooltablePy.h" #include "TooltablePy.cpp" From f9a591b06d4c1a1c5320df374b9ca85fe1ee3f3f Mon Sep 17 00:00:00 2001 From: Dubstar_04 Date: Fri, 23 Aug 2019 22:13:04 +0100 Subject: [PATCH 03/23] Allow multiple Tool Tables Allow path to hold multiple tool tables --- src/Mod/Path/App/Tooltable.h | 3 + src/Mod/Path/App/TooltablePy.xml | 12 + src/Mod/Path/App/TooltablePyImp.cpp | 23 + .../Gui/Resources/panels/ToolLibraryEditor.ui | 208 +++++++- .../PathScripts/PathToolLibraryManager.py | 487 +++++++++++++----- 5 files changed, 579 insertions(+), 154 deletions(-) diff --git a/src/Mod/Path/App/Tooltable.h b/src/Mod/Path/App/Tooltable.h index 13a051704e..77112398f5 100644 --- a/src/Mod/Path/App/Tooltable.h +++ b/src/Mod/Path/App/Tooltable.h @@ -50,6 +50,7 @@ namespace Path void addTool(const Tool &tool); // adds a tool at the end void setTool(const Tool &tool, int); // inserts a tool void deleteTool(int); // deletes a tool + //void setVersion(int); //set the table version // auto unsigned int getSize(void) const {return Tools.size();} @@ -59,6 +60,8 @@ namespace Path // attributes std::map Tools; + int Version; + std::string Name; }; } //namespace Path diff --git a/src/Mod/Path/App/TooltablePy.xml b/src/Mod/Path/App/TooltablePy.xml index 39230d35cb..0480a83b03 100644 --- a/src/Mod/Path/App/TooltablePy.xml +++ b/src/Mod/Path/App/TooltablePy.xml @@ -15,6 +15,18 @@ The Tooltable object holds a table of CNC tools + + + the name of this tool table + + + + + + the version of this tooltable + + + the dictionary of tools of this table diff --git a/src/Mod/Path/App/TooltablePyImp.cpp b/src/Mod/Path/App/TooltablePyImp.cpp index 8c346ebc08..bb03bd8649 100644 --- a/src/Mod/Path/App/TooltablePyImp.cpp +++ b/src/Mod/Path/App/TooltablePyImp.cpp @@ -63,6 +63,9 @@ PyObject *TooltablePy::PyMake(struct _typeobject *, PyObject *, PyObject *) // // constructor method int TooltablePy::PyInit(PyObject* args, PyObject* /*kwd*/) { + char *name="Tooltable"; + int version = 1; + if (PyArg_ParseTuple(args, "")) { return 0; } @@ -234,6 +237,25 @@ int TooltablePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) return 0; } +Py::Int TooltablePy::getVersion(void) const +{ + return Py::Int(getTooltablePtr()->Version); +} + +void TooltablePy::setVersion(Py::Int version) { + getTooltablePtr()->Version = version; +} + +Py::String TooltablePy::getName(void) const +{ + return Py::String(getTooltablePtr()->Name.c_str()); +} + +void TooltablePy::setName(Py::String arg) +{ + std::string name = arg.as_std_string(); + getTooltablePtr()->Name = name; +} PyObject* TooltablePy::setFromTemplate(PyObject * args) { @@ -263,3 +285,4 @@ PyObject* TooltablePy::templateAttrs(PyObject * args) } return dict; } + diff --git a/src/Mod/Path/Gui/Resources/panels/ToolLibraryEditor.ui b/src/Mod/Path/Gui/Resources/panels/ToolLibraryEditor.ui index 01657469c4..ed3cdf6bd5 100644 --- a/src/Mod/Path/Gui/Resources/panels/ToolLibraryEditor.ui +++ b/src/Mod/Path/Gui/Resources/panels/ToolLibraryEditor.ui @@ -19,8 +19,8 @@ Tool Library - - + + @@ -38,32 +38,184 @@ - - - - true - - - QAbstractItemView::DragOnly - - - true - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - false - - - false - - + + + + + + + 225 + 16777215 + + + + + 0 + + + 0 + + + 6 + + + 0 + + + + + + + Tool Tables + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + 32 + 32 + + + + + + + + :/icons/FreeCAD-default/scalable/edit-edit.svg:/icons/FreeCAD-default/scalable/edit-edit.svg + + + + + + + + 32 + 32 + + + + + + + + :/icons/FreeCAD-default/scalable/list-remove.svg + + + + + + + + + 32 + 32 + + + + + + + + :/icons/FreeCAD-default/scalable/list-add.svg + + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 0 + 0 + + + + true + + + + 20 + 20 + + + + + + + + + + + false + + + false + + + QAbstractItemView::NoDragDrop + + + Qt::IgnoreAction + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + true + + + false + + + false + + + + - + @@ -140,7 +292,7 @@ - + Qt::Horizontal diff --git a/src/Mod/Path/PathScripts/PathToolLibraryManager.py b/src/Mod/Path/PathScripts/PathToolLibraryManager.py index 9580f60d25..afeec84318 100644 --- a/src/Mod/Path/PathScripts/PathToolLibraryManager.py +++ b/src/Mod/Path/PathScripts/PathToolLibraryManager.py @@ -145,6 +145,8 @@ class ToolLibraryManager(): preferences and all or part of the library can be exported to other formats ''' + #TODO: copy & Duplicate tools between lists + TooltableTypeJSON = translate("TooltableEditor", "Tooltable JSON (*.json)") TooltableTypeXML = translate("TooltableEditor", "Tooltable XML (*.xml)") TooltableTypeHeekscad = translate("TooltableEditor", "HeeksCAD tooltable (*.tooltable)") @@ -155,75 +157,194 @@ class ToolLibraryManager(): def __init__(self): self.prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Path") + self.toolTables = [] + self.currentTableName = None + self.loadToolTables() + + if len(self.toolTables): + self.currentTableName = self.toolTables[0].Name + return - def templateAttrs(self, tooltable): - attrs = {} - attrs['Version'] = 1 - attrs['Tools'] = tooltable.templateAttrs() - return attrs + def getCurrentTableName(self): + ''' return the name of the currently loaded tool table ''' + return self.currentTableName + + def getCurrentTable(self): + ''' returns an object of the current tool table ''' + return self.getTableFromName(self.currentTableName) + + def getTableFromName(self, name): + ''' get the tool table object from the name ''' + for table in self.toolTables: + if table.Name == name: + return table + + def getNextToolTableName(self): + ''' get a unique name for a new tool table ''' + iter = 1 + tableNames = [] + + for table in self.toolTables: + tableNames.append(table.Name) + + while "ToolTable-" + str(iter) in tableNames: + iter += 1 + + return "ToolTable-" + str(iter) + + def addNewToolTable(self): + ''' creates a new tool table ''' + tt = Path.Tooltable() + tt.Version = 1 + name = self.getNextToolTableName() + tt.Name = name + self.toolTables.append(tt) + self.saveMainLibrary() + return name + + def deleteToolTable(self): + ''' deletes the selected tool table ''' + index = next((index for (index, d) in enumerate(self.toolTables) if d.Name == self.currentTableName), None) + self.toolTables.pop(index) + self.saveMainLibrary() + + def renameToolTable(self, newName, index): + ''' renames a tool table with the new name''' + currentTableName = self.toolTables[index].Name + if newName == currentTableName: + PathLog.error(translate('PathToolLibraryManager', "Tool Table Same Name")) + return False + if newName in self.toolTables: + PathLog.error(translate('PathToolLibraryManager', "Tool Table Name Exists")) + return False + tt = self.getTableFromName(currentTableName) + if tt: + tt.Name = newName + self.saveMainLibrary() + return True + + + def templateAttrs(self): + ''' gets the tool table arributes ''' + toolTables = [] + for tt in self.toolTables: + tableData = {} + tableData['Version'] = 1 + tableData['TableName'] = tt.Name + + toolData = {} + for tool in tt.Tools: + toolData[tool] = tt.Tools[tool].templateAttrs() + + tableData['Tools'] = toolData + toolTables.append(tableData) + + return toolTables def tooltableFromAttrs(self, stringattrs): if stringattrs.get('Version') and 1 == int(stringattrs['Version']): - attrs = {} - for key, val in PathUtil.keyValueIter(stringattrs['Tools']): - attrs[int(key)] = val - return Path.Tooltable(attrs) + + tt = Path.Tooltable() + tt.Version = 1 + + if stringattrs.get('Version'): + tt.Version = stringattrs.get('Version') + + if stringattrs.get('TableName'): + tt.Name = stringattrs.get('TableName') + + for key, attrs in PathUtil.keyValueIter(stringattrs['Tools']): + tool = Path.Tool() + tool.Name = str(attrs["name"]) + tool.ToolType = str(attrs["tooltype"]) + tool.Material = str(attrs["material"]) + tool.Diameter = float(attrs["diameter"]) + tool.LengthOffset = float(attrs["lengthOffset"]) + tool.FlatRadius = float(attrs["flatRadius"]) + tool.CornerRadius = float(attrs["cornerRadius"]) + tool.CuttingEdgeAngle = float(attrs["cuttingEdgeAngle"]) + tool.CuttingEdgeHeight = float(attrs["cuttingEdgeHeight"]) + tt.setTool(int(key), tool) + + return tt else: PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable template version %s") % stringattrs.get('Version')) return None - def saveMainLibrary(self, tooltable): + def loadToolTables(self): + ''' loads the tool tables from tehe stored data ''' + self.toolTables = [] + self.currentTableName = '' + + for table in json.loads(self.prefs.GetString(self.PreferenceMainLibraryJSON, "")): + + tt = self.tooltableFromAttrs(table) + if tt: + self.toolTables.append(tt) + else: + PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable")) + + def saveMainLibrary(self): '''Persists the permanent library to FreeCAD user preferences''' - tmpstring = json.dumps(self.templateAttrs(tooltable)) + tmpstring = json.dumps(self.templateAttrs()) self.prefs.SetString(self.PreferenceMainLibraryJSON, tmpstring) + self.loadToolTables() return True def getLists(self): '''Builds the list of all Tool Table lists''' - tablelist = [] - toollist = "
" - tablelist.append(toollist) - + tablelist = self.toolTables.copy() + #TODO load a tool table for current job? # Get ToolTables from any open CNC jobs - for o in FreeCAD.ActiveDocument.Objects: - if hasattr(o, "Proxy"): - if isinstance(o.Proxy, PathScripts.PathJob.ObjectJob): - tablelist.append(o.Label) + # for o in FreeCAD.ActiveDocument.Objects: + # if hasattr(o, "Proxy"): + # if isinstance(o.Proxy, PathScripts.PathJob.ObjectJob): + # tablelist.append(o.Label) return tablelist - def _findList(self, listname): - tt = None - if listname == "
": - tmpstring = self.prefs.GetString(self.PreferenceMainLibraryJSON, "") - if not tmpstring: - tmpstring = self.prefs.GetString(self.PreferenceMainLibraryXML, "") - if tmpstring: - if tmpstring[0] == '{': - tt = self.tooltableFromAttrs(json.loads(tmpstring)) - elif tmpstring[0] == '<': - # legacy XML table - Handler = FreeCADTooltableHandler() - xml.sax.parseString(tmpstring, Handler) - tt = Handler.tooltable - # store new format - self.saveMainLibrary(tt) - else: - tt = Path.Tooltable() - else: - for o in FreeCAD.ActiveDocument.Objects: - if o.Label == listname: - tt = o.Tooltable - return tt + # def _findList(self, listname): + # tt = None + # if listname == self.getCurrentTableName(): + # #print("Findlist - ListName:", listname) + # return self.getCurrentTable() + # else: + # tmpstring = self.prefs.GetString(self.PreferenceMainLibraryJSON, "") + # if not tmpstring: + # tmpstring = self.prefs.GetString(self.PreferenceMainLibraryXML, "") + # if tmpstring: + # if tmpstring[0] == '{': + # tt = self.tooltableFromAttrs(json.loads(tmpstring)) + # elif tmpstring[0] == '<': + # # legacy XML table + # Handler = FreeCADTooltableHandler() + # xml.sax.parseString(tmpstring, Handler) + # tt = Handler.tooltable + # # store new format + # self.saveMainLibrary() + # else: + # tt = Path.Tooltable() + # # else: + # # for o in FreeCAD.ActiveDocument.Objects: + # # if o.Label == listname: + # # tt = o.Tooltable + # return tt def getTool(self, listname, toolnum): - tt = self._findList(listname) + ''' gets the tool object ''' + tt = self.getTableFromName(listname) return tt.getTool(toolnum) def getTools(self, tablename): '''returns the tool data for a given table''' tooldata = [] - tt = self._findList(tablename) + tableExists = any(table.Name == tablename for table in self.toolTables) + if tableExists: + self.currentTableName = tablename + else: + return None + + tt = self.getTableFromName(tablename) headers = ["","Tool Num.","Name","Tool Type","Material","Diameter","Length Offset","Flat Radius","Corner Radius","Cutting Edge Angle","Cutting Edge Height"] model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(headers) @@ -247,11 +368,11 @@ class ToolLibraryManager(): itemDiameter = QtGui.QStandardItem(unitconv(t.Diameter)) itemLengthOffset = QtGui.QStandardItem(unitconv(t.LengthOffset)) itemFlatRadius = QtGui.QStandardItem(unitconv(t.FlatRadius)) - itmCornerRadius = QtGui.QStandardItem(unitconv(t.CornerRadius)) + itemCornerRadius = QtGui.QStandardItem(unitconv(t.CornerRadius)) itemCuttingEdgeAngle = QtGui.QStandardItem(str(t.CuttingEdgeAngle)) itemCuttingEdgeHeight = QtGui.QStandardItem(unitconv(t.CuttingEdgeHeight)) - row = [itemcheck, itemNumber, itemName, itemToolType, itemMaterial, itemDiameter, itemLengthOffset, itemFlatRadius, itmCornerRadius, itemCuttingEdgeAngle, itemCuttingEdgeHeight] + row = [itemcheck, itemNumber, itemName, itemToolType, itemMaterial, itemDiameter, itemLengthOffset, itemFlatRadius, itemCornerRadius, itemCuttingEdgeAngle, itemCuttingEdgeHeight] model.appendRow(row) return model @@ -281,12 +402,12 @@ class ToolLibraryManager(): with open(PathUtil.toUnicode(filename[0]), "rb") as fp: ht = self.tooltableFromAttrs(json.load(fp)) - tt = self._findList(listname) + tt = self.getTableFromName(listname) for t in ht.Tools: newt = ht.getTool(t).copy() tt.addTools(newt) - if listname == "
": - self.saveMainLibrary(tt) + if listname == self.getCurrentTableName(): + self.saveMainLibrary() return True except Exception as e: # pylint: disable=broad-except print("could not parse file", e) @@ -294,7 +415,7 @@ class ToolLibraryManager(): def write(self, filename, listname): "exports the tooltable to a file" - tt = self._findList(listname) + tt = self.getTableFromName(listname) if tt: try: def openFileWithExtension(name, ext): @@ -314,7 +435,7 @@ class ToolLibraryManager(): fp.write("T{0} P{0} Y{1} Z{2} A{3} B{4} C{5} U{6} V{7} W{8} D{9} I{10} J{11} Q{12} ;{13}\n".format(key,0,t.LengthOffset,0,0,0,0,0,0,t.Diameter,0,0,0,t.Name)) else: fp,fname = openFileWithExtension(filename[0], '.json') - json.dump(self.templateAttrs(tt), fp, sort_keys=True, indent=2) + json.dump(self.templateAttrs(), fp, sort_keys=True, indent=2) fp.close() print("Written ", PathUtil.toUnicode(fname)) @@ -324,8 +445,7 @@ class ToolLibraryManager(): def addnew(self, listname, tool, position = None): "adds a new tool at the end of the table" - print(listname, tool, position) - tt = self._findList(listname) + tt = self.getTableFromName(listname) if not tt: tt = Path.Tooltable() if position is None: @@ -335,26 +455,26 @@ class ToolLibraryManager(): tt.setTool(position, tool) newID = position - if listname == "
": - return self.saveMainLibrary(tt) + if listname == self.getCurrentTableName(): + self.saveMainLibrary() return newID def updateTool(self, listname, toolnum, tool): '''updates tool data''' - tt = self._findList(listname) + tt = self.getTableFromName(listname) tt.deleteTool(toolnum) tt.setTool(toolnum, tool) - if listname == "
": - return self.saveMainLibrary(tt) + if listname == self.getCurrentTableName(): + return self.saveMainLibrary() return True def moveup(self, number, listname): "moves a tool to a lower number, if possible" - if number < 2: - return False target = number - 1 - tt = self._findList(listname) - + if number < 2: + return False, target + target = number - 1 + tt = self.getTableFromName(listname) t1 = tt.getTool(number).copy() tt.deleteTool(number) if target in tt.Tools.keys(): @@ -362,13 +482,13 @@ class ToolLibraryManager(): tt.deleteTool(target) tt.setTool(number, t2) tt.setTool(target, t1) - if listname == "
": - self.saveMainLibrary(tt) - return True + if listname == self.getCurrentTableName(): + self.saveMainLibrary() + return True, target def movedown(self, number, listname): "moves a tool to a higher number, if possible" - tt = self._findList(listname) + tt = self.getTableFromName(listname) target = number + 1 t1 = tt.getTool(number).copy() tt.deleteTool(number) @@ -377,16 +497,16 @@ class ToolLibraryManager(): tt.deleteTool(target) tt.setTool(number, t2) tt.setTool(target, t1) - if listname == "
": - self.saveMainLibrary(tt) - return True + if listname == self.getCurrentTableName(): + self.saveMainLibrary() + return True, target def delete(self, number, listname): '''deletes a tool from the current list''' - tt = self._findList(listname) + tt = self.getTableFromName(listname) tt.deleteTool(number) - if listname == "
": - self.saveMainLibrary(tt) + if listname == self.getCurrentTableName(): + self.saveMainLibrary() return True @@ -395,9 +515,12 @@ class EditorPanel(): def __init__(self, job, cb): self.form = FreeCADGui.PySideUic.loadUi(":/panels/ToolLibraryEditor.ui") self.TLM = ToolLibraryManager() + listname = self.TLM.getCurrentTableName() + + if listname: + self.loadToolTables() + #self.loadTable(listname) - self.loadTable() - self.form.ToolsList.resizeColumnsToContents() self.job = job self.cb = cb @@ -417,6 +540,12 @@ class EditorPanel(): def getFields(self): pass + def setFields(self): + pass + + def open(self): + pass + def getType(self, tooltype): "gets a combobox index number for a given type or viceversa" toolslist = Path.Tool.getToolTypes(Path.Tool()) @@ -429,7 +558,7 @@ class EditorPanel(): return toolslist[tooltype] def getMaterial(self, material): - "gets a combobox index number for a given material or viceversa" + '''gets a combobox index number for a given material or viceversa''' matslist = Path.Tool.getToolMaterials(Path.Tool()) if isinstance(material, str): if material in matslist: @@ -440,65 +569,34 @@ class EditorPanel(): return matslist[material] def addTool(self): + '''adds new tool to the current tool table''' tool = Path.Tool() editor = self.toolEditor(tool) r = editor.Parent.exec_() if r: editor.accept() - listname = "
" - if self.TLM.addnew(listname, editor.Tool) is True: - self.loadTable() - - def setFields(self): - pass - - def open(self): - pass - - def loadTable(self): - #tooldata = self.TLM.getTools(curr.data()) - tooldata = self.TLM.getTools("
") - self.form.ToolsList.setModel(tooldata) - - def moveUp(self): - "moves a tool to a lower number, if possible" - item = self.form.ToolsList.selectedIndexes()[1].data() - if item: - number = int(item) - listname = "
" - #listname = self.form.listView.selectedIndexes()[0].data() - if self.TLM.moveup(number, listname) is True: - self.loadTable() - - def moveDown(self): - "moves a tool to a higher number, if possible" - item = self.form.ToolsList.selectedIndexes()[1].data() - if item: - number = int(item) - listname = "
" - #listname = self.form.listView.selectedIndexes()[0].data() - if self.TLM.movedown(number, listname) is True: - self.loadTable() + listname = self.TLM.getCurrentTableName() + self.TLM.addnew(listname, editor.Tool) # is True: + self.loadTable(listname) def delete(self): - '''deletes a tool''' + '''deletes the selected tool''' #listname = self.form.listView.selectedIndexes()[0].data() - listname = "
" + listname = self.TLM.getCurrentTableName() model = self.form.ToolsList.model() for i in range(model.rowCount()): item = model.item(i, 0) if item.checkState(): t = model.index(i, 1) self.TLM.delete(int(t.data()) ,listname) - self.loadTable() + self.loadTable(listname) def editTool(self, currItem): - + '''load the tool edit dialog''' row = currItem.row() value = currItem.sibling(row, 1).data() - #listname = self.form.listView.selectedIndexes()[0].data() - listname = "
" + listname = self.TLM.getCurrentTableName() toolnum = int(value) tool = self.TLM.getTool(listname, toolnum) editor = self.toolEditor(tool) @@ -507,38 +605,88 @@ class EditorPanel(): if r: editor.accept() if self.TLM.updateTool(listname, toolnum, editor.Tool) is True: - self.loadTable() + self.loadTable(listname) + + def moveUp(self): + '''moves a tool to a lower number, if possible''' + item = self.form.ToolsList.selectedIndexes()[1].data() + if item: + number = int(item) + listname = self.TLM.getCurrentTableName() + success, newNum = self.TLM.moveup(number, listname) + if success: + self.loadTable(listname) + self.updateSelection(newNum) + + def moveDown(self): + '''moves a tool to a higher number, if possible''' + item = self.form.ToolsList.selectedIndexes()[1].data() + if item: + number = int(item) + listname = self.TLM.getCurrentTableName() + success, newNum = self.TLM.movedown(number, listname) + if success: + self.loadTable(listname) + self.updateSelection(newNum) + + def updateSelection(self, number): + '''update the tool list selection to track moves''' + model = self.form.ToolsList.model() + for i in range(model.rowCount()): + if int(model.index(i, 1).data()) == number: + self.form.ToolsList.selectRow(i) + self.form.ToolsList.model().item(i, 0).setCheckState(QtCore.Qt.Checked) + return + def importFile(self): - "imports a tooltable from a file" + '''imports a tooltable from a file''' filename = QtGui.QFileDialog.getOpenFileName(self.form, translate( "TooltableEditor", "Open tooltable", None), None, "{};;{};;{}".format(ToolLibraryManager.TooltableTypeJSON, ToolLibraryManager.TooltableTypeXML, ToolLibraryManager.TooltableTypeHeekscad)) if filename[0]: - listname = '
' + listname = self.TLM.getNextToolTableName() if self.TLM.read(filename, listname): - self.loadTable() + self.loadTable(listname) def exportFile(self): - "export a tooltable to a file" + '''export a tooltable to a file''' filename = QtGui.QFileDialog.getSaveFileName(self.form, translate("TooltableEditor", "Save tooltable", None), None, "{};;{};;{}".format(ToolLibraryManager.TooltableTypeJSON, ToolLibraryManager.TooltableTypeXML, ToolLibraryManager.TooltableTypeLinuxCNC)) - if filename[0]: - #listname = self.form.listView.selectedIndexes()[0].data() - listname = '
' + listname = self.TLM.getCurrentTableName() self.TLM.write(filename, listname) - def checkCopy(self): + def toolSelected(self, index): + ''' updates the ui when tools are selected''' + self.form.ToolsList.selectRow(index.row()) + self.form.btnCopyTools.setEnabled(False) + self.form.ButtonDelete.setEnabled(False) + self.form.ButtonUp.setEnabled(False) + self.form.ButtonDown.setEnabled(False) + model = self.form.ToolsList.model() + checkCount = 0 + checkList = [] for i in range(model.rowCount()): item = model.item(i, 0) if item.checkState(): + checkCount += 1 + checkList.append(i) self.form.btnCopyTools.setEnabled(True) + # only allow moving or deleting a single tool at a time. + if checkCount == 1: + #make sure the row is highlighted when the check box gets ticked + self.form.ToolsList.selectRow(checkList[0]) + self.form.ButtonDelete.setEnabled(True) + self.form.ButtonUp.setEnabled(True) + self.form.ButtonDown.setEnabled(True) + if len(PathUtils.GetJobs()) == 0: self.form.btnCopyTools.setEnabled(False) def copyTools(self): + ''' copy selected tool ''' tools = [] model = self.form.ToolsList.model() for i in range(model.rowCount()): @@ -550,7 +698,7 @@ class EditorPanel(): return targets = self.TLM.getLists() - currList = "
" + currList = self.TLM.getCurrentTableName() for target in targets: if target == currList: @@ -587,9 +735,78 @@ class EditorPanel(): self.cb() FreeCAD.ActiveDocument.recompute() + def tableSelected(self, index): + ''' loads the tools for the selected tool table ''' + name = self.form.TableList.itemFromIndex(index).text() + self.loadTable(name) + + def loadTable(self, name): + ''' loads the tools for the selected tool table ''' + tooldata = self.TLM.getTools(name) + self.form.ToolsList.setModel(tooldata) + self.form.ToolsList.resizeColumnsToContents() + self.setCurrentToolTableByName(name) + + def addNewToolTable(self): + ''' adds new tool to selected tool table ''' + name = self.TLM.addNewToolTable() + self.loadToolTables() + self.loadTable(name) + + def loadToolTables(self): + ''' Load list of available tool tables ''' + self.form.TableList.clear() + for table in self.TLM.getLists(): + listItem = QtGui.QListWidgetItem(table.Name) + listItem.setIcon(QtGui.QIcon(':/icons/Path-ToolTable.svg')) + listItem.setFlags(listItem.flags() | QtCore.Qt.ItemIsEditable) + listItem.setSizeHint(QtCore.QSize(0,40)) + self.form.TableList.addItem(listItem) + self.loadTable(self.TLM.toolTables[0].Name) + + def setCurrentToolTableByName(self, name): + ''' get the current tool table ''' + item = self.form.TableList.findItems(name, QtCore.Qt.MatchExactly)[0] + self.form.TableList.setCurrentItem(item) + + def removeToolTable(self): + ''' delete the selected tool table ''' + self.TLM.deleteToolTable() + self.loadToolTables() + + def initTableRename(self): + ''' update the tool table list entry to allow renaming ''' + name = self.TLM.getCurrentTableName() + item = self.form.TableList.findItems(name, QtCore.Qt.MatchExactly)[0] + self.form.TableList.editItem(item) + + def renameTable(self, listItem): + ''' rename the selected too table ''' + newName = listItem.text() + index = self.form.TableList.indexFromItem(listItem).row() + reloadTables = self.TLM.renameToolTable(newName, index) + if reloadTables: + self.loadToolTables() + def getStandardButtons(self): return int(QtGui.QDialogButtonBox.Ok) + # def openMenu(self, position): + # menu = QtGui.QMenu() + # newAction = menu.addAction("New Tool Table") + # deleteAction = menu.addAction("Delete") + # renameAction = menu.addAction("Rename") + # action = menu.exec_(self.form.TableList.mapToGlobal(position)) + # if action == newAction: + # self.addNewToolTable() + # pass + # if action == deleteAction: + # self.removeToolTable() + # pass + # if action == renameAction: + # self.initTableRename() + # pass + def setupUi(self): # Connect Signals and Slots self.form.ButtonNewTool.clicked.connect(self.addTool) @@ -598,11 +815,29 @@ class EditorPanel(): self.form.ButtonDown.clicked.connect(self.moveDown) self.form.ButtonUp.clicked.connect(self.moveUp) self.form.ButtonDelete.clicked.connect(self.delete) + self.form.ToolsList.doubleClicked.connect(self.editTool) - self.form.ToolsList.clicked.connect(self.checkCopy) + self.form.ToolsList.clicked.connect(self.toolSelected) + self.form.btnCopyTools.clicked.connect(self.copyTools) + self.form.TableList.clicked.connect(self.tableSelected) + self.form.TableList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) + #self.form.TableList.customContextMenuRequested.connect(self.openMenu) + self.form.TableList.itemChanged.connect(self.renameTable) + + self.form.ButtonAddToolTable.clicked.connect(self.addNewToolTable) + self.form.ButtonAddToolTable.setToolTip(translate("TooltableEditor","Add New Tool Table")) + self.form.ButtonRemoveToolTable.clicked.connect(self.removeToolTable) + self.form.ButtonRemoveToolTable.setToolTip(translate("TooltableEditor","Delete Selected Tool Table")) + self.form.ButtonRenameToolTable.clicked.connect(self.initTableRename) + self.form.ButtonRenameToolTable.setToolTip(translate("TooltableEditor","Rename Selected Tool Table")) + + self.form.btnCopyTools.setEnabled(False) + self.form.ButtonDelete.setEnabled(False) + self.form.ButtonUp.setEnabled(False) + self.form.ButtonDown.setEnabled(False) self.setFields() From 2f478e5a5882165e6ee743be1b65d4ddd2970f4d Mon Sep 17 00:00:00 2001 From: Dubstar_04 Date: Sat, 24 Aug 2019 19:16:31 +0100 Subject: [PATCH 04/23] Make sure the tool list get cleared Ensure the tool list gets clear when all tooltables are deleted. --- .../PathScripts/PathToolLibraryManager.py | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathToolLibraryManager.py b/src/Mod/Path/PathScripts/PathToolLibraryManager.py index afeec84318..938450e8fd 100644 --- a/src/Mod/Path/PathScripts/PathToolLibraryManager.py +++ b/src/Mod/Path/PathScripts/PathToolLibraryManager.py @@ -743,9 +743,11 @@ class EditorPanel(): def loadTable(self, name): ''' loads the tools for the selected tool table ''' tooldata = self.TLM.getTools(name) - self.form.ToolsList.setModel(tooldata) - self.form.ToolsList.resizeColumnsToContents() - self.setCurrentToolTableByName(name) + if tooldata: + self.form.ToolsList.setModel(tooldata) + self.form.ToolsList.resizeColumnsToContents() + self.setCurrentToolTableByName(name) + def addNewToolTable(self): ''' adds new tool to selected tool table ''' @@ -756,13 +758,17 @@ class EditorPanel(): def loadToolTables(self): ''' Load list of available tool tables ''' self.form.TableList.clear() - for table in self.TLM.getLists(): - listItem = QtGui.QListWidgetItem(table.Name) - listItem.setIcon(QtGui.QIcon(':/icons/Path-ToolTable.svg')) - listItem.setFlags(listItem.flags() | QtCore.Qt.ItemIsEditable) - listItem.setSizeHint(QtCore.QSize(0,40)) - self.form.TableList.addItem(listItem) - self.loadTable(self.TLM.toolTables[0].Name) + model = self.form.ToolsList.model() + if model: + model.clear() + if len(self.TLM.toolTables) > 0: + for table in self.TLM.getLists(): + listItem = QtGui.QListWidgetItem(table.Name) + listItem.setIcon(QtGui.QIcon(':/icons/Path-ToolTable.svg')) + listItem.setFlags(listItem.flags() | QtCore.Qt.ItemIsEditable) + listItem.setSizeHint(QtCore.QSize(0,40)) + self.form.TableList.addItem(listItem) + self.loadTable(self.TLM.toolTables[0].Name) def setCurrentToolTableByName(self, name): ''' get the current tool table ''' From f181565a40a7853121702829bf2b3e79cf84bb00 Mon Sep 17 00:00:00 2001 From: Dubstar_04 Date: Sat, 24 Aug 2019 21:52:30 +0100 Subject: [PATCH 05/23] Check there is preference data before reading it --- .../Path/PathScripts/PathToolLibraryManager.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathToolLibraryManager.py b/src/Mod/Path/PathScripts/PathToolLibraryManager.py index 938450e8fd..94e5b76d48 100644 --- a/src/Mod/Path/PathScripts/PathToolLibraryManager.py +++ b/src/Mod/Path/PathScripts/PathToolLibraryManager.py @@ -146,6 +146,7 @@ class ToolLibraryManager(): ''' #TODO: copy & Duplicate tools between lists + #TODO: update version number and handle upgrading TooltableTypeJSON = translate("TooltableEditor", "Tooltable JSON (*.json)") TooltableTypeXML = translate("TooltableEditor", "Tooltable XML (*.xml)") @@ -273,17 +274,19 @@ class ToolLibraryManager(): return None def loadToolTables(self): - ''' loads the tool tables from tehe stored data ''' + ''' loads the tool tables from the stored data ''' self.toolTables = [] self.currentTableName = '' - for table in json.loads(self.prefs.GetString(self.PreferenceMainLibraryJSON, "")): + prefsData = self.prefs.GetString(self.PreferenceMainLibraryJSON, "") + if prefsData: + for table in json.loads(prefsData): - tt = self.tooltableFromAttrs(table) - if tt: - self.toolTables.append(tt) - else: - PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable")) + tt = self.tooltableFromAttrs(table) + if tt: + self.toolTables.append(tt) + else: + PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable")) def saveMainLibrary(self): '''Persists the permanent library to FreeCAD user preferences''' From d34ee627d85a0374cd7779a41f8c5b36b6e7c6d6 Mon Sep 17 00:00:00 2001 From: Daniel Wood Date: Mon, 26 Aug 2019 20:19:12 +0100 Subject: [PATCH 06/23] Import and opening current tool tables Handle opening and importing current (pre-0.19) tool tables. --- .../PathScripts/PathToolLibraryManager.py | 80 +++++++++++++------ 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathToolLibraryManager.py b/src/Mod/Path/PathScripts/PathToolLibraryManager.py index 94e5b76d48..cf3dbbc777 100644 --- a/src/Mod/Path/PathScripts/PathToolLibraryManager.py +++ b/src/Mod/Path/PathScripts/PathToolLibraryManager.py @@ -146,7 +146,6 @@ class ToolLibraryManager(): ''' #TODO: copy & Duplicate tools between lists - #TODO: update version number and handle upgrading TooltableTypeJSON = translate("TooltableEditor", "Tooltable JSON (*.json)") TooltableTypeXML = translate("TooltableEditor", "Tooltable XML (*.xml)") @@ -181,18 +180,18 @@ class ToolLibraryManager(): if table.Name == name: return table - def getNextToolTableName(self): + def getNextToolTableName(self, tableName='Tool Table'): ''' get a unique name for a new tool table ''' iter = 1 - tableNames = [] + tempName = tableName[-2:] - for table in self.toolTables: - tableNames.append(table.Name) - - while "ToolTable-" + str(iter) in tableNames: + if tempName[0] == '-' and tempName[-1].isdigit(): + tableName = tableName[:-2] + + while any(table.Name == tableName + '-' + str(iter) for table in self.toolTables): iter += 1 - return "ToolTable-" + str(iter) + return tableName + '-' + str(iter) def addNewToolTable(self): ''' creates a new tool table ''' @@ -248,13 +247,16 @@ class ToolLibraryManager(): tt = Path.Tooltable() tt.Version = 1 + tt.Name = self.getNextToolTableName() if stringattrs.get('Version'): tt.Version = stringattrs.get('Version') if stringattrs.get('TableName'): tt.Name = stringattrs.get('TableName') - + if any(table.Name == tt.Name for table in self.toolTables): + tt.Name = self.getNextToolTableName(tt.Name) + for key, attrs in PathUtil.keyValueIter(stringattrs['Tools']): tool = Path.Tool() tool.Name = str(attrs["name"]) @@ -278,15 +280,22 @@ class ToolLibraryManager(): self.toolTables = [] self.currentTableName = '' - prefsData = self.prefs.GetString(self.PreferenceMainLibraryJSON, "") - if prefsData: - for table in json.loads(prefsData): + def addTable(tt): + if tt: + self.toolTables.append(tt) + else: + PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable")) + + prefsData = json.loads(self.prefs.GetString(self.PreferenceMainLibraryJSON, "")) + if isinstance(prefsData, dict): + tt = self.tooltableFromAttrs(prefsData) + addTable(tt) + + if isinstance(prefsData, list): + for table in prefsData: tt = self.tooltableFromAttrs(table) - if tt: - self.toolTables.append(tt) - else: - PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable")) + addTable(tt) def saveMainLibrary(self): '''Persists the permanent library to FreeCAD user preferences''' @@ -384,6 +393,8 @@ class ToolLibraryManager(): def read(self, filename, listname): "imports a tooltable from a file" + importedTables = [] + try: fileExtension = os.path.splitext(filename[0])[1].lower() xmlHandler = None @@ -403,15 +414,35 @@ class ToolLibraryManager(): ht = xmlHandler.tooltable else: with open(PathUtil.toUnicode(filename[0]), "rb") as fp: - ht = self.tooltableFromAttrs(json.load(fp)) + tableData = json.load(fp) - tt = self.getTableFromName(listname) - for t in ht.Tools: - newt = ht.getTool(t).copy() - tt.addTools(newt) - if listname == self.getCurrentTableName(): + if isinstance(tableData, dict): + ht = self.tooltableFromAttrs(tableData) + if ht: + importedTables.append(ht) + + if isinstance(tableData, list): + for table in tableData: + ht = self.tooltableFromAttrs(table) + if ht: + importedTables.append(ht) + + if importedTables: + for tt in importedTables: + self.toolTables.append(tt) + self.saveMainLibrary() - return True + return True + else: + return False + + # tt = self.getTableFromName(listname) + # for t in ht.Tools: + # newt = ht.getTool(t).copy() + # tt.addTools(newt) + # if listname == self.getCurrentTableName(): + # self.saveMainLibrary() + # return True except Exception as e: # pylint: disable=broad-except print("could not parse file", e) @@ -648,7 +679,8 @@ class EditorPanel(): if filename[0]: listname = self.TLM.getNextToolTableName() if self.TLM.read(filename, listname): - self.loadTable(listname) + self.loadToolTables() + #self.loadTable(listname) def exportFile(self): From 7c74411c327e84a649b9355ba1ea75c0cfefabe4 Mon Sep 17 00:00:00 2001 From: Daniel Wood Date: Mon, 26 Aug 2019 21:24:44 +0100 Subject: [PATCH 07/23] Return document jobs for copy commands Return the document jobs when creating tool controllers. --- .../PathScripts/PathToolLibraryManager.py | 58 ++++++------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathToolLibraryManager.py b/src/Mod/Path/PathScripts/PathToolLibraryManager.py index cf3dbbc777..817c0b5152 100644 --- a/src/Mod/Path/PathScripts/PathToolLibraryManager.py +++ b/src/Mod/Path/PathScripts/PathToolLibraryManager.py @@ -166,6 +166,9 @@ class ToolLibraryManager(): return + def getToolTables(self): + return self.toolTables + def getCurrentTableName(self): ''' return the name of the currently loaded tool table ''' return self.currentTableName @@ -285,7 +288,7 @@ class ToolLibraryManager(): self.toolTables.append(tt) else: PathLog.error(translate('PathToolLibraryManager', "Unsupported Path tooltable")) - + prefsData = json.loads(self.prefs.GetString(self.PreferenceMainLibraryJSON, "")) if isinstance(prefsData, dict): @@ -304,43 +307,16 @@ class ToolLibraryManager(): self.loadToolTables() return True - def getLists(self): + def getJobList(self): '''Builds the list of all Tool Table lists''' - tablelist = self.toolTables.copy() - #TODO load a tool table for current job? - # Get ToolTables from any open CNC jobs - # for o in FreeCAD.ActiveDocument.Objects: - # if hasattr(o, "Proxy"): - # if isinstance(o.Proxy, PathScripts.PathJob.ObjectJob): - # tablelist.append(o.Label) - return tablelist + tablelist = [] - # def _findList(self, listname): - # tt = None - # if listname == self.getCurrentTableName(): - # #print("Findlist - ListName:", listname) - # return self.getCurrentTable() - # else: - # tmpstring = self.prefs.GetString(self.PreferenceMainLibraryJSON, "") - # if not tmpstring: - # tmpstring = self.prefs.GetString(self.PreferenceMainLibraryXML, "") - # if tmpstring: - # if tmpstring[0] == '{': - # tt = self.tooltableFromAttrs(json.loads(tmpstring)) - # elif tmpstring[0] == '<': - # # legacy XML table - # Handler = FreeCADTooltableHandler() - # xml.sax.parseString(tmpstring, Handler) - # tt = Handler.tooltable - # # store new format - # self.saveMainLibrary() - # else: - # tt = Path.Tooltable() - # # else: - # # for o in FreeCAD.ActiveDocument.Objects: - # # if o.Label == listname: - # # tt = o.Tooltable - # return tt + for o in FreeCAD.ActiveDocument.Objects: + if hasattr(o, "Proxy"): + if isinstance(o.Proxy, PathScripts.PathJob.ObjectJob): + tablelist.append(o.Label) + + return tablelist def getTool(self, listname, toolnum): ''' gets the tool object ''' @@ -732,7 +708,7 @@ class EditorPanel(): if len(tools) == 0: return - targets = self.TLM.getLists() + targets = self.TLM.getJobList() currList = self.TLM.getCurrentTableName() for target in targets: @@ -740,7 +716,7 @@ class EditorPanel(): targets.remove(target) if len(targets) == 0: - FreeCAD.Console.PrintWarning("no place to go") + FreeCAD.Console.PrintWarning("No Path Jobs in current document") return elif len(targets) == 1: targetlist = targets[0] @@ -796,14 +772,14 @@ class EditorPanel(): model = self.form.ToolsList.model() if model: model.clear() - if len(self.TLM.toolTables) > 0: - for table in self.TLM.getLists(): + if len(self.TLM.getToolTables()) > 0: + for table in self.TLM.getToolTables(): listItem = QtGui.QListWidgetItem(table.Name) listItem.setIcon(QtGui.QIcon(':/icons/Path-ToolTable.svg')) listItem.setFlags(listItem.flags() | QtCore.Qt.ItemIsEditable) listItem.setSizeHint(QtCore.QSize(0,40)) self.form.TableList.addItem(listItem) - self.loadTable(self.TLM.toolTables[0].Name) + self.loadTable(self.TLM.getToolTables()[0].Name) def setCurrentToolTableByName(self, name): ''' get the current tool table ''' From 23c3bfb163cc01daaf12434ea0018eb43e60bc20 Mon Sep 17 00:00:00 2001 From: Daniel Wood Date: Mon, 26 Aug 2019 21:27:06 +0100 Subject: [PATCH 08/23] clean up unused code --- src/Mod/Path/PathScripts/PathToolLibraryManager.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathToolLibraryManager.py b/src/Mod/Path/PathScripts/PathToolLibraryManager.py index 817c0b5152..a34f267244 100644 --- a/src/Mod/Path/PathScripts/PathToolLibraryManager.py +++ b/src/Mod/Path/PathScripts/PathToolLibraryManager.py @@ -167,6 +167,7 @@ class ToolLibraryManager(): return def getToolTables(self): + ''' Return tool table list ''' return self.toolTables def getCurrentTableName(self): @@ -412,13 +413,6 @@ class ToolLibraryManager(): else: return False - # tt = self.getTableFromName(listname) - # for t in ht.Tools: - # newt = ht.getTool(t).copy() - # tt.addTools(newt) - # if listname == self.getCurrentTableName(): - # self.saveMainLibrary() - # return True except Exception as e: # pylint: disable=broad-except print("could not parse file", e) @@ -529,7 +523,6 @@ class EditorPanel(): if listname: self.loadToolTables() - #self.loadTable(listname) self.job = job self.cb = cb From 63d3181f2d69ab8d1ea0a94a810ac254e5e7cb24 Mon Sep 17 00:00:00 2001 From: Daniel Wood Date: Tue, 27 Aug 2019 07:15:23 +0100 Subject: [PATCH 09/23] Remove unused function definition --- src/Mod/Path/App/Tooltable.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Mod/Path/App/Tooltable.h b/src/Mod/Path/App/Tooltable.h index 77112398f5..873b943afd 100644 --- a/src/Mod/Path/App/Tooltable.h +++ b/src/Mod/Path/App/Tooltable.h @@ -50,7 +50,6 @@ namespace Path void addTool(const Tool &tool); // adds a tool at the end void setTool(const Tool &tool, int); // inserts a tool void deleteTool(int); // deletes a tool - //void setVersion(int); //set the table version // auto unsigned int getSize(void) const {return Tools.size();} From a9e63c5b23f070f76531876a444dddaed158812c Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Wed, 28 Aug 2019 21:47:43 +0200 Subject: [PATCH 10/23] FEM: mesh tools, use double string quotes instead of single --- src/Mod/Fem/femmesh/meshtools.py | 622 +++++++++++++++---------------- 1 file changed, 311 insertions(+), 311 deletions(-) diff --git a/src/Mod/Fem/femmesh/meshtools.py b/src/Mod/Fem/femmesh/meshtools.py index 7cc82168cf..e1bc9e85d1 100644 --- a/src/Mod/Fem/femmesh/meshtools.py +++ b/src/Mod/Fem/femmesh/meshtools.py @@ -37,8 +37,8 @@ def get_femnodes_by_femobj_with_references( ): node_set = [] if femmesh.GroupCount: - node_set = get_femmesh_groupdata_sets_by_name(femmesh, femobj, 'Node') - # FreeCAD.Console.PrintMessage('node_set_group: {}\n'.format(node_set)) + node_set = get_femmesh_groupdata_sets_by_name(femmesh, femobj, "Node") + # FreeCAD.Console.PrintMessage("node_set_group: {}\n".format(node_set)) if node_set: FreeCAD.Console.PrintMessage( " Finite element mesh nodes where retrieved " @@ -49,8 +49,8 @@ def get_femnodes_by_femobj_with_references( " Finite element mesh nodes will be retrieved " "by searching the appropriate nodes in the finite element mesh.\n" ) - node_set = get_femnodes_by_references(femmesh, femobj['Object'].References) - # FreeCAD.Console.PrintMessage('node_set_nogroup: {}\n'.format(node_set)) + node_set = get_femnodes_by_references(femmesh, femobj["Object"].References) + # FreeCAD.Console.PrintMessage("node_set_nogroup: {}\n".format(node_set)) return node_set @@ -62,8 +62,8 @@ def get_femelements_by_references( references, femnodes_ele_table=None ): - '''get the femelements for a list of references - ''' + """get the femelements for a list of references + """ references_femelements = [] for ref in references: # femnodes for the current ref @@ -91,8 +91,8 @@ def get_femnodes_by_references( femmesh, references ): - '''get the femnodes for a list of references - ''' + """get the femnodes for a list of references + """ references_femnodes = [] for ref in references: references_femnodes += get_femnodes_by_refshape(femmesh, ref) @@ -112,25 +112,25 @@ def get_femnodes_by_refshape( # the following method getElement(element) does not return Solid elements r = get_element(ref[0], refelement) FreeCAD.Console.PrintMessage( - ' ' - 'ReferenceShape ... Type: {0}, ' - 'Object name: {1}, ' - 'Object label: {2}, ' - 'Element name: {3}\n' + " " + "ReferenceShape ... Type: {0}, " + "Object name: {1}, " + "Object label: {2}, " + "Element name: {3}\n" .format(r.ShapeType, ref[0].Name, ref[0].Label, refelement) ) - if r.ShapeType == 'Vertex': + if r.ShapeType == "Vertex": nodes += femmesh.getNodesByVertex(r) - elif r.ShapeType == 'Edge': + elif r.ShapeType == "Edge": nodes += femmesh.getNodesByEdge(r) - elif r.ShapeType == 'Face': + elif r.ShapeType == "Face": nodes += femmesh.getNodesByFace(r) - elif r.ShapeType == 'Solid': + elif r.ShapeType == "Solid": nodes += femmesh.getNodesBySolid(r) else: FreeCAD.Console.PrintMessage( - ' ' - 'No Vertice, Edge, Face or Solid as reference shapes!\n' + " " + "No Vertice, Edge, Face or Solid as reference shapes!\n" ) return nodes @@ -151,7 +151,7 @@ def get_femelement_table( for i in femmesh.Edges: femelement_table[i] = femmesh.getElementNodes(i) else: - FreeCAD.Console.PrintError('Neither solid nor face nor edge femmesh!\n') + FreeCAD.Console.PrintError("Neither solid nor face nor edge femmesh!\n") return femelement_table @@ -199,7 +199,7 @@ def get_femnodes_ele_table( femnodes_mesh, femelement_table ): - '''the femnodes_ele_table contains for each node its membership in elements + """the femnodes_ele_table contains for each node its membership in elements {nodeID : [[eleID, NodePosition], [], ...], nodeID : [[], [], ...], ...} stored information is: element number, the number of nodes per element @@ -213,22 +213,22 @@ def get_femnodes_ele_table( volume or face or edgemesh the femnodes_ele_table only has either volume or face or edge elements see get_femelement_table() - ''' + """ femnodes_ele_table = {} # node_dict in ulrichs class for n in femnodes_mesh: # initialize it with sorted node keys and empty lists femnodes_ele_table[n] = [] for ele in femelement_table: ele_list = femelement_table[ele] - # FreeCAD.Console.PrintMessage('{}\n'.format(ele_list)) + # FreeCAD.Console.PrintMessage("{}\n".format(ele_list)) pos = int(1) for ele_node in ele_list: femnodes_ele_table[ele_node].append([ele, pos]) pos = pos << 1 FreeCAD.Console.PrintLog( - 'len femnodes_ele_table: {}\n' + "len femnodes_ele_table: {}\n" .format(len(femnodes_ele_table)) ) - FreeCAD.Console.PrintLog('femnodes_ele_table: {}\n'.format(femnodes_ele_table)) + FreeCAD.Console.PrintLog("femnodes_ele_table: {}\n".format(femnodes_ele_table)) return femnodes_ele_table @@ -236,8 +236,8 @@ def get_femnodes_ele_table( def get_copy_of_empty_femelement_table( femelement_table ): - '''{eleID : 0, eleID : 0, ...} - ''' + """{eleID : 0, eleID : 0, ...} + """ empty_femelement_table = {} for ele in femelement_table: # initialize it with sorted element keys and empty int empty_femelement_table[ele] = 0 @@ -250,9 +250,9 @@ def get_bit_pattern_dict( femnodes_ele_table, node_set ): - '''Now we are looking for nodes inside of the Faces = filling the bit_pattern_dict + """Now we are looking for nodes inside of the Faces = filling the bit_pattern_dict {eleID : [lenEleNodes, binary_position]} - see forum post for a very good explanation of what's really happening + see forum post for a very good explanation of what"s really happening https://forum.freecadweb.org/viewtopic.php?f=18&t=17318&start=50#p141108 The bit_pattern_dict holds later an integer (bit array) for each element, which gives us the information we are searching for: @@ -260,10 +260,10 @@ def get_bit_pattern_dict( or has this element a face we are searching for? The number in the ele_dict is organized as a bit array. The corresponding bit is set, if the node of the node_set is contained in the element. - ''' - FreeCAD.Console.PrintLog('len femnodes_ele_table: ' + str(len(femnodes_ele_table)) + '\n') - FreeCAD.Console.PrintLog('len node_set: ' + str(len(node_set)) + '\n') - FreeCAD.Console.PrintLog('node_set: {}\n'.format(node_set)) + """ + FreeCAD.Console.PrintLog("len femnodes_ele_table: " + str(len(femnodes_ele_table)) + "\n") + FreeCAD.Console.PrintLog("len node_set: " + str(len(node_set)) + "\n") + FreeCAD.Console.PrintLog("node_set: {}\n".format(node_set)) bit_pattern_dict = get_copy_of_empty_femelement_table(femelement_table) # # initializing the bit_pattern_dict for ele in femelement_table: @@ -272,8 +272,8 @@ def get_bit_pattern_dict( for node in node_set: for nList in femnodes_ele_table[node]: bit_pattern_dict[nList[0]][1] += nList[1] - FreeCAD.Console.PrintLog('len bit_pattern_dict: ' + str(len(bit_pattern_dict)) + '\n') - # FreeCAD.Console.PrintMessage('bit_pattern_dict: {}\n'.format(bit_pattern_dict)) + FreeCAD.Console.PrintLog("len bit_pattern_dict: " + str(len(bit_pattern_dict)) + "\n") + # FreeCAD.Console.PrintMessage("bit_pattern_dict: {}\n".format(bit_pattern_dict)) return bit_pattern_dict @@ -281,8 +281,8 @@ def get_bit_pattern_dict( def get_ccxelement_faces_from_binary_search( bit_pattern_dict ): - '''get the CalculiX element face numbers - ''' + """get the CalculiX element face numbers + """ tet10_mask = { 119: 1, 411: 2, @@ -332,8 +332,8 @@ def get_ccxelement_faces_from_binary_search( for key in mask_dict: if (key & bit_pattern_dict[ele][1]) == key: faces.append([ele, mask_dict[key]]) - FreeCAD.Console.PrintLog('found Faces: {}\n'.format(len(faces))) - # FreeCAD.Console.PrintMessage('faces: {}\n'.format(faces)) + FreeCAD.Console.PrintLog("found Faces: {}\n".format(len(faces))) + # FreeCAD.Console.PrintMessage("faces: {}\n".format(faces)) return faces @@ -343,12 +343,12 @@ def get_femelements_by_femnodes_bin( femnodes_ele_table, node_list ): - '''for every femelement of femelement_table + """for every femelement of femelement_table if all nodes of the femelement are in node_list, the femelement is added to the list which is returned blind fast binary search, but works for volumes only - ''' - FreeCAD.Console.PrintMessage('binary search: get_femelements_by_femnodes_bin\n') + """ + FreeCAD.Console.PrintMessage("binary search: get_femelements_by_femnodes_bin\n") vol_masks = { 4: 15, 6: 63, @@ -358,7 +358,7 @@ def get_femelements_by_femnodes_bin( 20: 1048575} # Now we are looking for nodes inside of the Volumes = filling the bit_pattern_dict FreeCAD.Console.PrintMessage( - 'len femnodes_ele_table: {}\n' + "len femnodes_ele_table: {}\n" .format(len(femnodes_ele_table)) ) bit_pattern_dict = get_bit_pattern_dict(femelement_table, femnodes_ele_table, node_list) @@ -366,12 +366,12 @@ def get_femelements_by_femnodes_bin( ele_list = [] # The ele_list contains the result of the search. for ele in bit_pattern_dict: FreeCAD.Console.PrintLog( - 'bit_pattern_dict[ele][0]: {}\n'.format(bit_pattern_dict[ele][0]) + "bit_pattern_dict[ele][0]: {}\n".format(bit_pattern_dict[ele][0]) ) if bit_pattern_dict[ele][1] == vol_masks[bit_pattern_dict[ele][0]]: ele_list.append(ele) - FreeCAD.Console.PrintMessage('found Volumes: {}\n'.format(len(ele_list))) - # FreeCAD.Console.PrintMessage(' volumes: {}\n'.format(ele_list)) + FreeCAD.Console.PrintMessage("found Volumes: {}\n".format(len(ele_list))) + # FreeCAD.Console.PrintMessage(" volumes: {}\n".format(ele_list)) return ele_list @@ -380,12 +380,12 @@ def get_femelements_by_femnodes_std( femelement_table, node_list ): - '''for every femelement of femelement_table + """for every femelement of femelement_table if all nodes of the femelement are in node_list, the femelement is added to the list which is returned e: elementlist - nodes: nodelist ''' - FreeCAD.Console.PrintMessage('std search: get_femelements_by_femnodes_std\n') + nodes: nodelist """ + FreeCAD.Console.PrintMessage("std search: get_femelements_by_femnodes_std\n") e = [] # elementlist for elementID in sorted(femelement_table): nodecount = 0 @@ -402,7 +402,7 @@ def get_femvolumeelements_by_femfacenodes( femelement_table, node_list ): - '''assume femelement_table only has volume elements + """assume femelement_table only has volume elements for every femvolumeelement of femelement_table for tetra4 and tetra10 the C++ methods could be used --> test again to be sure if hexa8 volume element @@ -414,7 +414,7 @@ def get_femvolumeelements_by_femfacenodes( if penta15 volume element --> if exact 6 or 8 element nodes are in node_list --> add femelement e: elementlist - nodes: nodelist ''' + nodes: nodelist """ e = [] # elementlist for elementID in sorted(femelement_table): nodecount = 0 @@ -457,11 +457,11 @@ def get_femvolumeelements_by_femfacenodes( e.append(elementID) else: FreeCAD.Console.PrintError( - 'Error in get_femvolumeelements_by_femfacenodes(): ' - 'unknown volume element: {}\n' + "Error in get_femvolumeelements_by_femfacenodes(): " + "unknown volume element: {}\n" .format(el_nd_ct) ) - # FreeCAD.Console.PrintMessage('{}\n'.format(sorted(e))) + # FreeCAD.Console.PrintMessage("{}\n".format(sorted(e))) return e @@ -478,14 +478,14 @@ def get_femelement_sets( referenced_femelements = [] has_remaining_femelements = None for fem_object_i, fem_object in enumerate(fem_objects): - obj = fem_object['Object'] + obj = fem_object["Object"] FreeCAD.Console.PrintMessage( "Constraint: {} --> We're going to search " "in the mesh for the element ID's.\n" .format(obj.Name) ) # unique short identifier - fem_object['ShortName'] = get_elset_short_name(obj, fem_object_i) + fem_object["ShortName"] = get_elset_short_name(obj, fem_object_i) if obj.References: ref_shape_femelements = [] ref_shape_femelements = get_femelements_by_references( @@ -495,7 +495,7 @@ def get_femelement_sets( ) referenced_femelements += ref_shape_femelements count_femelements += len(ref_shape_femelements) - fem_object['FEMElements'] = ref_shape_femelements + fem_object["FEMElements"] = ref_shape_femelements else: has_remaining_femelements = obj.Name # get remaining femelements for the fem_objects @@ -506,15 +506,15 @@ def get_femelement_sets( remaining_femelements.append(elemid) count_femelements += len(remaining_femelements) for fem_object in fem_objects: - obj = fem_object['Object'] + obj = fem_object["Object"] if obj.Name == has_remaining_femelements: - fem_object['FEMElements'] = sorted(remaining_femelements) + fem_object["FEMElements"] = sorted(remaining_femelements) # check if all worked out well if femelements_count_ok(len(femelement_table), count_femelements): return True else: FreeCAD.Console.PrintError( - 'Error in get_femelement_sets -- > femelements_count_ok() failed!\n' + "Error in get_femelement_sets -- > femelements_count_ok() failed!\n" ) return False @@ -526,17 +526,17 @@ def get_femelement_direction1D_set( beamrotation_objects, theshape=None ): - ''' + """ get for each geometry edge direction, the normal and the element ids and # write all into the beamrotation_objects means no return value, we're going to write into the beamrotation_objects dictionary FEMRotations1D is a list of dictionaries for every beamdirection of all edges - beamrot_obj['FEMRotations1D'] = [{ - 'ids' : [theids], - 'direction' : direction, - 'normal' : normal + beamrot_obj["FEMRotations1D"] = [{ + "ids" : [theids], + "direction" : direction, + "normal" : normal }, ... ] - ''' + """ if len(beamrotation_objects) == 0: # no beamrotation document object, all beams use standard rotation of 0 degree (angle) # we need theshape (the shape which was meshed) @@ -545,9 +545,9 @@ def get_femelement_direction1D_set( # add normals for each direction rotation_angle = 0 for rot in rotations_ids: - rot['normal'] = get_beam_normal(rot['direction'], rotation_angle) - # key 'Object' will be empty - beamrotation_objects.append({'FEMRotations1D': rotations_ids, 'ShortName': 'Rstd'}) + rot["normal"] = get_beam_normal(rot["direction"], rotation_angle) + # key "Object" will be empty + beamrotation_objects.append({"FEMRotations1D": rotations_ids, "ShortName": "Rstd"}) elif len(beamrotation_objects) == 1: # one beamrotation document object with no references # all beams use rotation from this object @@ -555,11 +555,11 @@ def get_femelement_direction1D_set( # since ccx needs to split them in sets anyway we need to take care of this too rotations_ids = get_femelement_directions_theshape(femmesh, femelement_table, theshape) # add normals for each direction - rotation_angle = beamrotation_objects[0]['Object'].Rotation + rotation_angle = beamrotation_objects[0]["Object"].Rotation for rot in rotations_ids: - rot['normal'] = get_beam_normal(rot['direction'], rotation_angle) - beamrotation_objects[0]['FEMRotations1D'] = rotations_ids - beamrotation_objects[0]['ShortName'] = 'R0' + rot["normal"] = get_beam_normal(rot["direction"], rotation_angle) + beamrotation_objects[0]["FEMRotations1D"] = rotations_ids + beamrotation_objects[0]["ShortName"] = "R0" elif len(beamrotation_objects) > 1: # multiple beam rotation document objects # rotations defined by reference shapes, TODO implement this @@ -573,9 +573,9 @@ def get_femelement_direction1D_set( # pre check, only one beam rotation with empty ref shapes is allowed # we need theshape for multiple rotations too # because of the corner cases mentioned above - FreeCAD.Console.PrintError('Multiple Rotations not yet supported!\n') + FreeCAD.Console.PrintError("Multiple Rotations not yet supported!\n") for rot_object in beamrotation_objects: # debug output - FreeCAD.Console.PrintMessage('{}\n'.format(rot_object['FEMRotations1D'])) + FreeCAD.Console.PrintMessage("{}\n".format(rot_object["FEMRotations1D"])) # ************************************************************************************************ @@ -585,15 +585,15 @@ def get_femelement_directions_theshape(femmesh, femelement_table, theshape): # add directions and all ids for each direction for e in theshape.Shape.Edges: the_edge = {} - the_edge['direction'] = e.Vertexes[1].Point - e.Vertexes[0].Point + the_edge["direction"] = e.Vertexes[1].Point - e.Vertexes[0].Point edge_femnodes = femmesh.getNodesByEdge(e) # femnodes for the current edge # femelements for this edge - the_edge['ids'] = get_femelements_by_femnodes_std(femelement_table, edge_femnodes) + the_edge["ids"] = get_femelements_by_femnodes_std(femelement_table, edge_femnodes) for rot in rotations_ids: # tolerance will be managed by FreeCAD # see https://forum.freecadweb.org/viewtopic.php?f=22&t=14179 - if rot['direction'] == the_edge['direction']: - rot['ids'] += the_edge['ids'] + if rot["direction"] == the_edge["direction"]: + rot["ids"] += the_edge["ids"] break else: rotations_ids.append(the_edge) @@ -651,8 +651,8 @@ def get_beam_normal(beam_direction, defined_angle): dot_nt = vector_a[0] * normal_n[0] + vector_a[1] * normal_n[1] + vector_a[2] * normal_n[2] dot = vector_a[0] * normal_n[0] + vector_a[1] * normal_n[1] + vector_a[2] * normal_n[2] - FreeCAD.Console.PrintLog('{}\n'.format(dot)) - FreeCAD.Console.PrintLog('{}\n'.format(normal_n)) + FreeCAD.Console.PrintLog("{}\n".format(dot)) + FreeCAD.Console.PrintLog("{}\n".format(normal_n)) # dummy usage of the axis dot to get flake8 quiet del dot_x, dot_y, dot_z, dot, dot_nt @@ -672,14 +672,14 @@ def get_femmesh_groupdata_sets_by_name( # we just check for the group name and the group data type # what happens if a reference shape was changed # but the mesh and the mesh groups were not created new !?! - obj = fem_object['Object'] + obj = fem_object["Object"] if femmesh.GroupCount: for g in femmesh.Groups: grp_name = femmesh.getGroupName(g) if grp_name.startswith(obj.Name + "_"): if femmesh.getGroupElementType(g) == group_data_type: FreeCAD.Console.PrintMessage( - ' found mesh group for the IDs: {}, Type: {}\n' + " found mesh group for the IDs: {}, Type: {}\n" .format(grp_name, group_data_type) ) return femmesh.getGroupElements(g) # == ref_shape_femelements @@ -695,24 +695,24 @@ def get_femelement_sets_from_group_data( count_femelements = 0 sum_group_elements = [] for fem_object_i, fem_object in enumerate(fem_objects): - obj = fem_object['Object'] + obj = fem_object["Object"] FreeCAD.Console.PrintMessage( "Constraint: {} --> We have mesh groups. " "We will search for appropriate group data.\n" .format(obj.Name) ) # unique short identifier - fem_object['ShortName'] = get_elset_short_name(obj, fem_object_i) + fem_object["ShortName"] = get_elset_short_name(obj, fem_object_i) # see comments over there ! - group_elements = get_femmesh_groupdata_sets_by_name(femmesh, fem_object, 'Volume') + group_elements = get_femmesh_groupdata_sets_by_name(femmesh, fem_object, "Volume") sum_group_elements += group_elements count_femelements += len(group_elements) - fem_object['FEMElements'] = group_elements + fem_object["FEMElements"] = group_elements # check if all worked out well if not femelements_count_ok(femmesh.VolumeCount, count_femelements): FreeCAD.Console.PrintError( - 'Error in get_femelement_sets_from_group_data -- > ' - 'femelements_count_ok() failed!\n' + "Error in get_femelement_sets_from_group_data -- > " + "femelements_count_ok() failed!\n" ) return False else: @@ -724,20 +724,20 @@ def get_elset_short_name( obj, i ): - if hasattr(obj, "Proxy") and obj.Proxy.Type == 'Fem::Material': - return 'M' + str(i) - elif hasattr(obj, "Proxy") and obj.Proxy.Type == 'Fem::FemElementGeometry1D': - return 'B' + str(i) - elif hasattr(obj, "Proxy") and obj.Proxy.Type == 'Fem::FemElementRotation1D': - return 'R' + str(i) - elif hasattr(obj, "Proxy") and obj.Proxy.Type == 'Fem::FemElementFluid1D': - return 'F' + str(i) - elif hasattr(obj, "Proxy") and obj.Proxy.Type == 'Fem::FemElementGeometry2D': - return 'S' + str(i) + if hasattr(obj, "Proxy") and obj.Proxy.Type == "Fem::Material": + return "M" + str(i) + elif hasattr(obj, "Proxy") and obj.Proxy.Type == "Fem::FemElementGeometry1D": + return "B" + str(i) + elif hasattr(obj, "Proxy") and obj.Proxy.Type == "Fem::FemElementRotation1D": + return "R" + str(i) + elif hasattr(obj, "Proxy") and obj.Proxy.Type == "Fem::FemElementFluid1D": + return "F" + str(i) + elif hasattr(obj, "Proxy") and obj.Proxy.Type == "Fem::FemElementGeometry2D": + return "S" + str(i) else: FreeCAD.Console.PrintError( - 'Error in creating short elset name ' - 'for obj: {} --> Proxy.Type: {}\n' + "Error in creating short elset name " + "for obj: {} --> Proxy.Type: {}\n" .format(obj.Name, obj.Proxy.Type) ) @@ -751,9 +751,9 @@ def get_force_obj_vertex_nodeload_table( ): # force_obj_node_load_table: # [ - # ('refshape_name.elemname', node_load_table), + # ("refshape_name.elemname", node_load_table), # ..., - # ('refshape_name.elemname', node_load_table) + # ("refshape_name.elemname", node_load_table) # ] force_obj_node_load_table = [] node_load = frc_obj.Force / len(frc_obj.References) @@ -762,15 +762,15 @@ def get_force_obj_vertex_nodeload_table( for elem in elem_tup: ref_node = o.Shape.getElement(elem) FreeCAD.Console.PrintMessage( - ' ' - 'ReferenceShape ... Type: {0}, ' - 'Object name: {1}, ' - 'Object label: {2}, ' - 'Element name: {3}\n' + " " + "ReferenceShape ... Type: {0}, " + "Object name: {1}, " + "Object label: {2}, " + "Element name: {3}\n" .format(ref_node.ShapeType, o.Name, o.Label, elem) ) node = femmesh.getNodesByVertex(ref_node) - elem_info_string = 'node load on shape: ' + o.Name + ':' + elem + elem_info_string = "node load on shape: " + o.Name + ":" + elem force_obj_node_load_table.append( (elem_info_string, {node[0]: node_load / node_count}) ) @@ -789,9 +789,9 @@ def get_force_obj_edge_nodeload_table( ): # force_obj_node_load_table: # [ - # ('refshape_name.elemname', node_load_table), + # ("refshape_name.elemname", node_load_table), # ..., - # ('refshape_name.elemname', node_load_table) + # ("refshape_name.elemname", node_load_table) # ] force_obj_node_load_table = [] sum_ref_edge_length = 0 @@ -801,11 +801,11 @@ def get_force_obj_edge_nodeload_table( for elem in elem_tup: ref_edge = o.Shape.getElement(elem) FreeCAD.Console.PrintMessage( - ' ' - 'ReferenceShape ... Type: {0}, ' - 'Object name: {1}, ' - 'Object label: {2}, ' - 'Element name: {3}\n' + " " + "ReferenceShape ... Type: {0}, " + "Object name: {1}, " + "Object label: {2}, " + "Element name: {3}\n" .format(ref_edge.ShapeType, o.Name, o.Label, elem) ) sum_ref_edge_length += ref_edge.Length @@ -840,14 +840,14 @@ def get_force_obj_edge_nodeload_table( ratio_refedge_lengths = sum_node_lengths / ref_edge.Length if ratio_refedge_lengths < 0.99 or ratio_refedge_lengths > 1.01: FreeCAD.Console.PrintError( - 'Error on: ' + frc_obj.Name + ' --> ' + o.Name + '.' + elem + '\n' + "Error on: " + frc_obj.Name + " --> " + o.Name + "." + elem + "\n" ) - FreeCAD.Console.PrintMessage(' sum_node_lengths: {}\n'.format(sum_node_lengths)) - FreeCAD.Console.PrintMessage(' refedge_length: {}\n'.format(ref_edge.Length)) + FreeCAD.Console.PrintMessage(" sum_node_lengths: {}\n".format(sum_node_lengths)) + FreeCAD.Console.PrintMessage(" refedge_length: {}\n".format(ref_edge.Length)) bad_refedge = ref_edge sum_ref_edge_node_length += sum_node_lengths - elem_info_string = 'node loads on shape: ' + o.Name + ':' + elem + elem_info_string = "node loads on shape: " + o.Name + ":" + elem force_obj_node_load_table.append((elem_info_string, node_load_table)) for ref_shape in force_obj_node_load_table: @@ -857,74 +857,74 @@ def get_force_obj_edge_nodeload_table( ratio = sum_node_load / frc_obj.Force if ratio < 0.99 or ratio > 1.01: FreeCAD.Console.PrintMessage( - 'Deviation sum_node_load to frc_obj.Force is more than 1% : {}\n' + "Deviation sum_node_load to frc_obj.Force is more than 1% : {}\n" .format(ratio) ) FreeCAD.Console.PrintMessage( - ' sum_ref_edge_node_length: {}\n' + " sum_ref_edge_node_length: {}\n" .format(sum_ref_edge_node_length) ) FreeCAD.Console.PrintMessage( - ' sum_ref_edge_length: {}\n' + " sum_ref_edge_length: {}\n" .format(sum_ref_edge_length) ) FreeCAD.Console.PrintMessage( - ' sum_node_load: {}\n' + " sum_node_load: {}\n" .format(sum_node_load) ) FreeCAD.Console.PrintMessage( - ' frc_obj.Force: {}\n' + " frc_obj.Force: {}\n" .format(frc_obj.Force) ) FreeCAD.Console.PrintMessage( - ' the reason could be simply a circle length --> ' - 'see method get_ref_edge_node_lengths\n' + " the reason could be simply a circle length --> " + "see method get_ref_edge_node_lengths\n" ) FreeCAD.Console.PrintMessage( - ' the reason could also be a problem in ' - 'retrieving the ref_edge_node_length\n' + " the reason could also be a problem in " + "retrieving the ref_edge_node_length\n" ) # try debugging of the last bad refedge - FreeCAD.Console.PrintMessage('DEBUGGING\n') - FreeCAD.Console.PrintMessage('\n'.format(bad_refedge)) + FreeCAD.Console.PrintMessage("DEBUGGING\n") + FreeCAD.Console.PrintMessage("\n".format(bad_refedge)) - FreeCAD.Console.PrintMessage('bad_refedge_nodes\n') + FreeCAD.Console.PrintMessage("bad_refedge_nodes\n") bad_refedge_nodes = femmesh.getNodesByEdge(bad_refedge) - FreeCAD.Console.PrintMessage('{}\n'.format(len(bad_refedge_nodes))) - FreeCAD.Console.PrintMessage('{}\n'.format(bad_refedge_nodes)) + FreeCAD.Console.PrintMessage("{}\n".format(len(bad_refedge_nodes))) + FreeCAD.Console.PrintMessage("{}\n".format(bad_refedge_nodes)) # import FreeCADGui # FreeCADGui.ActiveDocument.Compound_Mesh.HighlightedNodes = bad_refedge_nodes - FreeCAD.Console.PrintMessage('bad_edge_table\n') + FreeCAD.Console.PrintMessage("bad_edge_table\n") # bad_edge_table: # { meshedgeID : ( nodeID, ... , nodeID ) } bad_edge_table = get_ref_edgenodes_table(femmesh, femelement_table, bad_refedge) - FreeCAD.Console.PrintMessage('{}\n'.format(len(bad_edge_table))) + FreeCAD.Console.PrintMessage("{}\n".format(len(bad_edge_table))) bad_edge_table_nodes = [] for elem in bad_edge_table: - FreeCAD.Console.PrintMessage(elem, ' --> \n'.format(bad_edge_table[elem])) + FreeCAD.Console.PrintMessage(elem, " --> \n".format(bad_edge_table[elem])) for node in bad_edge_table[elem]: if node not in bad_edge_table_nodes: bad_edge_table_nodes.append(node) - FreeCAD.Console.PrintMessage('sorted(bad_edge_table_nodes)\n') + FreeCAD.Console.PrintMessage("sorted(bad_edge_table_nodes)\n") # should be == bad_refedge_nodes - FreeCAD.Console.PrintMessage('{}\n'.format(sorted(bad_edge_table_nodes))) + FreeCAD.Console.PrintMessage("{}\n".format(sorted(bad_edge_table_nodes))) # import FreeCADGui # FreeCADGui.ActiveDocument.Compound_Mesh.HighlightedNodes = bad_edge_table_nodes # bad_node_length_table: # [ (nodeID, length), ... , (nodeID, length) ] # some nodes will have more than one entry - FreeCAD.Console.PrintMessage('good_edge_table\n') + FreeCAD.Console.PrintMessage("good_edge_table\n") good_edge_table = delete_duplicate_mesh_elements(bad_edge_table) for elem in good_edge_table: - FreeCAD.Console.PrintMessage('{} --> {}\n'.format(elem, bad_edge_table[elem])) + FreeCAD.Console.PrintMessage("{} --> {}\n".format(elem, bad_edge_table[elem])) - FreeCAD.Console.PrintMessage('bad_node_length_table\n') + FreeCAD.Console.PrintMessage("bad_node_length_table\n") bad_node_length_table = get_ref_edgenodes_lengths(femnodes_mesh, bad_edge_table) for n, l in bad_node_length_table: - FreeCAD.Console.PrintMessage('{} --> {}\n'.format(n, l)) + FreeCAD.Console.PrintMessage("{} --> {}\n".format(n, l)) return force_obj_node_load_table @@ -1012,7 +1012,7 @@ def get_ref_edgenodes_lengths( return [] node_length_table = [] mesh_edge_length = 0 - # FreeCAD.Console.PrintMessage('{}\n'.format(len(edge_table))) + # FreeCAD.Console.PrintMessage("{}\n".format(len(edge_table))) for me in edge_table: femmesh_edgetype = len(edge_table[me]) if femmesh_edgetype == 2: # 2 node femmesh edge @@ -1023,7 +1023,7 @@ def get_ref_edgenodes_lengths( P2 = femnodes_mesh[edge_table[me][1]] edge_vec = P2 - P1 mesh_edge_length = edge_vec.Length - # FreeCAD.Console.PrintMessage('{}\n'.format(mesh_edge_length)) + # FreeCAD.Console.PrintMessage("{}\n".format(mesh_edge_length)) end_node_length = mesh_edge_length / 2.0 node_length_table.append((edge_table[me][0], end_node_length)) node_length_table.append((edge_table[me][1], end_node_length)) @@ -1039,7 +1039,7 @@ def get_ref_edgenodes_lengths( edge_vec1 = P3 - P1 edge_vec2 = P2 - P3 mesh_edge_length = edge_vec1.Length + edge_vec2.Length - # FreeCAD.Console.PrintMessage('{} --> {}\n'.format(me, mesh_edge_length)) + # FreeCAD.Console.PrintMessage("{} --> {}\n".format(me, mesh_edge_length)) end_node_length = mesh_edge_length / 6.0 middle_node_length = mesh_edge_length * 2.0 / 3.0 node_length_table.append((edge_table[me][0], end_node_length)) @@ -1061,9 +1061,9 @@ def get_force_obj_face_nodeload_table( ): # force_obj_node_load_table: # [ - # ('refshape_name.elemname',node_load_table), + # ("refshape_name.elemname",node_load_table), # ..., - # ('refshape_name.elemname',node_load_table) + # ("refshape_name.elemname",node_load_table) # ] force_obj_node_load_table = [] sum_ref_face_area = 0 @@ -1073,11 +1073,11 @@ def get_force_obj_face_nodeload_table( for elem in elem_tup: ref_face = o.Shape.getElement(elem) FreeCAD.Console.PrintMessage( - ' ' - 'ReferenceShape ... Type: {0}, ' - 'Object name: {1}, ' - 'Object label: {2}, ' - 'Element name: {3}\n' + " " + "ReferenceShape ... Type: {0}, " + "Object name: {1}, " + "Object label: {2}, " + "Element name: {3}\n" .format(ref_face.ShapeType, o.Name, o.Label, elem) ) sum_ref_face_area += ref_face.Area @@ -1112,13 +1112,13 @@ def get_force_obj_face_nodeload_table( ratio_refface_areas = sum_node_areas / ref_face.Area if ratio_refface_areas < 0.99 or ratio_refface_areas > 1.01: FreeCAD.Console.PrintError( - 'Error on: ' + frc_obj.Name + ' --> ' + o.Name + '.' + elem + '\n' + "Error on: " + frc_obj.Name + " --> " + o.Name + "." + elem + "\n" ) - FreeCAD.Console.PrintMessage(' sum_node_areas: {}\n'.format(sum_node_areas)) - FreeCAD.Console.PrintMessage(' ref_face_area: {}\n'.format(ref_face.Area)) + FreeCAD.Console.PrintMessage(" sum_node_areas: {}\n".format(sum_node_areas)) + FreeCAD.Console.PrintMessage(" ref_face_area: {}\n".format(ref_face.Area)) sum_ref_face_node_area += sum_node_areas - elem_info_string = 'node loads on shape: ' + o.Name + ':' + elem + elem_info_string = "node loads on shape: " + o.Name + ":" + elem force_obj_node_load_table.append((elem_info_string, node_load_table)) for ref_shape in force_obj_node_load_table: @@ -1128,32 +1128,32 @@ def get_force_obj_face_nodeload_table( ratio = sum_node_load / frc_obj.Force if ratio < 0.99 or ratio > 1.01: FreeCAD.Console.PrintMessage( - 'Deviation sum_node_load to frc_obj.Force is more than 1% : {}\n' + "Deviation sum_node_load to frc_obj.Force is more than 1% : {}\n" .format(ratio) ) FreeCAD.Console.PrintMessage( - ' sum_ref_face_node_area: {}\n' + " sum_ref_face_node_area: {}\n" .format(sum_ref_face_node_area) ) FreeCAD.Console.PrintMessage( - ' sum_ref_face_area: {}\n' + " sum_ref_face_area: {}\n" .format(sum_ref_face_area) ) FreeCAD.Console.PrintMessage( - ' sum_node_load: {}\n' + " sum_node_load: {}\n" .format(sum_node_load) ) FreeCAD.Console.PrintMessage( - ' frc_obj.Force: {}\n' + " frc_obj.Force: {}\n" .format(frc_obj.Force) ) FreeCAD.Console.PrintMessage( - ' the reason could be simply a circle area --> ' - 'see method get_ref_face_node_areas\n' + " the reason could be simply a circle area --> " + "see method get_ref_face_node_areas\n" ) FreeCAD.Console.PrintMessage( - ' the reason could also be a problem in ' - 'retrieving the ref_face_node_area\n' + " the reason could also be a problem in " + "retrieving the ref_face_node_area\n" ) return force_obj_node_load_table @@ -1169,9 +1169,9 @@ def get_ref_facenodes_table( if is_solid_femmesh(femmesh): if has_no_face_data(femmesh): FreeCAD.Console.PrintMessage( - ' No face data in finite volume element mesh. ' - 'FreeCAD uses getccxVolumesByFace() ' - 'to retrieve the volume elements of the ref_face.\n' + " No face data in finite volume element mesh. " + "FreeCAD uses getccxVolumesByFace() " + "to retrieve the volume elements of the ref_face.\n" ) # there is no face data # if we retrieve the nodes ourself we will have a problem: @@ -1186,8 +1186,8 @@ def get_ref_facenodes_table( ref_face_volume_elements = femmesh.getccxVolumesByFace(ref_face) if ref_face_volume_elements: # mesh with tetras FreeCAD.Console.PrintLog( - ' Use of getccxVolumesByFace() has ' - 'returned volume elements of the ref_face.\n' + " Use of getccxVolumesByFace() has " + "returned volume elements of the ref_face.\n" ) for ve in ref_face_volume_elements: veID = ve[0] @@ -1199,9 +1199,9 @@ def get_ref_facenodes_table( face_table[veID] = ve_ref_face_nodes else: # mesh with hexa or penta FreeCAD.Console.PrintLog( - ' The use of getccxVolumesByFace() has NOT returned ' - 'volume elements of the ref_face. ' - 'FreeCAD tries to use get_femvolumeelements_by_femfacenodes().\n' + " The use of getccxVolumesByFace() has NOT returned " + "volume elements of the ref_face. " + "FreeCAD tries to use get_femvolumeelements_by_femfacenodes().\n" ) # list of integer [mv] ref_face_volume_elements = get_femvolumeelements_by_femfacenodes( @@ -1226,7 +1226,7 @@ def get_ref_facenodes_table( ref_face_elements = get_femelements_by_femnodes_std(femelement_table, ref_face_nodes) for mf in ref_face_elements: face_table[mf] = femelement_table[mf] - # FreeCAD.Console.PrintMessage('{}\n'.format(face_table)) + # FreeCAD.Console.PrintMessage("{}\n".format(face_table)) return face_table @@ -1397,13 +1397,13 @@ def build_mesh_faces_of_volume_elements( face_nodenumber_table[veID] = [] for n in face_table[veID]: index = femelement_table[veID].index(n) - # FreeCAD.Console.PrintMessage('{}\n'.format(index)) + # FreeCAD.Console.PrintMessage("{}\n".format(index)) # local node number = index + 1 face_nodenumber_table[veID].append(index + 1) - FreeCAD.Console.PrintLog('VolElement: {}\n'.format(veID)) - FreeCAD.Console.PrintLog(' --> {}\n'.format(femelement_table[veID])) - FreeCAD.Console.PrintLog(' --> {}\n'.format(face_table[veID])) - FreeCAD.Console.PrintLog(' --> {}\n'.format(face_nodenumber_table[veID])) + FreeCAD.Console.PrintLog("VolElement: {}\n".format(veID)) + FreeCAD.Console.PrintLog(" --> {}\n".format(femelement_table[veID])) + FreeCAD.Console.PrintLog(" --> {}\n".format(face_table[veID])) + FreeCAD.Console.PrintLog(" --> {}\n".format(face_nodenumber_table[veID])) for veID in face_nodenumber_table: vol_node_ct = len(femelement_table[veID]) face_node_indexs = sorted(face_nodenumber_table[veID]) @@ -1539,7 +1539,7 @@ def build_mesh_faces_of_volume_elements( # index = node number - 1i -= 1 face_nodes.append(femelement_table[veID][i]) face_table[veID] = face_nodes # reset the entry in face_table - # FreeCAD.Console.PrintMessage(' --> {}\n'.format(face_table[veID])) + # FreeCAD.Console.PrintMessage(" --> {}\n".format(face_table[veID])) return face_table @@ -1551,7 +1551,7 @@ def get_ref_shape_node_sum_geom_table( # sum of length or area for each node of the ref_shape node_sum_geom_table = {} for n, A in node_geom_table: - # FreeCAD.Console.PrintMessage('{} --> {}\n'.format(n, A)) + # FreeCAD.Console.PrintMessage("{} --> {}\n".format(n, A)) if n in node_sum_geom_table: node_sum_geom_table[n] = node_sum_geom_table[n] + A else: @@ -1571,7 +1571,7 @@ def get_pressure_obj_faces( # get the nodes # sorted and duplicates removed prs_face_node_set = get_femnodes_by_femobj_with_references(femmesh, femobj) - # FreeCAD.Console.PrintMessage('prs_face_node_set: {}\n'.format(prs_face_node_set)) + # FreeCAD.Console.PrintMessage("prs_face_node_set: {}\n".format(prs_face_node_set)) # fill the bit_pattern_dict and search for the faces bit_pattern_dict = get_bit_pattern_dict( femelement_table, @@ -1584,8 +1584,8 @@ def get_pressure_obj_faces( # normally we should call get_femelements_by_references and # the group check should be integrated there if femmesh.GroupCount: - meshfaces = get_femmesh_groupdata_sets_by_name(femmesh, femobj, 'Face') - # FreeCAD.Console.PrintMessage('{}\n'.format(meshfaces)) + meshfaces = get_femmesh_groupdata_sets_by_name(femmesh, femobj, "Face") + # FreeCAD.Console.PrintMessage("{}\n".format(meshfaces)) if not meshfaces: FreeCAD.Console.PrintError( "Error: Something went wrong in getting the group element faces.\n" @@ -1615,12 +1615,12 @@ def get_pressure_obj_faces_depreciated( femobj ): pressure_faces = [] - for o, elem_tup in femobj['Object'].References: + for o, elem_tup in femobj["Object"].References: for elem in elem_tup: ref_shape = o.Shape.getElement(elem) - elem_info_string = 'face load on shape: ' + o.Name + ':' + elem - FreeCAD.Console.PrintMessage('{}\n'.format(elem_info_string)) - if ref_shape.ShapeType == 'Face': + elem_info_string = "face load on shape: " + o.Name + ":" + elem + FreeCAD.Console.PrintMessage("{}\n".format(elem_info_string)) + if ref_shape.ShapeType == "Face": pressure_faces.append( (elem_info_string, femmesh.getccxVolumesByFace(ref_shape)) ) @@ -1633,17 +1633,17 @@ def get_mesh_group_elements( mesh_group_obj, aPart ): - '''the Reference shapes of the mesh_group_object are searched in the Shape of aPart. + """the Reference shapes of the mesh_group_object are searched in the Shape of aPart. If found in shape they are added to a dict - {MeshGroupIdentifier : ['ShapeType of the Elements'], [ElementID, ElementID, ...], ...} - ''' + {MeshGroupIdentifier : ["ShapeType of the Elements"], [ElementID, ElementID, ...], ...} + """ group_elements = {} # { name : [element, element, ... , element]} if mesh_group_obj.References: grp_ele = get_reference_group_elements(mesh_group_obj, aPart) group_elements[grp_ele[0]] = grp_ele[1] else: FreeCAD.Console.PrintError( - ' Empty reference in mesh group object: {} {}\n' + " Empty reference in mesh group object: {} {}\n" .format(mesh_group_obj.Name, mesh_group_obj.Label) ) return group_elements @@ -1654,10 +1654,10 @@ def get_analysis_group_elements( aAnalysis, aPart ): - ''' all Reference shapes of all Analysis member are searched in the Shape of aPart. + """ all Reference shapes of all Analysis member are searched in the Shape of aPart. If found in shape they are added to a dict - {ConstraintName : ['ShapeType of the Elements'], [ElementID, ElementID, ...], ...} - ''' + {ConstraintName : ["ShapeType of the Elements"], [ElementID, ElementID, ...], ...} + """ group_elements = {} # { name : [element, element, ... , element]} empty_references = [] for m in aAnalysis.Group: @@ -1668,7 +1668,7 @@ def get_analysis_group_elements( grp_ele = get_reference_group_elements(m, aPart) group_elements[grp_ele[0]] = grp_ele[1] else: - FreeCAD.Console.PrintMessage(' Empty reference: ' + m.Name + '\n') + FreeCAD.Console.PrintMessage(" Empty reference: " + m.Name + "\n") empty_references.append(m) if empty_references: if len(empty_references) == 1: @@ -1679,29 +1679,29 @@ def get_analysis_group_elements( ) else: FreeCAD.Console.PrintError( - 'Problem: more than one object with empty references.\n' + "Problem: more than one object with empty references.\n" ) FreeCAD.Console.PrintMessage( - 'We are going to try to get the empty material references anyway.\n' + "We are going to try to get the empty material references anyway.\n" ) # FemElementGeometry2D, ElementGeometry1D and # FemElementFluid1D could have empty references, # but on solid meshes only materials should have empty references for er in empty_references: - FreeCAD.Console.PrintMessage(er.Name + '\n') + FreeCAD.Console.PrintMessage(er.Name + "\n") group_elements = get_anlysis_empty_references_group_elements( group_elements, aAnalysis, aPart.Shape ) # check if all groups have at least one element, - # it doesn't mean ALL reference shapes for a group have been found + # it doesn"t mean ALL reference shapes for a group have been found for g in group_elements: - # FreeCAD.Console.PrintMessage('{}\n'.format(group_elements[g])) + # FreeCAD.Console.PrintMessage("{}\n".format(group_elements[g])) if len(group_elements[g]) == 0: FreeCAD.Console.PrintError( - 'Error: The shapes for the mesh group for the reference ' - 'shapes of analysis member: {} could not be found!\n' + "Error: The shapes for the mesh group for the reference " + "shapes of analysis member: {} could not be found!\n" .format(g) ) return group_elements @@ -1712,14 +1712,14 @@ def get_reference_group_elements( obj, aPart ): - ''' obj is an FEM object which has reference shapes like the group object + """ obj is an FEM object which has reference shapes like the group object the material, most of the constraints aPart is geometry feature normally CompSolid the method searches all reference shapes of obj inside aPart even if the reference shapes are a totally different geometry feature. - a tuple is returned ('Name or Label of the FEMobject', ['Element1', 'Element2', ...]) + a tuple is returned ("Name or Label of the FEMobject", ["Element1", "Element2", ...]) The names in the list are the Elements of the geometry aPart - whereas 'Solid1' == aPart.Shape.Solids[0] + whereas "Solid1" == aPart.Shape.Solids[0] !!! It is strongly recommended to use as reference shapes the Solids of a CompSolid and not the Solids the CompSolid is made of !!! see https://forum.freecadweb.org/viewtopic.php?f=18&t=12212&p=175777#p175777 @@ -1727,7 +1727,7 @@ def get_reference_group_elements( Occt might change the Solids a CompSolid is made of during creation of the CompSolid by adding Edges and vertices Thus the Elements do not have the same geometry anymore - ''' + """ aShape = aPart.Shape if hasattr(obj, "UseLabel") and obj.UseLabel: # TODO: check the character of the Label @@ -1740,8 +1740,8 @@ def get_reference_group_elements( for r in obj.References: parent = r[0] childs = r[1] - # FreeCAD.Console.PrintMessage('{}\n'.format(parent)) - # FreeCAD.Console.PrintMessage('{}\n'.format(childs)) + # FreeCAD.Console.PrintMessage("{}\n".format(parent)) + # FreeCAD.Console.PrintMessage("{}\n".format(childs)) for child in childs: # the method getElement(element) does not return Solid elements ref_shape = get_element(parent, child) @@ -1749,42 +1749,42 @@ def get_reference_group_elements( stype = ref_shape.ShapeType elif stype != ref_shape.ShapeType: FreeCAD.Console.PrintError( - 'Error, two refshapes in References with different ShapeTypes.\n' + "Error, two refshapes in References with different ShapeTypes.\n" ) - FreeCAD.Console.PrintLog('\n'.format(ref_shape)) + FreeCAD.Console.PrintLog("\n".format(ref_shape)) found_element = find_element_in_shape(aShape, ref_shape) if found_element is not None: elements.append(found_element) else: FreeCAD.Console.PrintError( - 'Problem: For the geometry of the ' - 'following shape was no Shape found: {}\n' + "Problem: For the geometry of the " + "following shape was no Shape found: {}\n" .format(ref_shape) ) - FreeCAD.Console.PrintMessage(' ' + obj.Name + '\n') - FreeCAD.Console.PrintMessage(' ' + str(obj.References) + '\n') - FreeCAD.Console.PrintMessage(' ' + r[0].Name + '\n') + FreeCAD.Console.PrintMessage(" " + obj.Name + "\n") + FreeCAD.Console.PrintMessage(" " + str(obj.References) + "\n") + FreeCAD.Console.PrintMessage(" " + r[0].Name + "\n") if parent.Name != aPart.Name: FreeCAD.Console.PrintError( - 'The reference Shape is not a child ' - 'nor it is the shape the mesh is made of. : {}\n' + "The reference Shape is not a child " + "nor it is the shape the mesh is made of. : {}\n" .format(ref_shape) ) FreeCAD.Console.PrintMessage( - '{}--> Name of the Feature we where searching in.\n' + "{}--> Name of the Feature we where searching in.\n" .format(aPart.Name) ) FreeCAD.Console.PrintMessage( - '{} --> Name of the parent Feature of reference Shape ' - '(Use the same as in the line before and you ' - 'will have less trouble :-) !!!!!!).\n' + "{} --> Name of the parent Feature of reference Shape " + "(Use the same as in the line before and you " + "will have less trouble :-) !!!!!!).\n" .format(parent.Name) ) # import Part # Part.show(aShape) # Part.show(ref_shape) else: - FreeCAD.Console.PrintError('This should not happen, please debug!\n') + FreeCAD.Console.PrintError("This should not happen, please debug!\n") # in this case we would not have needed to use the # is_same_geometry() inside find_element_in_shape() # AFAIK we could have used the Part methods isPartner() or even isSame() @@ -1798,16 +1798,16 @@ def get_anlysis_empty_references_group_elements( aAnalysis, aShape ): - '''get the elementIDs if the Reference shape is empty + """get the elementIDs if the Reference shape is empty see get_analysis_group_elements() for more information on solid meshes only material objects could have an empty reference without there being something wrong! face meshes could have empty ShellThickness and edge meshes could have empty BeamSection/FluidSection - ''' - # FreeCAD.Console.PrintMessage('{}\n'.format(group_elements)) + """ + # FreeCAD.Console.PrintMessage("{}\n".format(group_elements)) material_ref_shapes = [] - material_shape_type = '' + material_shape_type = "" missed_material_refshapes = [] empty_reference_material = None for m in aAnalysis.Group: @@ -1817,52 +1817,52 @@ def get_anlysis_empty_references_group_elements( empty_reference_material = m.Name else: FreeCAD.Console.PrintError( - 'Problem in get_anlysis_empty_references_group_elements, ' - 'we seem to have two or more materials with empty references\n' + "Problem in get_anlysis_empty_references_group_elements, " + "we seem to have two or more materials with empty references\n" ) return {} elif hasattr(m, "References") and m.References: # ShapeType of the group elements, strip the number of the first group element # http://stackoverflow.com/questions/12851791/removing-numbers-from-string - group_shape_type = ''.join(i for i in group_elements[m.Name][0] if not i.isdigit()) + group_shape_type = "".join(i for i in group_elements[m.Name][0] if not i.isdigit()) if not material_shape_type: material_shape_type = group_shape_type elif material_shape_type != group_shape_type: FreeCAD.Console.PrintError( - 'Problem, material shape type does not match ' - 'get_anlysis_empty_references_group_elements\n' + "Problem, material shape type does not match " + "get_anlysis_empty_references_group_elements\n" ) for ele in group_elements[m.Name]: material_ref_shapes.append(ele) - if material_shape_type == 'Solid': - # FreeCAD.Console.PrintMessage('{}\n'.format(len(aShape.Solids))) + if material_shape_type == "Solid": + # FreeCAD.Console.PrintMessage("{}\n".format(len(aShape.Solids))) for i in range(len(aShape.Solids)): - ele = 'Solid' + str(i + 1) + ele = "Solid" + str(i + 1) if ele not in material_ref_shapes: missed_material_refshapes.append(ele) - elif material_shape_type == 'Face': - # FreeCAD.Console.PrintMessage('{}\n'.format(len(aShape.Faces))) + elif material_shape_type == "Face": + # FreeCAD.Console.PrintMessage("{}\n".format(len(aShape.Faces))) for i in range(len(aShape.Faces)): - ele = 'Face' + str(i + 1) + ele = "Face" + str(i + 1) if ele not in material_ref_shapes: missed_material_refshapes.append(ele) - elif material_shape_type == 'Edge': - # FreeCAD.Console.PrintMessage('{}\n'.format(len(aShape.Edges))) + elif material_shape_type == "Edge": + # FreeCAD.Console.PrintMessage("{}\n".format(len(aShape.Edges))) for i in range(len(aShape.Edges)): - ele = 'Edge' + str(i + 1) + ele = "Edge" + str(i + 1) if ele not in material_ref_shapes: missed_material_refshapes.append(ele) else: FreeCAD.Console.PrintMessage( - ' One material with no reference shapes. No need to make a group for materials.\n' + " One material with no reference shapes. No need to make a group for materials.\n" ) # make no changes group_elements return group_elements - # FreeCAD.Console.PrintMessage('{}\n'.format(sorted(material_ref_shapes))) - # FreeCAD.Console.PrintMessage('{}\n'.format(sorted(missed_material_refshapes))) + # FreeCAD.Console.PrintMessage("{}\n".format(sorted(material_ref_shapes))) + # FreeCAD.Console.PrintMessage("{}\n".format(sorted(missed_material_refshapes))) # FreeCAD.Console.PrintMessage(group_elements) group_elements[empty_reference_material] = sorted(missed_material_refshapes) - # FreeCAD.Console.PrintMessage('{}\n'.format(group_elements)) + # FreeCAD.Console.PrintMessage("{}\n".format(group_elements)) return group_elements @@ -1873,52 +1873,52 @@ def find_element_in_shape( ): # import Part ele_st = anElement.ShapeType - if ele_st == 'Solid' or ele_st == 'CompSolid': + if ele_st == "Solid" or ele_st == "CompSolid": for index, solid in enumerate(aShape.Solids): - # FreeCAD.Console.PrintMessage('{}\n'.format(is_same_geometry(solid, anElement))) + # FreeCAD.Console.PrintMessage("{}\n".format(is_same_geometry(solid, anElement))) if is_same_geometry(solid, anElement): - # FreeCAD.Console.PrintMessage('{}\n'.format(index)) + # FreeCAD.Console.PrintMessage("{}\n".format(index)) # Part.show(aShape.Solids[index]) ele = ele_st + str(index + 1) return ele FreeCAD.Console.PrintError( - 'Solid ' + str(anElement) + ' not found in: ' + str(aShape) + '\n' + "Solid " + str(anElement) + " not found in: " + str(aShape) + "\n" ) - if ele_st == 'Solid' and aShape.ShapeType == 'Solid': + if ele_st == "Solid" and aShape.ShapeType == "Solid": message_part = ( - 'We have been searching for a Solid in a Solid and we have not found it. ' - 'In most cases this should be searching for a Solid inside a CompSolid. ' - 'Check the ShapeType of your Part to mesh.' + "We have been searching for a Solid in a Solid and we have not found it. " + "In most cases this should be searching for a Solid inside a CompSolid. " + "Check the ShapeType of your Part to mesh." ) - FreeCAD.Console.PrintMessage(message_part + '\n') + FreeCAD.Console.PrintMessage(message_part + "\n") # Part.show(anElement) # Part.show(aShape) - elif ele_st == 'Face' or ele_st == 'Shell': + elif ele_st == "Face" or ele_st == "Shell": for index, face in enumerate(aShape.Faces): - # FreeCAD.Console.PrintMessage('{}\n'.format(is_same_geometry(face, anElement))) + # FreeCAD.Console.PrintMessage("{}\n".format(is_same_geometry(face, anElement))) if is_same_geometry(face, anElement): - # FreeCAD.Console.PrintMessage('{}\n'.format(index)) + # FreeCAD.Console.PrintMessage("{}\n".format(index)) # Part.show(aShape.Faces[index]) ele = ele_st + str(index + 1) return ele - elif ele_st == 'Edge' or ele_st == 'Wire': + elif ele_st == "Edge" or ele_st == "Wire": for index, edge in enumerate(aShape.Edges): - # FreeCAD.Console.PrintMessage('{}\n'.format(is_same_geometry(edge, anElement))) + # FreeCAD.Console.PrintMessage("{}\n".format(is_same_geometry(edge, anElement))) if is_same_geometry(edge, anElement): - # FreeCAD.Console.PrintMessage(index, '\n') + # FreeCAD.Console.PrintMessage(index, "\n") # Part.show(aShape.Edges[index]) ele = ele_st + str(index + 1) return ele - elif ele_st == 'Vertex': + elif ele_st == "Vertex": for index, vertex in enumerate(aShape.Vertexes): - # FreeCAD.Console.PrintMessage('{}\n'.format(is_same_geometry(vertex, anElement))) + # FreeCAD.Console.PrintMessage("{}\n".format(is_same_geometry(vertex, anElement))) if is_same_geometry(vertex, anElement): - # FreeCAD.Console.PrintMessage('{}\n'.format(index)) + # FreeCAD.Console.PrintMessage("{}\n".format(index)) # Part.show(aShape.Vertexes[index]) ele = ele_st + str(index + 1) return ele - elif ele_st == 'Compound': - FreeCAD.Console.PrintError('Compound is not supported.\n') + elif ele_st == "Compound": + FreeCAD.Console.PrintError("Compound is not supported.\n") # ************************************************************************************************ @@ -1930,44 +1930,44 @@ def get_vertexes_by_element( # import Part ele_vertexes = [] ele_st = anElement.ShapeType - if ele_st == 'Solid' or ele_st == 'CompSolid': + if ele_st == "Solid" or ele_st == "CompSolid": for index, solid in enumerate(aShape.Solids): if is_same_geometry(solid, anElement): for vele in aShape.Solids[index].Vertexes: for i, v in enumerate(aShape.Vertexes): if vele.isSame(v): # use isSame, because orientation could be different ele_vertexes.append(i) - # FreeCAD.Console.PrintMessage(' ' + str(sorted(ele_vertexes)), '\n') + # FreeCAD.Console.PrintMessage(" " + str(sorted(ele_vertexes)), "\n") return ele_vertexes FreeCAD.Console.PrintError( - 'Error, Solid ' + str(anElement) + ' not found in: ' + str(aShape) + '\n' + "Error, Solid " + str(anElement) + " not found in: " + str(aShape) + "\n" ) - elif ele_st == 'Face' or ele_st == 'Shell': + elif ele_st == "Face" or ele_st == "Shell": for index, face in enumerate(aShape.Faces): if is_same_geometry(face, anElement): for vele in aShape.Faces[index].Vertexes: for i, v in enumerate(aShape.Vertexes): if vele.isSame(v): # use isSame, because orientation could be different ele_vertexes.append(i) - # FreeCAD.Console.PrintMessage(' ' + str(sorted(ele_vertexes)) + '\n') + # FreeCAD.Console.PrintMessage(" " + str(sorted(ele_vertexes)) + "\n") return ele_vertexes - elif ele_st == 'Edge' or ele_st == 'Wire': + elif ele_st == "Edge" or ele_st == "Wire": for index, edge in enumerate(aShape.Edges): if is_same_geometry(edge, anElement): for vele in aShape.Edges[index].Vertexes: for i, v in enumerate(aShape.Vertexes): if vele.isSame(v): # use isSame, because orientation could be different ele_vertexes.append(i) - # FreeCAD.Console.PrintMessage(' ' + str(sorted(ele_vertexes)) + '\n') + # FreeCAD.Console.PrintMessage(" " + str(sorted(ele_vertexes)) + "\n") return ele_vertexes - elif ele_st == 'Vertex': + elif ele_st == "Vertex": for index, vertex in enumerate(aShape.Vertexes): if is_same_geometry(vertex, anElement): ele_vertexes.append(index) - # FreeCAD.Console.PrintMessage(' ' + str(sorted(ele_vertexes)) + '\n') + # FreeCAD.Console.PrintMessage(" " + str(sorted(ele_vertexes)) + "\n") return ele_vertexes - elif ele_st == 'Compound': - FreeCAD.Console.PrintError('Compound is not supported.\n') + elif ele_st == "Compound": + FreeCAD.Console.PrintError("Compound is not supported.\n") # ************************************************************************************************ @@ -1979,8 +1979,8 @@ def is_same_geometry( # it is a hack, but I do not know any better ! # check of Volume and Area before starting with the vertices could be added # BoundBox is possible too, but is BB calculations robust?! - # FreeCAD.Console.PrintMessage('{}\n'.format(shape1)) - # FreeCAD.Console.PrintMessage('{}\n'.format(shape2)) + # FreeCAD.Console.PrintMessage("{}\n".format(shape1)) + # FreeCAD.Console.PrintMessage("{}\n".format(shape2)) same_Vertexes = 0 if len(shape1.Vertexes) == len(shape2.Vertexes) and len(shape1.Vertexes) > 1: # compare CenterOfMass @@ -1993,7 +1993,7 @@ def is_same_geometry( if vs1.X == vs2.X and vs1.Y == vs2.Y and vs1.Z == vs2.Z: same_Vertexes += 1 continue - # FreeCAD.Console.PrintMessage('{}\n'.(same_Vertexes)) + # FreeCAD.Console.PrintMessage("{}\n".(same_Vertexes)) if same_Vertexes == len(shape1.Vertexes): return True else: @@ -2014,11 +2014,11 @@ def get_element( part, element ): - if element.startswith('Solid'): - index = int(element.lstrip('Solid')) - 1 + if element.startswith("Solid"): + index = int(element.lstrip("Solid")) - 1 if index >= len(part.Shape.Solids): FreeCAD.Console.PrintError( - 'Index out of range. This Solid does not exist in the Shape!\n' + "Index out of range. This Solid does not exist in the Shape!\n" ) return None else: @@ -2033,18 +2033,18 @@ def femelements_count_ok( count_femelements ): FreeCAD.Console.PrintMessage( - 'Count finite elements as sum of constraints: {}\n' + "Count finite elements as sum of constraints: {}\n" .format(count_femelements) ) FreeCAD.Console.PrintMessage( - 'Count finite elements of the finite element mesh: {}\n' + "Count finite elements of the finite element mesh: {}\n" .format(len_femelement_table) ) if count_femelements == len_femelement_table: return True else: FreeCAD.Console.PrintMessage( - 'ERROR: femelement_table != count_femelements\n' + "ERROR: femelement_table != count_femelements\n" ) return False @@ -2144,8 +2144,8 @@ def get_three_non_colinear_nodes( # Code to obtain three non-colinear nodes on the PlaneRotation support face # nodes_coords --> [(nodenumber, x, y, z), (nodenumber, x, y, z), ...] if not nodes_coords: - FreeCAD.Console.PrintMessage('{}\n'.format(len(nodes_coords))) - FreeCAD.Console.PrintMessage('Error: No nodes in nodes_coords\n') + FreeCAD.Console.PrintMessage("{}\n".format(len(nodes_coords))) + FreeCAD.Console.PrintMessage("Error: No nodes in nodes_coords\n") return [] dum_max = [1, 2, 3, 4, 5, 6, 7, 8, 0] for i in range(len(nodes_coords)): @@ -2180,7 +2180,7 @@ def get_three_non_colinear_nodes( node_dis = [node_3, tot] node_1 = int(dum_max[0]) node_2 = int(dum_max[4]) - FreeCAD.Console.PrintMessage('{}\n'.format([node_1, node_2, node_3])) + FreeCAD.Console.PrintMessage("{}\n".format([node_1, node_2, node_3])) return [node_1, node_2, node_3] @@ -2217,9 +2217,9 @@ def get_rectangular_coords( b_y = B[1] * cos(z_rot) - B[0] * sin(z_rot) A = [a_x, a_y, a_z] B = [b_x, b_y, b_z] - A_coords = str(round(A[0], 4)) + ',' + str(round(A[1], 4)) + ',' + str(round(A[2], 4)) - B_coords = str(round(B[0], 4)) + ',' + str(round(B[1], 4)) + ',' + str(round(B[2], 4)) - coords = A_coords + ',' + B_coords + A_coords = str(round(A[0], 4)) + "," + str(round(A[1], 4)) + "," + str(round(A[2], 4)) + B_coords = str(round(B[0], 4)) + "," + str(round(B[1], 4)) + "," + str(round(B[2], 4)) + coords = A_coords + "," + B_coords return coords @@ -2237,9 +2237,9 @@ def get_cylindrical_coords( Bz = base[2] - 10 * vec[2] A = [Ax, Ay, Az] B = [Bx, By, Bz] - A_coords = str(A[0]) + ',' + str(A[1]) + ',' + str(A[2]) - B_coords = str(B[0]) + ',' + str(B[1]) + ',' + str(B[2]) - coords = A_coords + ',' + B_coords + A_coords = str(A[0]) + "," + str(A[1]) + "," + str(A[2]) + B_coords = str(B[0]) + "," + str(B[1]) + "," + str(B[2]) + coords = A_coords + "," + B_coords return coords @@ -2248,7 +2248,7 @@ def write_D_network_element_to_inputfile( fileName ): # replace B32 elements with D elements for fluid section - f = open(fileName, 'r+') + f = open(fileName, "r+") lines = f.readlines() f.seek(0) for line in lines: @@ -2267,7 +2267,7 @@ def use_correct_fluidinout_ele_def( fileName, fluid_inout_nodes_file ): - f = open(fileName, 'r') + f = open(fileName, "r") cnt = 0 line = f.readline() @@ -2280,7 +2280,7 @@ def use_correct_fluidinout_ele_def( # obtain element line numbers for inlet and outlet while (len(line) > 1): - ind = line.find(',') + ind = line.find(",") elem = line[0:ind] for i in range(len(FluidInletoutlet_ele)): if (elem == FluidInletoutlet_ele[i][0]): @@ -2290,30 +2290,30 @@ def use_correct_fluidinout_ele_def( f.close() # re-define elements for INLET and OUTLET - f = open(fileName, 'r+') + f = open(fileName, "r+") lines = f.readlines() f.seek(0) cnt = 0 elem_counter = 0 FreeCAD.Console.PrintMessage( - '1DFlow inout nodes file: {}\n' + "1DFlow inout nodes file: {}\n" .format(fluid_inout_nodes_file) ) inout_nodes_file = open(fluid_inout_nodes_file, "w") for line in lines: - new_line = '' + new_line = "" for i in range(len(FluidInletoutlet_ele)): if (cnt == FluidInletoutlet_ele[i][2]): elem_counter = elem_counter + 1 - a = line.split(',') + a = line.split(",") for j in range(len(a)): if elem_counter == 1: if j == 1: - new_line = new_line + ' 0,' + new_line = new_line + " 0," node1 = int(a[j + 2]) node2 = int(a[j + 1]) node3 = int(a[j]) - inout_nodes_file.write('{},{},{},{}\n'.format( + inout_nodes_file.write("{},{},{},{}\n".format( node1, node2, node3, @@ -2322,22 +2322,22 @@ def use_correct_fluidinout_ele_def( elif j == 3: new_line = new_line + a[j] else: - new_line = new_line + a[j] + ',' + new_line = new_line + a[j] + "," else: if j == 3: - new_line = new_line + ' 0\n' + new_line = new_line + " 0\n" node1 = int(a[j - 2]) node2 = int(a[j - 1]) node3 = int(a[j]) - inout_nodes_file.write('{},{},{},{}\n'.format( + inout_nodes_file.write("{},{},{},{}\n".format( node1, node2, node3, FluidInletoutlet_ele[i][1] )) else: - new_line = new_line + a[j] + ',' - if new_line == '': + new_line = new_line + a[j] + "," + if new_line == "": f.write(line) else: f.write(new_line) @@ -2351,10 +2351,10 @@ def use_correct_fluidinout_ele_def( def compact_mesh( old_femmesh ): - ''' + """ removes all gaps in node and element ids, start ids with 1 returns a tuple (FemMesh, node_assignment_map, element_assignment_map) - ''' + """ node_map = {} # {old_node_id: new_node_id, ...} elem_map = {} # {old_elem_id: new_elem_id, ...} old_nodes = old_femmesh.Nodes From 44a47e278d4bfa9877f898abea510ddcff531a52 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Wed, 28 Aug 2019 21:47:45 +0200 Subject: [PATCH 11/23] FEM: mesh tools, typo --- src/Mod/Fem/femmesh/meshtools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Fem/femmesh/meshtools.py b/src/Mod/Fem/femmesh/meshtools.py index e1bc9e85d1..aae871210d 100644 --- a/src/Mod/Fem/femmesh/meshtools.py +++ b/src/Mod/Fem/femmesh/meshtools.py @@ -671,7 +671,7 @@ def get_femmesh_groupdata_sets_by_name( # no check is done in this regard !!! # we just check for the group name and the group data type # what happens if a reference shape was changed - # but the mesh and the mesh groups were not created new !?! + # but the mesh and the mesh groups where not created new !?! obj = fem_object["Object"] if femmesh.GroupCount: for g in femmesh.Groups: From 7b13ebf47dad788dd3e647ea109a0753b42773ca Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Wed, 28 Aug 2019 21:47:45 +0200 Subject: [PATCH 12/23] Arch: import IFC helper, small code formating --- src/Mod/Arch/importIFCHelper.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/Arch/importIFCHelper.py b/src/Mod/Arch/importIFCHelper.py index 3e0dd5d02c..4b52931c14 100644 --- a/src/Mod/Arch/importIFCHelper.py +++ b/src/Mod/Arch/importIFCHelper.py @@ -362,7 +362,7 @@ def getScaling(ifcfile): for u in ua.Units: if u.UnitType == "LENGTHUNIT": if u.is_a("IfcConversionBasedUnit"): - f = getUnit(u.ConversionFactor.UnitComponent) + f = getUnit(u.ConversionFactor.UnitComponent) return f * u.ConversionFactor.ValueComponent.wrappedValue elif u.is_a("IfcSIUnit") or u.is_a("IfcUnit"): return getUnit(u) @@ -425,7 +425,7 @@ def getVector(entity,scaling=1000): v = None if entity.is_a("IfcDirection"): if len(entity.DirectionRatios) == 3: - v= FreeCAD.Vector(tuple(entity.DirectionRatios)) + v = FreeCAD.Vector(tuple(entity.DirectionRatios)) else: v = FreeCAD.Vector(tuple(entity.DirectionRatios+[0])) elif entity.is_a("IfcCartesianPoint"): From d3c31c131b244307ce2474016ecbf24990e7fb1d Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Wed, 28 Aug 2019 21:47:49 +0200 Subject: [PATCH 13/23] Arch: import IFC helper, some comment and rename property rel method --- src/Mod/Arch/importIFCHelper.py | 83 +++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/src/Mod/Arch/importIFCHelper.py b/src/Mod/Arch/importIFCHelper.py index 4b52931c14..6a75ae6659 100644 --- a/src/Mod/Arch/importIFCHelper.py +++ b/src/Mod/Arch/importIFCHelper.py @@ -239,9 +239,16 @@ def buildRelMattable(ifcfile): return mattable +# ************************************************************************************************ +# color relation tables +# products can have a color and materials can have a color and products can have a material +# colors for material assigned to a product and product color can be different + + def buildRelColors(ifcfile, prodrepr): """build the colors relation table and""" + # returns all IfcStyledItem colors, material and product colors colors = {} # { id:(r,g,b) } style_material_id = {} # { style_entity_id: material_id) } @@ -269,12 +276,13 @@ def buildRelColors(ifcfile, prodrepr): for p in prodrepr.keys(): if r.Item.id() in prodrepr[p]: style_material_id[r.id()] = p - # print(p) + # print(p) # print(ifcfile[p]) # product ''' # a much faster version for Nova style_material_id with product_ids + # no material colors, Nova ifc files often do not have materials at all for p in prodrepr.keys(): - # print("\n") + # print("\n") # print(ifcfile[p]) # IfcProduct # print(ifcfile[p].Representation) # IfcProductDefinitionShape # print(ifcfile[p].Representation.Representations[0]) # IfcShapeRepresentation @@ -300,10 +308,14 @@ def buildRelColors(ifcfile, prodrepr): return colors -def getRelProperties(ifcfile): - """Builds and returns a dictionary of {object:[properties]} from an IFC file""" +# ************************************************************************************************ +# property related methods +def buildRelProperties(ifcfile): + """ + Builds and returns a dictionary of {object:[properties]} from an IFC file + """ - # this method no longer used by this importer module + # this method no longer used by the importer module # but this relation table might be useful anyway for other purposes properties = {} # { objid : { psetid : [propertyid, ... ], ... }, ... } @@ -336,6 +348,37 @@ def getIfcPropertySets(ifcfile, pid): return psets +def getIfcProperties(ifcfile, pid, psets, d): + """builds valid property values for FreeCAD""" + + for pset in psets.keys(): + #print("reading pset: ",pset) + psetname = ifcfile[pset].Name + if six.PY2: + psetname = psetname.encode("utf8") + for prop in psets[pset]: + e = ifcfile[prop] + pname = e.Name + if six.PY2: + pname = pname.encode("utf8") + if e.is_a("IfcPropertySingleValue"): + if e.NominalValue: + ptype = e.NominalValue.is_a() + if ptype in ['IfcLabel','IfcText','IfcIdentifier','IfcDescriptiveMeasure']: + pvalue = e.NominalValue.wrappedValue + if six.PY2: + pvalue = pvalue.encode("utf8") + else: + pvalue = str(e.NominalValue.wrappedValue) + if hasattr(e.NominalValue,'Unit'): + if e.NominalValue.Unit: + pvalue += e.NominalValue.Unit + d[pname+";;"+psetname] = ptype+";;"+pvalue + #print("adding property: ",pname,ptype,pvalue," pset ",psetname) + return d + + +# ************************************************************************************************ def getScaling(ifcfile): """returns a scaling factor from file units to mm""" @@ -541,33 +584,3 @@ def get2DShape(representation,scaling=1000): elif representation.is_a() in ["IfcPolyline","IfcCircle","IfcTrimmedCurve"]: result = getCurveSet(representation) return result - - -def getIfcProperties(ifcfile, pid, psets, d): - """builds valid property values for FreeCAD""" - - for pset in psets.keys(): - #print("reading pset: ",pset) - psetname = ifcfile[pset].Name - if six.PY2: - psetname = psetname.encode("utf8") - for prop in psets[pset]: - e = ifcfile[prop] - pname = e.Name - if six.PY2: - pname = pname.encode("utf8") - if e.is_a("IfcPropertySingleValue"): - if e.NominalValue: - ptype = e.NominalValue.is_a() - if ptype in ['IfcLabel','IfcText','IfcIdentifier','IfcDescriptiveMeasure']: - pvalue = e.NominalValue.wrappedValue - if six.PY2: - pvalue = pvalue.encode("utf8") - else: - pvalue = str(e.NominalValue.wrappedValue) - if hasattr(e.NominalValue,'Unit'): - if e.NominalValue.Unit: - pvalue += e.NominalValue.Unit - d[pname+";;"+psetname] = ptype+";;"+pvalue - #print("adding property: ",pname,ptype,pvalue," pset ",psetname) - return d From 057caca9452773a6b4ecd0d60d2d347bc92a8db8 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Wed, 28 Aug 2019 21:47:51 +0200 Subject: [PATCH 14/23] Arch, import IFC helper, improve color code --- src/Mod/Arch/importIFCHelper.py | 103 ++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/Mod/Arch/importIFCHelper.py b/src/Mod/Arch/importIFCHelper.py index 6a75ae6659..e0c931d715 100644 --- a/src/Mod/Arch/importIFCHelper.py +++ b/src/Mod/Arch/importIFCHelper.py @@ -308,6 +308,109 @@ def buildRelColors(ifcfile, prodrepr): return colors +def buildRelProductColors(ifcfile, prodrepr): + + # gets the colors for the products + colors = {} # { id:(r,g,b) } + + for p in prodrepr.keys(): + + # print(p) + + # representation item, see docu IfcRepresentationItem + # all kind of geometric or topological representation items + # IfcExtrudedAreaSolid, IfcMappedItem, IfcFacetedBrep, IfcBooleanResult, etc + representation_item = ifcfile[p].Representation.Representations[0].Items[0] + # print(representation_item) + + # get the geometric representations which have a presentation style + # all representation items have the inverse attribute StyledByItem for this + # there will be gemetric representations which do not have a presentation style + # the StyledByItem will be empty than + if representation_item.StyledByItem: + + # it has to be a IfcStyledItem, no check needed + styled_item = representation_item.StyledByItem[0] + + # write into colors table if a IfcStyledItem exists for this product + # write None if something goes wrong or if the ifc file has errors and thus no valid color is returned + colors[p] = getColorFromStyledItem(styled_item) + + return colors + + +def buildRelMaterialColors(ifcfile, prodrepr): + # not implemented + pass + + +def getColorFromStyledItem(styled_item): + + # styled_item should be a IfcStyledItem + if not styled_item.is_a("IfcStyledItem"): + print("Not a IfcStyledItem passed.") + return None + + rgb_color = None + + # print(styled_item) + # The IfcStyledItem holds presentation style information for products, + # either explicitly for an IfcGeometricRepresentationItem being part of + # an IfcShapeRepresentation assigned to a product, or by assigning presentation + # information to IfcMaterial being assigned as other representation for a product. + + # In current IFC release (IFC2x3) only one presentation style assignment shall be assigned. + + if len(styled_item.Styles) != 1: + if len(styled_item.Styles) == 0: + pass + # ca 100x in 210_King_Merged.ifc + # empty styles, #4952778=IfcStyledItem(#4952779,(),$) + # this is an error in the ifc file IMHO + # print(ifcfile[p]) + # print(styled_item) + # print(styled_item.Styles) + else: + pass + # never seen an ifc with more than one Styles in IfcStyledItem + else: + # get the IfcPresentationStyleAssignment, there should only be one, see above + assign_style = styled_item.Styles[0] + # print(assign_style) # IfcPresentationStyleAssignment + + # IfcPresentationStyleAssignment can hold various kinde and count of styles + # see IfcPresentationStyleSelect + if assign_style.Styles[0].is_a("IfcSurfaceStyle"): + # Schependomlaan and Nova and others + # print(assign_style.Styles[0].Styles[0]) # IfcSurfaceStyleRendering + rgb_color = assign_style.Styles[0].Styles[0].SurfaceColour # IfcColourRgb + # print(rgb_color) + elif assign_style.Styles[0].is_a("IfcCurveStyle"): + if ( + len(assign_style.Styles) == 2 + and assign_style.Styles[1].is_a("IfcSurfaceStyle") + ): + # Allplan, new IFC export started in 2017 + # print(assign_style.Styles[0].CurveColour) # IfcDraughtingPreDefinedColour + # on index 1 ist das was wir brauchen !!! + rgb_color = assign_style.Styles[1].Styles[0].SurfaceColour + # print(rgb_color) + else: + # 2x Annotations in 210_King_Merged.ifc + # print(ifcfile[p]) + # print(assign_style.Styles[0]) + # print(assign_style.Styles[0].CurveColour) + rgb_color = assign_style.Styles[0].CurveColour + + if rgb_color is not None: + col = rgb_color.Red, rgb_color.Green, rgb_color.Blue + # print(col) + else: + col = None + + return col + + # ************************************************************************************************ # property related methods def buildRelProperties(ifcfile): From 4096c6b8c41c8473f4ef15d973880b6443ad8781 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Wed, 28 Aug 2019 21:47:53 +0200 Subject: [PATCH 15/23] Arch: import IFC, make use of improved color import --- src/Mod/Arch/importIFC.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 23c5f52986..0fbb3b28f4 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -272,7 +272,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): groups = importIFCHelper.buildRelGroups(ifcfile) subtractions = importIFCHelper.buildRelSubtractions(ifcfile) mattable = importIFCHelper.buildRelMattable(ifcfile) - colors = importIFCHelper.buildRelColors(ifcfile, prodrepr) + colors = importIFCHelper.buildRelProductColors(ifcfile, prodrepr) if preferences['DEBUG']: print("done.") # only import a list of IDs and their children, if defined From 04ff03fb586815214fc1585a7ccb9421ea7b7f42 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 28 Aug 2019 16:50:06 -0300 Subject: [PATCH 16/23] Draft/TechDraw: Allow TD Draft views to not override individual colors and line type of rendered objects --- src/Mod/Draft/getSVG.py | 47 ++++++++++++++++---------- src/Mod/TechDraw/App/DrawViewDraft.cpp | 9 +++-- src/Mod/TechDraw/App/DrawViewDraft.h | 1 + 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/Mod/Draft/getSVG.py b/src/Mod/Draft/getSVG.py index 6166d54ad1..9ae8eeb1f5 100644 --- a/src/Mod/Draft/getSVG.py +++ b/src/Mod/Draft/getSVG.py @@ -68,7 +68,7 @@ def getPattern(pat): return '' -def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direction=None,linestyle=None,color=None,linespacing=None,techdraw=False,rotation=0,fillSpaces=False): +def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direction=None,linestyle=None,color=None,linespacing=None,techdraw=False,rotation=0,fillSpaces=False,override=True): '''getSVG(object,[scale], [linewidth],[fontsize],[fillstyle],[direction],[linestyle],[color],[linespacing]): returns a string containing a SVG representation of the given object, with the given linewidth and fontsize (used if the given object contains @@ -77,15 +77,23 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct # if this is a group, gather all the svg views of its children if hasattr(obj,"isDerivedFrom"): - if obj.isDerivedFrom("App::DocumentObjectGroup"): + if obj.isDerivedFrom("App::DocumentObjectGroup") or getType(obj) == "Layer": svg = "" for child in obj.Group: - svg += getSVG(child,scale,linewidth,fontsize,fillstyle,direction,linestyle,color,linespacing,techdraw) + svg += getSVG(child,scale,linewidth,fontsize,fillstyle,direction,linestyle,color,linespacing,techdraw,rotation,fillSpaces,override) return svg pathdata = [] svg = "" linewidth = float(linewidth)/scale + if not override: + if hasattr(obj,"ViewObject"): + if hasattr(obj.ViewObject,"LineWidth"): + if hasattr(obj.ViewObject.LineWidth,"Value"): + lw = obj.ViewObject.LineWidth.Value + else: + lw = obj.ViewObject.LineWidth + linewidth = lw*linewidth fontsize = (float(fontsize)/scale)/2 if linespacing: linespacing = float(linespacing)/scale @@ -102,7 +110,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct elif isinstance(direction,WorkingPlane.plane): plane = direction stroke = "#000000" - if color: + if color and override: if "#" in color: stroke = color else: @@ -111,7 +119,15 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct if hasattr(obj,"ViewObject"): if hasattr(obj.ViewObject,"LineColor"): stroke = getrgb(obj.ViewObject.LineColor) - + elif hasattr(obj.ViewObject,"TextColor"): + stroke = getrgb(obj.ViewObject.TextColor) + lstyle = "none" + if override: + lstyle = getLineStyle(linestyle, scale) + else: + if hasattr(obj,"ViewObject"): + if hasattr(obj.ViewObject,"DrawStyle"): + lstyle = getLineStyle(obj.ViewObject.DrawStyle, scale) def getPath(edges=[],wires=[],pathname=None): import Part,DraftGeomUtils @@ -368,7 +384,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct svg += 'x2="'+ str(shootsize*-1) +'" y2="0" />\n' return svg - def getText(color,fontsize,fontname,angle,base,text,linespacing=0.5,align="center",flip=True): + def getText(tcolor,fontsize,fontname,angle,base,text,linespacing=0.5,align="center",flip=True): if isinstance(angle,FreeCAD.Rotation): if not plane: angle = angle.Angle @@ -390,13 +406,13 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct if techdraw: svg = "" for i in range(len(text)): - t = text[i] + t = text[i].replace("&","&").replace("<","<").replace(">",">") if six.PY2 and not isinstance(t, six.text_type): t = t.decode("utf8") # possible workaround if UTF8 is unsupported # import unicodedata # t = u"".join([c for c in unicodedata.normalize("NFKD",t) if not unicodedata.combining(c)]).encode("utf8") - svg += '\n' else: svg = '",">") except: svg += text[0].decode("utf8") else: @@ -454,7 +470,6 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct fill = "#888888" else: fill = 'url(#'+fillstyle+')' - lstyle = getLineStyle(linestyle, scale) svg += getPath(obj.Edges,pathname="") @@ -552,7 +567,6 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct # drawing arc fill= "none" - lstyle = getLineStyle(linestyle, scale) if obj.ViewObject.DisplayMode == "2D": svg += getPath([prx.circle]) else: @@ -666,7 +680,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct print ("export of axes to SVG is only available in GUI mode") else: vobj = obj.ViewObject - lorig = getLineStyle(linestyle, scale) + lorig = lstyle fill = 'none' rad = vobj.BubbleSize.Value/2 n = 0 @@ -703,10 +717,10 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct svg += '' + obj.ViewObject.Proxy.bubbletexts[n].string.getValues()[0] + '\n' svg += '\n' n += 1 + lstyle = lorig elif getType(obj) == "Pipe": fill = stroke - lstyle = getLineStyle(linestyle, scale) if obj.Base and obj.Diameter: svg += getPath(obj.Base.Shape.Edges) for f in obj.Shape.Faces: @@ -716,7 +730,6 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct elif getType(obj) == "Rebar": fill = "none" - lstyle = getLineStyle(linestyle, scale) if obj.Proxy: if not hasattr(obj.Proxy,"wires"): obj.Proxy.execute(obj) @@ -743,7 +756,6 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct fill_opacity = 1 - (obj.ViewObject.Transparency / 100.0) else: fill = "#888888" - lstyle = getLineStyle(linestyle, scale) svg += getPath(wires=[obj.Proxy.face.OuterWire]) c = getrgb(obj.ViewObject.TextColor) n = obj.ViewObject.FontName @@ -790,7 +802,6 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct fill = "#888888" else: fill = 'none' - lstyle = getLineStyle(linestyle, scale) if len(obj.Shape.Vertexes) > 1: wiredEdges = [] @@ -827,5 +838,5 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct # techdraw expects bottom-to-top coordinates if techdraw: - svg = ''+svg+'' + svg = '\n '+svg+'\n' return svg diff --git a/src/Mod/TechDraw/App/DrawViewDraft.cpp b/src/Mod/TechDraw/App/DrawViewDraft.cpp index bdb58a9381..5bdd98ba2a 100644 --- a/src/Mod/TechDraw/App/DrawViewDraft.cpp +++ b/src/Mod/TechDraw/App/DrawViewDraft.cpp @@ -53,12 +53,13 @@ DrawViewDraft::DrawViewDraft(void) ADD_PROPERTY_TYPE(Source ,(0),group,App::Prop_None,"Draft object for this view"); Source.setScope(App::LinkScope::Global); - ADD_PROPERTY_TYPE(LineWidth,(0.35),group,App::Prop_None,"Line width of this view"); + ADD_PROPERTY_TYPE(LineWidth,(0.35),group,App::Prop_None,"Line width of this view. If Override Style is false, this value multiplies the object line width"); ADD_PROPERTY_TYPE(FontSize,(12.0),group,App::Prop_None,"Text size for this view"); ADD_PROPERTY_TYPE(Direction ,(0,0,1.0),group,App::Prop_None,"Projection direction. The direction you are looking from."); ADD_PROPERTY_TYPE(Color,(0.0f,0.0f,0.0f),group,App::Prop_None,"The default color of text and lines"); ADD_PROPERTY_TYPE(LineStyle,("Solid") ,group,App::Prop_None,"A line style to use for this view. Can be Solid, Dashed, Dashdot, Dot or a SVG pattern like 0.20,0.20"); ADD_PROPERTY_TYPE(LineSpacing,(1.0f),group,App::Prop_None,"The spacing between lines to use for multiline texts"); + ADD_PROPERTY_TYPE(OverrideStyle,(false),group,App::Prop_None,"If True, line color, width and style of this view will override those of rendered objects"); ScaleType.setValue("Custom"); } @@ -76,7 +77,8 @@ short DrawViewDraft::mustExecute() const Direction.isTouched() || Color.isTouched() || LineStyle.isTouched() || - LineSpacing.isTouched(); + LineSpacing.isTouched() || + OverrideStyle.isTouched(); } if ((bool) result) { return result; @@ -113,7 +115,8 @@ App::DocumentObjectExecReturn *DrawViewDraft::execute(void) << ",color=\"" << col.asCSSString() << "\"" << ",linespacing=" << LineSpacing.getValue() // We must set techdraw to "true" becausea couple of things behave differently than in Drawing - << ",techdraw=True"; + << ",techdraw=True" + << ",override=" << (OverrideStyle.getValue() ? "True" : "False"); // this is ok for a starting point, but should eventually make dedicated Draft functions that build the svg for all the special cases // (Arch section, etc) diff --git a/src/Mod/TechDraw/App/DrawViewDraft.h b/src/Mod/TechDraw/App/DrawViewDraft.h index 411c4e0853..fb2967af65 100644 --- a/src/Mod/TechDraw/App/DrawViewDraft.h +++ b/src/Mod/TechDraw/App/DrawViewDraft.h @@ -50,6 +50,7 @@ public: App::PropertyColor Color; App::PropertyString LineStyle; App::PropertyFloat LineSpacing; + App::PropertyBool OverrideStyle; /** @name methods override Feature */ //@{ From efcb26ca6056e04c02eaf96a65f73c845817aa33 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Wed, 28 Aug 2019 22:15:21 +0200 Subject: [PATCH 17/23] FEM: gmsh tools, use double string quotes instead of single --- src/Mod/Fem/femmesh/gmshtools.py | 342 +++++++++++++++---------------- 1 file changed, 171 insertions(+), 171 deletions(-) diff --git a/src/Mod/Fem/femmesh/gmshtools.py b/src/Mod/Fem/femmesh/gmshtools.py index 9e75f8a9b6..96487bf4fc 100644 --- a/src/Mod/Fem/femmesh/gmshtools.py +++ b/src/Mod/Fem/femmesh/gmshtools.py @@ -62,55 +62,55 @@ class GmshTools(): self.geotol = 1e-08 # order - # known_element_orders = ['1st', '2nd'] + # known_element_orders = ["1st", "2nd"] self.order = self.mesh_obj.ElementOrder - if self.order == '1st': - self.order = '1' - elif self.order == '2nd': - self.order = '2' + if self.order == "1st": + self.order = "1" + elif self.order == "2nd": + self.order = "2" else: - print('Error in order') + print("Error in order") # dimension self.dimension = self.mesh_obj.ElementDimension # Algorithm2D algo2D = self.mesh_obj.Algorithm2D - if algo2D == 'Automatic': - self.algorithm2D = '2' - elif algo2D == 'MeshAdapt': - self.algorithm2D = '1' - elif algo2D == 'Delaunay': - self.algorithm2D = '5' - elif algo2D == 'Frontal': - self.algorithm2D = '6' - elif algo2D == 'BAMG': - self.algorithm2D = '7' - elif algo2D == 'DelQuad': - self.algorithm2D = '8' + if algo2D == "Automatic": + self.algorithm2D = "2" + elif algo2D == "MeshAdapt": + self.algorithm2D = "1" + elif algo2D == "Delaunay": + self.algorithm2D = "5" + elif algo2D == "Frontal": + self.algorithm2D = "6" + elif algo2D == "BAMG": + self.algorithm2D = "7" + elif algo2D == "DelQuad": + self.algorithm2D = "8" else: - self.algorithm2D = '2' + self.algorithm2D = "2" # Algorithm3D algo3D = self.mesh_obj.Algorithm3D - if algo3D == 'Automatic': - self.algorithm3D = '1' - elif algo3D == 'Delaunay': - self.algorithm3D = '1' - elif algo3D == 'New Delaunay': - self.algorithm3D = '2' - elif algo3D == 'Frontal': - self.algorithm3D = '4' - elif algo3D == 'Frontal Delaunay': - self.algorithm3D = '5' - elif algo3D == 'Frontal Hex': - self.algorithm3D = '6' - elif algo3D == 'MMG3D': - self.algorithm3D = '7' - elif algo3D == 'R-tree': - self.algorithm3D = '9' + if algo3D == "Automatic": + self.algorithm3D = "1" + elif algo3D == "Delaunay": + self.algorithm3D = "1" + elif algo3D == "New Delaunay": + self.algorithm3D = "2" + elif algo3D == "Frontal": + self.algorithm3D = "4" + elif algo3D == "Frontal Delaunay": + self.algorithm3D = "5" + elif algo3D == "Frontal Hex": + self.algorithm3D = "6" + elif algo3D == "MMG3D": + self.algorithm3D = "7" + elif algo3D == "R-tree": + self.algorithm3D = "9" else: - self.algorithm3D = '1' + self.algorithm3D = "1" # mesh groups if self.mesh_obj.GroupsOfNodes is True: @@ -120,30 +120,30 @@ class GmshTools(): self.group_elements = {} # mesh regions - self.ele_length_map = {} # { 'ElementString' : element length } - self.ele_node_map = {} # { 'ElementString' : [element nodes] } + self.ele_length_map = {} # { "ElementString" : element length } + self.ele_node_map = {} # { "ElementString" : [element nodes] } # mesh boundary layer self.bl_setting_list = [] # list of dict, each item map to MeshBoundaryLayer object self.bl_boundary_list = [] # to remove duplicated boundary edge or faces # other initializations - self.temp_file_geometry = '' - self.temp_file_mesh = '' - self.temp_file_geo = '' - self.mesh_name = '' - self.gmsh_bin = '' + self.temp_file_geometry = "" + self.temp_file_mesh = "" + self.temp_file_geo = "" + self.mesh_name = "" + self.gmsh_bin = "" self.error = False def create_mesh(self): print("\nWe are going to start Gmsh FEM mesh run!") print( - ' Part to mesh: Name --> {}, Label --> {}, ShapeType --> {}' + " Part to mesh: Name --> {}, Label --> {}, ShapeType --> {}" .format(self.part_obj.Name, self.part_obj.Label, self.part_obj.Shape.ShapeType) ) - print(' CharacteristicLengthMax: ' + str(self.clmax)) - print(' CharacteristicLengthMin: ' + str(self.clmin)) - print(' ElementOrder: ' + self.order) + print(" CharacteristicLengthMax: " + str(self.clmax)) + print(" CharacteristicLengthMin: " + str(self.clmin)) + print(" ElementOrder: " + self.order) self.get_dimension() self.get_tmp_file_paths() self.get_gmsh_command() @@ -158,45 +158,45 @@ class GmshTools(): def get_dimension(self): # Dimension - # known_element_dimensions = ['From Shape', '1D', '2D', '3D'] + # known_element_dimensions = ["From Shape", "1D", "2D", "3D"] # if not given, Gmsh uses the highest available. # A use case for not "From Shape" would be a surface (2D) mesh of a solid - if self.dimension == 'From Shape': + if self.dimension == "From Shape": shty = self.part_obj.Shape.ShapeType - if shty == 'Solid' or shty == 'CompSolid': - # print('Found: ' + shty) - self.dimension = '3' - elif shty == 'Face' or shty == 'Shell': - # print('Found: ' + shty) - self.dimension = '2' - elif shty == 'Edge' or shty == 'Wire': - # print('Found: ' + shty) - self.dimension = '1' - elif shty == 'Vertex': - # print('Found: ' + shty) + if shty == "Solid" or shty == "CompSolid": + # print("Found: " + shty) + self.dimension = "3" + elif shty == "Face" or shty == "Shell": + # print("Found: " + shty) + self.dimension = "2" + elif shty == "Edge" or shty == "Wire": + # print("Found: " + shty) + self.dimension = "1" + elif shty == "Vertex": + # print("Found: " + shty) FreeCAD.Console.PrintError("You can not mesh a Vertex.\n") - self.dimension = '0' - elif shty == 'Compound': - # print(' Found a ' + shty) + self.dimension = "0" + elif shty == "Compound": + # print(" Found a " + shty) FreeCAD.Console.PrintLog( " Found a Compound. Since it could contain" "any kind of shape dimension 3 is used.\n" ) - self.dimension = '3' # dimension 3 works for 2D and 1d shapes as well + self.dimension = "3" # dimension 3 works for 2D and 1d shapes as well else: - self.dimension = '0' + self.dimension = "0" FreeCAD.Console.PrintError( - 'Could not retrieve Dimension from shape type. Please choose dimension.' + "Could not retrieve Dimension from shape type. Please choose dimension." ) - elif self.dimension == '3D': - self.dimension = '3' - elif self.dimension == '2D': - self.dimension = '2' - elif self.dimension == '1D': - self.dimension = '1' + elif self.dimension == "3D": + self.dimension = "3" + elif self.dimension == "2D": + self.dimension = "2" + elif self.dimension == "1D": + self.dimension = "1" else: - print('Error in dimension') - print(' ElementDimension: ' + self.dimension) + print("Error in dimension") + print(" ElementDimension: " + self.dimension) def get_tmp_file_paths(self): if system() == "Linux": @@ -207,15 +207,15 @@ class GmshTools(): path_sep = "/" tmpdir = tempfile.gettempdir() # geometry file - self.temp_file_geometry = tmpdir + path_sep + self.part_obj.Name + '_Geometry.brep' - print(' ' + self.temp_file_geometry) + self.temp_file_geometry = tmpdir + path_sep + self.part_obj.Name + "_Geometry.brep" + print(" " + self.temp_file_geometry) # mesh file - self.mesh_name = self.part_obj.Name + '_Mesh_TmpGmsh' - self.temp_file_mesh = tmpdir + path_sep + self.mesh_name + '.unv' - print(' ' + self.temp_file_mesh) + self.mesh_name = self.part_obj.Name + "_Mesh_TmpGmsh" + self.temp_file_mesh = tmpdir + path_sep + self.mesh_name + ".unv" + print(" " + self.temp_file_mesh) # Gmsh input file - self.temp_file_geo = tmpdir + path_sep + 'shape2mesh.geo' - print(' ' + self.temp_file_geo) + self.temp_file_geo = tmpdir + path_sep + "shape2mesh.geo" + print(" " + self.temp_file_geo) def get_gmsh_command(self): gmsh_std_location = FreeCAD.ParamGet( @@ -229,12 +229,12 @@ class GmshTools(): ).SetString("gmshBinaryPath", gmsh_path) self.gmsh_bin = gmsh_path elif system() == "Linux": - p1 = subprocess.Popen(['which', 'gmsh'], stdout=subprocess.PIPE) + p1 = subprocess.Popen(["which", "gmsh"], stdout=subprocess.PIPE) if p1.wait() == 0: output = p1.stdout.read() if sys.version_info.major >= 3: - output = output.decode('utf-8') - gmsh_path = output.split('\n')[0] + output = output.decode("utf-8") + gmsh_path = output.split("\n")[0] elif p1.wait() == 1: error_message = ( "Gmsh binary gmsh not found in standard system binary path. " @@ -263,7 +263,7 @@ class GmshTools(): self.gmsh_bin = FreeCAD.getHomePath() + "bin/gmsh.exe" else: self.gmsh_bin = "gmsh" - print(' ' + self.gmsh_bin) + print(" " + self.gmsh_bin) def get_group_data(self): # TODO: solids, faces, edges and vertexes don't seem to work together in one group, @@ -271,10 +271,10 @@ class GmshTools(): # mesh group objects if not self.mesh_obj.MeshGroupList: - # print(' No mesh group objects.') + # print(" No mesh group objects.") pass else: - print(' Mesh group objects, we need to get the elements.') + print(" Mesh group objects, we need to get the elements.") for mg in self.mesh_obj.MeshGroupList: new_group_elements = meshtools.get_mesh_group_elements(mg, self.part_obj) for ge in new_group_elements: @@ -288,7 +288,7 @@ class GmshTools(): "User parameter:BaseApp/Preferences/Mod/Fem/General" ).GetBool("AnalysisGroupMeshing", False) if self.analysis and analysis_group_meshing: - print(' Group meshing for analysis.') + print(" Group meshing for analysis.") self.group_nodes_export = True new_group_elements = meshtools.get_analysis_group_elements( self.analysis, @@ -300,18 +300,18 @@ class GmshTools(): else: FreeCAD.Console.PrintError(" A group with this name exists already.\n") else: - print(' No Group meshing for analysis.') + print(" No Group meshing for analysis.") if self.group_elements: - print(' {}'.format(self.group_elements)) + print(" {}".format(self.group_elements)) def get_region_data(self): # mesh regions if not self.mesh_obj.MeshRegionList: - # print(' No mesh regions.') + # print(" No mesh regions.") pass else: - print(' Mesh regions, we need to get the elements.') + print(" Mesh regions, we need to get the elements.") # by the use of MeshRegion object and a BooleanSplitCompound # there could be problems with node numbers see # http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467 @@ -324,11 +324,11 @@ class GmshTools(): or part.Proxy.Type == "FeatureSlice" \ or part.Proxy.Type == "FeatureXOR": error_message = ( - ' The mesh to shape is a boolean split tools Compound ' - 'and the mesh has mesh region list. ' - 'Gmsh could return unexpected meshes in such circumstances. ' - 'It is strongly recommended to extract the shape to mesh ' - 'from the Compound and use this one.' + " The mesh to shape is a boolean split tools Compound " + "and the mesh has mesh region list. " + "Gmsh could return unexpected meshes in such circumstances. " + "It is strongly recommended to extract the shape to mesh " + "from the Compound and use this one." ) FreeCAD.Console.PrintError(error_message + "\n") # TODO: no gui popup because FreeCAD will be in a endless output loop @@ -387,14 +387,14 @@ class GmshTools(): ) else: FreeCAD.Console.PrintError( - 'The meshregion: {} is not used to create the mesh ' - 'because the reference list is empty.\n' + "The meshregion: {} is not used to create the mesh " + "because the reference list is empty.\n" .format(mr_obj.Name) ) else: FreeCAD.Console.PrintError( - 'The meshregion: {} is not used to create the ' - 'mesh because the CharacteristicLength is 0.0 mm.\n' + "The meshregion: {} is not used to create the " + "mesh because the CharacteristicLength is 0.0 mm.\n" .format(mr_obj.Name) ) for eleml in self.ele_length_map: @@ -402,8 +402,8 @@ class GmshTools(): ele_shape = meshtools.get_element(self.part_obj, eleml) ele_vertexes = meshtools.get_vertexes_by_element(self.part_obj.Shape, ele_shape) self.ele_node_map[eleml] = ele_vertexes - print(' {}'.format(self.ele_length_map)) - print(' {}'.format(self.ele_node_map)) + print(" {}".format(self.ele_length_map)) + print(" {}".format(self.ele_node_map)) def get_boundary_layer_data(self): # mesh boundary layer @@ -412,11 +412,11 @@ class GmshTools(): # Mesh.CharacteristicLengthMin, must be zero # or a value less than first inflation layer height if not self.mesh_obj.MeshBoundaryLayerList: - # print(' No mesh boundary layer setting document object.') + # print(" No mesh boundary layer setting document object.") pass else: - print(' Mesh boundary layers, we need to get the elements.') - if self.part_obj.Shape.ShapeType == 'Compound': + print(" Mesh boundary layers, we need to get the elements.") + if self.part_obj.Shape.ShapeType == "Compound": # see http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467 and # http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520 err = ( @@ -478,30 +478,30 @@ class GmshTools(): .format(elems, mr_obj.Name) ) setting = {} - setting['hwall_n'] = Units.Quantity(mr_obj.MinimumThickness).Value - setting['ratio'] = mr_obj.GrowthRate - setting['thickness'] = sum([ - setting['hwall_n'] * setting['ratio'] ** i for i in range( + setting["hwall_n"] = Units.Quantity(mr_obj.MinimumThickness).Value + setting["ratio"] = mr_obj.GrowthRate + setting["thickness"] = sum([ + setting["hwall_n"] * setting["ratio"] ** i for i in range( mr_obj.NumberOfLayers ) ]) - # setting['hwall_n'] * 5 # tangential cell dimension - setting['hwall_t'] = setting['thickness'] + # setting["hwall_n"] * 5 # tangential cell dimension + setting["hwall_t"] = setting["thickness"] # hfar: cell dimension outside boundary # should be set later if some character length is set - if self.clmax > setting['thickness'] * 0.8 \ - and self.clmax < setting['thickness'] * 1.6: - setting['hfar'] = self.clmax + if self.clmax > setting["thickness"] * 0.8 \ + and self.clmax < setting["thickness"] * 1.6: + setting["hfar"] = self.clmax else: # set a value for safety, it may works as background mesh cell size - setting['hfar'] = setting['thickness'] + setting["hfar"] = setting["thickness"] # from face name -> face id is done in geo file write up # TODO: fan angle setup is not implemented yet - if self.dimension == '2': - setting['EdgesList'] = belem_list - elif self.dimension == '3': - setting['FacesList'] = belem_list + if self.dimension == "2": + setting["EdgesList"] = belem_list + elif self.dimension == "3": + setting["FacesList"] = belem_list else: FreeCAD.Console.PrintError( "boundary layer is only supported for 2D and 3D mesh" @@ -509,38 +509,38 @@ class GmshTools(): self.bl_setting_list.append(setting) else: FreeCAD.Console.PrintError( - 'The mesh boundary layer: {} is not used to create ' - 'the mesh because the reference list is empty.\n' + "The mesh boundary layer: {} is not used to create " + "the mesh because the reference list is empty.\n" .format(mr_obj.Name) ) else: FreeCAD.Console.PrintError( - 'The mesh boundary layer: {} is not used to create ' - 'the mesh because the min thickness is 0.0 mm.\n' + "The mesh boundary layer: {} is not used to create " + "the mesh because the min thickness is 0.0 mm.\n" .format(mr_obj.Name) ) - print(' {}'.format(self.bl_setting_list)) + print(" {}".format(self.bl_setting_list)) def write_boundary_layer(self, geo): # currently single body is supported if len(self.bl_setting_list): geo.write("// boundary layer setting\n") - print(' Start to write boundary layer setup') + print(" Start to write boundary layer setup") field_number = 1 for item in self.bl_setting_list: prefix = "Field[" + str(field_number) + "]" geo.write(prefix + " = BoundaryLayer;\n") for k in item: v = item[k] - if k in set(['EdgesList', 'FacesList']): + if k in set(["EdgesList", "FacesList"]): # the element name of FreeCAD which starts - # with 1 (example: 'Face1'), same as Gmsh + # with 1 (example: "Face1"), same as Gmsh # el_id = int(el[4:]) # FIXME: strip `face` or `edge` prefix - ele_nodes = (''.join((str(el[4:]) + ', ') for el in v)).rstrip(', ') - line = prefix + '.' + str(k) + ' = {' + ele_nodes + ' };\n' + ele_nodes = ("".join((str(el[4:]) + ", ") for el in v)).rstrip(", ") + line = prefix + "." + str(k) + " = {" + ele_nodes + " };\n" geo.write(line) else: - line = prefix + '.' + str(k) + ' = ' + str(v) + ';\n' + line = prefix + "." + str(k) + " = " + str(v) + ";\n" geo.write(line) print(line) geo.write("BoundaryLayer Field = " + str(field_number) + ";\n") @@ -548,9 +548,9 @@ class GmshTools(): field_number += 1 geo.write("\n") geo.flush() - print(' finished in boundary layer setup') + print(" finished in boundary layer setup") else: - # print(' no boundary layer setup is found for this mesh') + # print(" no boundary layer setup is found for this mesh") geo.write("// no boundary layer settings for this mesh\n") def write_part_file(self): @@ -561,40 +561,40 @@ class GmshTools(): geo.write("// geo file for meshing with Gmsh meshing software created by FreeCAD\n") geo.write("\n") geo.write("// open brep geometry\n") - geo.write('Merge "' + self.temp_file_geometry + '";\n') + geo.write("Merge "" + self.temp_file_geometry + "";\n") geo.write("\n") if self.group_elements: - # print(' We are going to have to find elements to make mesh groups for.') + # print(" We are going to have to find elements to make mesh groups for.") geo.write("// group data\n") # we use the element name of FreeCAD which starts - # with 1 (example: 'Face1'), same as Gmsh + # with 1 (example: "Face1"), same as Gmsh # for unit test we need them to have a fixed order for group in sorted(self.group_elements.keys()): gdata = self.group_elements[group] # print(gdata) # geo.write("// " + group + "\n") - ele_nr = '' - if gdata[0].startswith('Solid'): - physical_type = 'Volume' + ele_nr = "" + if gdata[0].startswith("Solid"): + physical_type = "Volume" for ele in gdata: - ele_nr += (ele.lstrip('Solid') + ', ') - elif gdata[0].startswith('Face'): - physical_type = 'Surface' + ele_nr += (ele.lstrip("Solid") + ", ") + elif gdata[0].startswith("Face"): + physical_type = "Surface" for ele in gdata: - ele_nr += (ele.lstrip('Face') + ', ') - elif gdata[0].startswith('Edge'): - physical_type = 'Line' + ele_nr += (ele.lstrip("Face") + ", ") + elif gdata[0].startswith("Edge"): + physical_type = "Line" for ele in gdata: - ele_nr += (ele.lstrip('Edge') + ', ') - elif gdata[0].startswith('Vertex'): - physical_type = 'Point' + ele_nr += (ele.lstrip("Edge") + ", ") + elif gdata[0].startswith("Vertex"): + physical_type = "Point" for ele in gdata: - ele_nr += (ele.lstrip('Vertex') + ', ') + ele_nr += (ele.lstrip("Vertex") + ", ") if ele_nr: - ele_nr = ele_nr.rstrip(', ') + ele_nr = ele_nr.rstrip(", ") # print(ele_nr) geo.write( - 'Physical ' + physical_type + '("' + group + '") = {' + ele_nr + '};\n' + "Physical " + physical_type + "("" + group + "") = {" + ele_nr + "};\n" ) geo.write("\n") geo.write("// Characteristic Length\n") @@ -604,8 +604,8 @@ class GmshTools(): geo.write("// Characteristic Length according CharacteristicLengthMap\n") for e in self.ele_length_map: ele_nodes = ( - ''.join((str(n + 1) + ', ') for n in self.ele_node_map[e]) - ).rstrip(', ') + "".join((str(n + 1) + ", ") for n in self.ele_node_map[e]) + ).rstrip(", ") geo.write("// " + e + "\n") elestr1 = "{" elestr2 = "}" @@ -633,23 +633,23 @@ class GmshTools(): else: geo.write("Mesh.CharacteristicLengthMin = " + str(self.clmin) + ";\n") geo.write("\n") - if hasattr(self.mesh_obj, 'RecombineAll') and self.mesh_obj.RecombineAll is True: + if hasattr(self.mesh_obj, "RecombineAll") and self.mesh_obj.RecombineAll is True: geo.write("// other mesh options\n") geo.write("Mesh.RecombineAll = 1;\n") geo.write("\n") geo.write("// optimize the mesh\n") # Gmsh tetra optimizer - if hasattr(self.mesh_obj, 'OptimizeStd') and self.mesh_obj.OptimizeStd is True: + if hasattr(self.mesh_obj, "OptimizeStd") and self.mesh_obj.OptimizeStd is True: geo.write("Mesh.Optimize = 1;\n") else: geo.write("Mesh.Optimize = 0;\n") # Netgen optimizer in Gmsh - if hasattr(self.mesh_obj, 'OptimizeNetgen') and self.mesh_obj.OptimizeNetgen is True: + if hasattr(self.mesh_obj, "OptimizeNetgen") and self.mesh_obj.OptimizeNetgen is True: geo.write("Mesh.OptimizeNetgen = 1;\n") else: geo.write("Mesh.OptimizeNetgen = 0;\n") # higher order mesh optimizing - if hasattr(self.mesh_obj, 'HighOrderOptimize') and self.mesh_obj.HighOrderOptimize is True: + if hasattr(self.mesh_obj, "HighOrderOptimize") and self.mesh_obj.HighOrderOptimize is True: geo.write( "Mesh.HighOrderOptimize = 1; // for more HighOrderOptimize " "parameter check http://gmsh.info/doc/texinfo/gmsh.html\n" @@ -673,7 +673,7 @@ class GmshTools(): "5=Delaunay, 6=Frontal, 7=BAMG, 8=DelQuad)\n" ) if len(self.bl_setting_list) and self.dimension == 3: - geo.write("Mesh.Algorithm = " + 'DelQuad' + ";\n") # Frontal/DelQuad are tested + geo.write("Mesh.Algorithm = " + "DelQuad" + ";\n") # Frontal/DelQuad are tested else: geo.write("Mesh.Algorithm = " + self.algorithm2D + ";\n") geo.write( @@ -686,7 +686,7 @@ class GmshTools(): geo.write("// meshing\n") # remove duplicate vertices # see https://forum.freecadweb.org/viewtopic.php?f=18&t=21571&start=20#p179443 - if hasattr(self.mesh_obj, 'CoherenceMesh') and self.mesh_obj.CoherenceMesh is True: + if hasattr(self.mesh_obj, "CoherenceMesh") and self.mesh_obj.CoherenceMesh is True: geo.write( "Geometry.Tolerance = {}; // set geometrical " "tolerance (also used for merging nodes)\n" @@ -727,7 +727,7 @@ class GmshTools(): geo.close() def run_gmsh_with_geo(self): - comandlist = [self.gmsh_bin, '-', self.temp_file_geo] + comandlist = [self.gmsh_bin, "-", self.temp_file_geo] # print(comandlist) try: p = subprocess.Popen( @@ -738,14 +738,14 @@ class GmshTools(): ) output, error = p.communicate() if sys.version_info.major >= 3: - # output = output.decode('utf-8') - error = error.decode('utf-8') + # output = output.decode("utf-8") + error = error.decode("utf-8") # stdout is still cut at some point # but the warnings are in stderr and thus printed :-) # print(output) # print(error) except: - error = 'Error executing: {}\n'.format(" ".join(comandlist)) + error = "Error executing: {}\n".format(" ".join(comandlist)) FreeCAD.Console.PrintError(error) self.error = True return error @@ -754,25 +754,25 @@ class GmshTools(): if not self.error: fem_mesh = Fem.read(self.temp_file_mesh) self.mesh_obj.FemMesh = fem_mesh - FreeCAD.Console.PrintMessage(' The Part should have a pretty new FEM mesh!\n') + FreeCAD.Console.PrintMessage(" The Part should have a pretty new FEM mesh!\n") else: - FreeCAD.Console.PrintError('No mesh was created.\n') + FreeCAD.Console.PrintError("No mesh was created.\n") del self.temp_file_geometry del self.temp_file_mesh ## @} -''' +""" # simple example how to use the class GmshTools import Part, ObjectsFem doc = App.ActiveDocument -box_obj = doc.addObject('Part::Box', 'Box') +box_obj = doc.addObject("Part::Box", "Box") doc.recompute() -femmesh_obj = ObjectsFem.makeMeshGmsh(doc, box_obj.Name + '_Mesh') +femmesh_obj = ObjectsFem.makeMeshGmsh(doc, box_obj.Name + "_Mesh") femmesh_obj.Part = box_obj doc.recompute() box_obj.ViewObject.Visibility = False @@ -783,9 +783,9 @@ error = gmsh_mesh.create_mesh() print(error) doc.recompute() -''' +""" -''' +""" TODO class GmshTools should be splittet in two classes one class should only collect the mesh parameter from mesh object and his childs @@ -794,4 +794,4 @@ writes the input file runs gmsh reads back the unv and returns a FemMesh gmsh binary will be collected in the second class with this we could mesh without document objects create a shape and run meshinging class, get the FemMesh :-) -''' +""" From 24caf8dab184d7acadbe1cbb5aafde109581013d Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 28 Aug 2019 20:09:25 -0300 Subject: [PATCH 18/23] Draft: Fixed text color and faces with holes in SVG rendering --- src/Mod/Draft/DraftGeomUtils.py | 37 ++++++++++++++++++++------------- src/Mod/Draft/getSVG.py | 18 ++++++++++++---- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index 45dd4942bc..ac54097671 100644 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -872,21 +872,28 @@ def sortEdgesOld(lEdges, aVertex=None): return [] -def invert(edge): - '''invert(edge): returns an inverted copy of this edge''' - if len(edge.Vertexes) == 1: - return edge - if geomType(edge) == "Line": - return Part.LineSegment(edge.Vertexes[-1].Point,edge.Vertexes[0].Point).toShape() - elif geomType(edge) == "Circle": - mp = findMidpoint(edge) - return Part.Arc(edge.Vertexes[-1].Point,mp,edge.Vertexes[0].Point).toShape() - elif geomType(edge) in ["BSplineCurve","BezierCurve"]: - if isLine(edge.Curve): - return Part.LineSegment(edge.Vertexes[-1].Point,edge.Vertexes[0].Point).toShape() - print("DraftGeomUtils.invert: unable to invert ",edge.Curve) - return edge - +def invert(shape): + '''invert(edge): returns an inverted copy of this edge or wire''' + if shape.ShapeType == "Wire": + edges = [invert(edge) for edge in shape.OrderedEdges] + edges.reverse() + return Part.Wire(edges) + elif shape.ShapeType == "Edge": + if len(shape.Vertexes) == 1: + return shape + if geomType(shape) == "Line": + return Part.LineSegment(shape.Vertexes[-1].Point,shape.Vertexes[0].Point).toShape() + elif geomType(shape) == "Circle": + mp = findMidpoint(shape) + return Part.Arc(shape.Vertexes[-1].Point,mp,shape.Vertexes[0].Point).toShape() + elif geomType(shape) in ["BSplineCurve","BezierCurve"]: + if isLine(shape.Curve): + return Part.LineSegment(shape.Vertexes[-1].Point,shape.Vertexes[0].Point).toShape() + print("DraftGeomUtils.invert: unable to invert",shape.Curve) + return shape + else: + print("DraftGeomUtils.invert: unable to handle",shape.ShapeType) + return shape def flattenWire(wire): '''flattenWire(wire): forces a wire to get completely flat diff --git a/src/Mod/Draft/getSVG.py b/src/Mod/Draft/getSVG.py index 9ae8eeb1f5..97a4fa2049 100644 --- a/src/Mod/Draft/getSVG.py +++ b/src/Mod/Draft/getSVG.py @@ -1,7 +1,6 @@ import six import FreeCAD, math, os, DraftVecUtils, WorkingPlane -import Part, DraftGeomUtils from FreeCAD import Vector from Draft import getType, getrgb, svgpatterns, gui @@ -75,6 +74,8 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct any text). You can also supply an arbitrary projection vector. the scale parameter allows to scale linewidths down, so they are resolution-independant.''' + import Part, DraftGeomUtils + # if this is a group, gather all the svg views of its children if hasattr(obj,"isDerivedFrom"): if obj.isDerivedFrom("App::DocumentObjectGroup") or getType(obj) == "Layer": @@ -130,7 +131,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct lstyle = getLineStyle(obj.ViewObject.DrawStyle, scale) def getPath(edges=[],wires=[],pathname=None): - import Part,DraftGeomUtils + svg = "\n' else: - svg = ' Date: Wed, 28 Aug 2019 21:21:05 -0300 Subject: [PATCH 19/23] Draft: further fixes to svg generation code --- src/Mod/Draft/getSVG.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Mod/Draft/getSVG.py b/src/Mod/Draft/getSVG.py index 97a4fa2049..faea430ec7 100644 --- a/src/Mod/Draft/getSVG.py +++ b/src/Mod/Draft/getSVG.py @@ -451,7 +451,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct try: svg += text[0].replace("&","&").replace("<","<").replace(">",">") except: - svg += text[0].decode("utf8") + svg += text[0].decode("utf8").replace("&","&").replace("<","<").replace(">",">") else: for i in range(len(text)): if i == 0: @@ -459,9 +459,9 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct else: svg += '' try: - svg += text[i] + svg += text[i].replace("&","&").replace("<","<").replace(">",">") except: - svg += text[i].decode("utf8") + svg += text[i].decode("utf8").replace("&","&").replace("<","<").replace(">",">") svg += '\n' svg += '\n' return svg From 5d2713e43fa2e5a65514ba5a506cf272e57c5dad Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 28 Aug 2019 22:48:57 -0300 Subject: [PATCH 20/23] Draft: Export DXF objects with BYLAYER color if applicable --- src/Mod/Draft/importDXF.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index 1f87c136c6..d55ff2f149 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -271,6 +271,13 @@ def getACI(ob,text=False): if not gui: return 0 else: + # detect if we need to set "BYLAYER" + for parent in ob.InList: + if Draft.getType(parent) == "Layer": + if ob in parent.Group: + if hasattr(parent,"ViewObject") and hasattr(parent.ViewObject,"OverrideChildren"): + if parent.ViewObject.OverrideChildren: + return 256 # BYLAYER if text: col=ob.ViewObject.TextColor else: From 0eef759864a990762c12444040383ec22d257d87 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Thu, 29 Aug 2019 07:37:07 +0200 Subject: [PATCH 21/23] Arch: import IFC and helper, code formating, E261 at least two spaces before inline comment --- src/Mod/Arch/importIFC.py | 52 ++++++++++++++++----------------- src/Mod/Arch/importIFCHelper.py | 22 +++++++------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 0fbb3b28f4..29b847e22b 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -45,11 +45,11 @@ import importIFCHelper # # This module provides tools to import IFC files. -DEBUG = False # Set to True to see debug messages. Otherwise, totally silent -ZOOMOUT = True # Set to False to not zoom extents after import +DEBUG = False # Set to True to see debug messages. Otherwise, totally silent +ZOOMOUT = True # Set to False to not zoom extents after import if open.__module__ in ['__builtin__','io']: - pyopen = open # because we'll redefine open below + pyopen = open # because we'll redefine open below # ************************************************************************************************ @@ -258,12 +258,12 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): materials = ifcfile.by_type("IfcMaterial") products, annotations = importIFCHelper.buildRelProductsAnnotations(ifcfile, preferences['ROOT_ELEMENT']) # empty relation tables - objects = {} # { id:object, ... } - shapes = {} # { id:shaoe } only used for merge mode - structshapes = {} # { id:shaoe } only used for merge mode - sharedobjects = {} # { representationmapid:object } - parametrics = [] # a list of imported objects whose parametric relationships need processing after all objects have been created - profiles = {} # to store reused extrusion profiles {ifcid:fcobj,...} + objects = {} # { id:object, ... } + shapes = {} # { id:shaoe } only used for merge mode + structshapes = {} # { id:shaoe } only used for merge mode + sharedobjects = {} # { representationmapid:object } + parametrics = [] # a list of imported objects whose parametric relationships need processing after all objects have been created + profiles = {} # to store reused extrusion profiles {ifcid:fcobj,...} # filled relation tables # TODO for the following tables might be better use inverse attributes, done for properties # see https://forum.freecadweb.org/viewtopic.php?f=39&t=37892 @@ -356,10 +356,10 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): if preferences['MERGE_MODE_STRUCT'] == 3 and not archobj: if preferences['DEBUG']: print(" skipped.") continue - if pid in skip: # user given id skip list + if pid in skip: # user given id skip list if preferences['DEBUG']: print(" skipped.") continue - if ptype in preferences['SKIP']: # preferences-set type skip list + if ptype in preferences['SKIP']: # preferences-set type skip list if preferences['DEBUG']: print(" skipped.") continue @@ -380,7 +380,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): clone = sharedobjects[originalid] else: sharedobjects[originalid] = None - store = originalid # flag this object to be stored later + store = originalid # flag this object to be stored later # set additional setting for structural entities if hasattr(settings,"INCLUDE_CURVES"): @@ -392,7 +392,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): cr = ifcopenshell.geom.create_shape(settings,product) brep = cr.geometry.brep_data except: - pass # IfcOpenShell will yield an error if a given product has no shape, but we don't care, we're brave enough + pass # IfcOpenShell will yield an error if a given product has no shape, but we don't care, we're brave enough # from now on we have a brep string if brep: @@ -401,7 +401,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): # create a Part shape shape = Part.Shape() shape.importBrepFromString(brep,False) - shape.scale(1000.0) # IfcOpenShell always outputs in meters, we convert to mm, the freecad internal unit + shape.scale(1000.0) # IfcOpenShell always outputs in meters, we convert to mm, the freecad internal unit if shape.isNull(): if preferences['DEBUG']: print("null shape ",end="") @@ -428,7 +428,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): # we are not using Arch objects # additional tweaks to set when not using Arch objects - if ptype == "IfcSpace": # do not add spaces to compounds + if ptype == "IfcSpace": # do not add spaces to compounds if preferences['DEBUG']: print("skipping space ",pid,end="") elif structobj: structshapes[pid] = shape @@ -451,7 +451,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): sortmethod = "z" else: sortmethod = "area" - ex = Arch.getExtrusionData(shape,sortmethod) # is this an extrusion? + ex = Arch.getExtrusionData(shape,sortmethod) # is this an extrusion? if ex: # check for extrusion profile @@ -756,7 +756,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): for p in psets[c]: l = ifcfile[p] if l.is_a("IfcPropertySingleValue"): - a[l.Name.encode("utf8")] = str(l.NominalValue) # no py3 support here + a[l.Name.encode("utf8")] = str(l.NominalValue) # no py3 support here obj.IfcData = a # color @@ -818,7 +818,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): if preferences['DEBUG']: print("Joining Structural shapes...",end="") - for host,children in groups.items(): # Structural + for host,children in groups.items(): # Structural if ifcfile[host].is_a("IfcStructuralAnalysisModel"): compound = [] for c in children: @@ -831,7 +831,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): obj = FreeCAD.ActiveDocument.addObject("Part::Feature",name) obj.Label = name obj.Shape = Part.makeCompound(compound) - if structshapes: # remaining Structural shapes + if structshapes: # remaining Structural shapes obj = FreeCAD.ActiveDocument.addObject("Part::Feature","UnclaimedStruct") obj.Shape = Part.makeCompound(structshapes.values()) @@ -902,7 +902,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): if preferences['DEBUG']: print("Joining Arch shapes...",end="") - for host,children in additions.items(): # Arch + for host,children in additions.items(): # Arch if ifcfile[host].is_a("IfcBuildingStorey"): compound = [] for c in children: @@ -920,7 +920,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): obj = FreeCAD.ActiveDocument.addObject("Part::Feature",name) obj.Label = name obj.Shape = Part.makeCompound(compound) - if shapes: # remaining Arch shapes + if shapes: # remaining Arch shapes obj = FreeCAD.ActiveDocument.addObject("Part::Feature","UnclaimedArch") obj.Shape = Part.makeCompound(shapes.values()) @@ -951,7 +951,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): cobs = [] for child in children: if child in objects.keys() \ - and child not in swallowed: # don't add objects already in groups + and child not in swallowed: # don't add objects already in groups cobs.append(objects[child]) if not cobs: continue @@ -995,9 +995,9 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): if preferences['DEBUG']: print(count,"/",len(annotations),"object #"+str(aid),":",annotation.is_a(),end="") if aid in skip: - continue # user given id skip list + continue # user given id skip list if annotation.is_a() in preferences['SKIP']: - continue # preferences-set type skip list + continue # preferences-set type skip list if annotation.is_a("IfcGrid"): axes = [] uvwaxes = () @@ -1010,7 +1010,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): for axis in uvwaxes: if axis.AxisCurve: sh = importIFCHelper.get2DShape(axis.AxisCurve,ifcscale) - if sh and (len(sh[0].Vertexes) == 2): # currently only straight axes are supported + if sh and (len(sh[0].Vertexes) == 2): # currently only straight axes are supported sh = sh[0] l = sh.Length pl = FreeCAD.Placement() @@ -1055,7 +1055,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): anno = FreeCAD.ActiveDocument.addObject("Part::Feature",name) anno.Shape = sh p = importIFCHelper.getPlacement(annotation.ObjectPlacement,ifcscale) - if p: # and annotation.is_a("IfcAnnotation"): + if p: # and annotation.is_a("IfcAnnotation"): anno.Placement = p else: if preferences['DEBUG']: print(" no shape") diff --git a/src/Mod/Arch/importIFCHelper.py b/src/Mod/Arch/importIFCHelper.py index e0c931d715..0c2598c50b 100644 --- a/src/Mod/Arch/importIFCHelper.py +++ b/src/Mod/Arch/importIFCHelper.py @@ -166,7 +166,7 @@ def buildRelProductsAnnotations(ifcfile, root_element): def buildRelProductRepresentation(ifcfile): """build the product/representations relation table""" - prodrepr = {} # product/representations table + prodrepr = {} # product/representations table for p in ifcfile.by_type("IfcProduct"): if hasattr(p,"Representation"): @@ -188,7 +188,7 @@ def buildRelProductRepresentation(ifcfile): def buildRelAdditions(ifcfile): """build the additions relation table""" - additions = {} # { host:[child,...], ... } + additions = {} # { host:[child,...], ... } for r in ifcfile.by_type("IfcRelContainedInSpatialStructure"): additions.setdefault(r.RelatingStructure.id(),[]).extend([e.id() for e in r.RelatedElements]) @@ -201,7 +201,7 @@ def buildRelAdditions(ifcfile): def buildRelGroups(ifcfile): """build the groups relation table""" - groups = {} # { host:[child,...], ... } # used in structural IFC + groups = {} # { host:[child,...], ... } # used in structural IFC for r in ifcfile.by_type("IfcRelAssignsToGroup"): groups.setdefault(r.RelatingGroup.id(),[]).extend([e.id() for e in r.RelatedObjects]) @@ -212,7 +212,7 @@ def buildRelGroups(ifcfile): def buildRelSubtractions(ifcfile): """build the subtractions relation table""" - subtractions = [] # [ [opening,host], ... ] + subtractions = [] # [ [opening,host], ... ] for r in ifcfile.by_type("IfcRelVoidsElement"): subtractions.append([r.RelatedOpeningElement.id(), r.RelatingBuildingElement.id()]) @@ -223,7 +223,7 @@ def buildRelSubtractions(ifcfile): def buildRelMattable(ifcfile): """build the mattable relation table""" - mattable = {} # { objid:matid } + mattable = {} # { objid:matid } for r in ifcfile.by_type("IfcRelAssociatesMaterial"): for o in r.RelatedObjects: @@ -249,7 +249,7 @@ def buildRelColors(ifcfile, prodrepr): """build the colors relation table and""" # returns all IfcStyledItem colors, material and product colors - colors = {} # { id:(r,g,b) } + colors = {} # { id:(r,g,b) } style_material_id = {} # { style_entity_id: material_id) } # get style_color_rgb table @@ -311,7 +311,7 @@ def buildRelColors(ifcfile, prodrepr): def buildRelProductColors(ifcfile, prodrepr): # gets the colors for the products - colors = {} # { id:(r,g,b) } + colors = {} # { id:(r,g,b) } for p in prodrepr.keys(): @@ -421,7 +421,7 @@ def buildRelProperties(ifcfile): # this method no longer used by the importer module # but this relation table might be useful anyway for other purposes - properties = {} # { objid : { psetid : [propertyid, ... ], ... }, ... } + properties = {} # { objid : { psetid : [propertyid, ... ], ... }, ... } for r in ifcfile.by_type("IfcRelDefinesByProperties"): for obj in r.RelatedObjects: if not obj.id() in properties: @@ -548,8 +548,8 @@ def getPlacement(entity,scaling=1000): if loc: pl.move(loc) elif entity.is_a("IfcLocalPlacement"): - pl = getPlacement(entity.PlacementRelTo,1) # original placement - relpl = getPlacement(entity.RelativePlacement,1) # relative transf + pl = getPlacement(entity.PlacementRelTo,1) # original placement + relpl = getPlacement(entity.RelativePlacement,1) # relative transf if pl and relpl: pl = pl.multiply(relpl) elif relpl: @@ -683,7 +683,7 @@ def get2DShape(representation,scaling=1000): result = preresult elif item.is_a("IfcTextLiteral"): t = Draft.makeText([item.Literal],point=getPlacement(item.Placement,scaling).Base) - return t # dirty hack... Object creation should not be done here + return t # dirty hack... Object creation should not be done here elif representation.is_a() in ["IfcPolyline","IfcCircle","IfcTrimmedCurve"]: result = getCurveSet(representation) return result From e84b5d662cdde470079f2421f7f8c497bf84e19e Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Thu, 29 Aug 2019 07:39:55 +0200 Subject: [PATCH 22/23] Arch: import IFC and helper, code formating, E261 at least two spaces before inline comment --- src/Mod/Arch/importIFC.py | 16 ++++++++-------- src/Mod/Arch/importIFCHelper.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 29b847e22b..923db85afb 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -232,10 +232,10 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): # IfcOpenShell multiplies the precision value of the file by 100 # So we raise the precision by 100 too to compensate... - #ctxs = ifcfile.by_type("IfcGeometricRepresentationContext") - #for ctx in ctxs: - # if not ctx.is_a("IfcGeometricRepresentationSubContext"): - # ctx.Precision = ctx.Precision/100 + # ctxs = ifcfile.by_type("IfcGeometricRepresentationContext") + # for ctx in ctxs: + # if not ctx.is_a("IfcGeometricRepresentationSubContext"): + # ctx.Precision = ctx.Precision/100 # set default ifcopenshell options to work in brep mode from ifcopenshell import geom @@ -623,7 +623,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): for attribute in ArchIFCSchema.IfcProducts[product.is_a()]["attributes"]: if attribute["name"] == "Name": continue - #print("attribute:",attribute["name"]) + # print("attribute:",attribute["name"]) if hasattr(product, attribute["name"]) and getattr(product, attribute["name"]) and hasattr(obj,attribute["name"]): #print("Setting attribute",attribute["name"],"to",getattr(product, attribute["name"])) setattr(obj, attribute["name"], getattr(product, attribute["name"])) @@ -726,7 +726,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): if preferences['DEBUG']: print("property NominalValue",l.NominalValue.is_a(),type(l.NominalValue.is_a())) print("property NominalValue.wrappedValue",l.NominalValue.wrappedValue,type(l.NominalValue.wrappedValue)) - #print("l.NominalValue.Unit",l.NominalValue.Unit,type(l.NominalValue.Unit)) + # print("l.NominalValue.Unit",l.NominalValue.Unit,type(l.NominalValue.Unit)) ifc_spreadsheet.set(str('C'+str(n)), l.NominalValue.is_a()) if l.NominalValue.is_a() in ['IfcLabel','IfcText','IfcIdentifier','IfcDescriptiveMeasure']: if six.PY2: @@ -1075,8 +1075,8 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): # Materials if preferences['DEBUG'] and materials: print("Creating materials...",end="") - #print("mattable:",mattable) - #print("materials:",materials) + # print("mattable:",mattable) + # print("materials:",materials) fcmats = {} for material in materials: # get and set material name diff --git a/src/Mod/Arch/importIFCHelper.py b/src/Mod/Arch/importIFCHelper.py index 0c2598c50b..e647166905 100644 --- a/src/Mod/Arch/importIFCHelper.py +++ b/src/Mod/Arch/importIFCHelper.py @@ -579,8 +579,8 @@ def getVector(entity,scaling=1000): v = FreeCAD.Vector(tuple(entity.Coordinates)) else: v = FreeCAD.Vector(tuple(entity.Coordinates+[0])) - #if v: - # v.multiply(scaling) + # if v: + # v.multiply(scaling) return v From 929450521a67c45290aa2d0fbee5e0ab5894677c Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Thu, 29 Aug 2019 07:42:56 +0200 Subject: [PATCH 23/23] Arch: import IFC and helper, code formating, E265 block comment should start with '# ' --- src/Mod/Arch/importIFC.py | 4 ++-- src/Mod/Arch/importIFCHelper.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 923db85afb..c416a5c648 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -625,7 +625,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): continue # print("attribute:",attribute["name"]) if hasattr(product, attribute["name"]) and getattr(product, attribute["name"]) and hasattr(obj,attribute["name"]): - #print("Setting attribute",attribute["name"],"to",getattr(product, attribute["name"])) + # print("Setting attribute",attribute["name"],"to",getattr(product, attribute["name"])) setattr(obj, attribute["name"], getattr(product, attribute["name"])) # TODO: ArchIFCSchema.IfcProducts uses the IFC version from the FreeCAD prefs. # This might not coincide with the file being opened, hence some attributes are not properly read. @@ -762,7 +762,7 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None): # color if FreeCAD.GuiUp and (pid in colors) and hasattr(obj.ViewObject,"ShapeColor"): - #if preferences['DEBUG']: print(" setting color: ",int(colors[pid][0]*255),"/",int(colors[pid][1]*255),"/",int(colors[pid][2]*255)) + # if preferences['DEBUG']: print(" setting color: ",int(colors[pid][0]*255),"/",int(colors[pid][1]*255),"/",int(colors[pid][2]*255)) obj.ViewObject.ShapeColor = colors[pid] # if preferences['DEBUG'] is on, recompute after each shape diff --git a/src/Mod/Arch/importIFCHelper.py b/src/Mod/Arch/importIFCHelper.py index e647166905..d29dec1f16 100644 --- a/src/Mod/Arch/importIFCHelper.py +++ b/src/Mod/Arch/importIFCHelper.py @@ -455,7 +455,7 @@ def getIfcProperties(ifcfile, pid, psets, d): """builds valid property values for FreeCAD""" for pset in psets.keys(): - #print("reading pset: ",pset) + # print("reading pset: ",pset) psetname = ifcfile[pset].Name if six.PY2: psetname = psetname.encode("utf8") @@ -477,7 +477,7 @@ def getIfcProperties(ifcfile, pid, psets, d): if e.NominalValue.Unit: pvalue += e.NominalValue.Unit d[pname+";;"+psetname] = ptype+";;"+pvalue - #print("adding property: ",pname,ptype,pvalue," pset ",psetname) + # print("adding property: ",pname,ptype,pvalue," pset ",psetname) return d @@ -677,7 +677,7 @@ def get2DShape(representation,scaling=1000): if rot.Angle: pla.Rotation = rot for r in preresult: - #r.Placement = pla + # r.Placement = pla result.append(r) else: result = preresult