diff --git a/src/Mod/Import/App/AppImportPy.cpp b/src/Mod/Import/App/AppImportPy.cpp index dfb6234e5ab8..45d6e1c04181 100644 --- a/src/Mod/Import/App/AppImportPy.cpp +++ b/src/Mod/Import/App/AppImportPy.cpp @@ -56,8 +56,7 @@ #include #include -#include "ImportOCAF.h" -#include "ExportOCAF.h" +#include "ImportOCAF2.h" //#include "ImportOCAFAssembly.h" #include #include @@ -76,22 +75,38 @@ #include "ImpExpDxf.h" +class ImportOCAFExt : public Import::ImportOCAF2 +{ +public: + ImportOCAFExt(Handle(TDocStd_Document) h, App::Document* d, const std::string& name) + : ImportOCAF2(h, d, name) + { + } + + std::map > partColors; + +private: + virtual void applyFaceColors(Part::Feature* part, const std::vector& colors) override { + partColors[part] = colors; + } +}; + namespace Import { class Module : public Py::ExtensionModule { public: Module() : Py::ExtensionModule("Import") { - add_varargs_method("open",&Module::importer, + add_keyword_method("open",&Module::importer, "open(string) -- Open the file and create a new document." ); - add_varargs_method("insert",&Module::importer, + add_keyword_method("insert",&Module::importer, "insert(string,string) -- Insert the file into the given document." ); // add_varargs_method("openAssembly",&Module::importAssembly, // "openAssembly(string) -- Open the assembly file and create a new document." // ); - add_varargs_method("export",&Module::exporter, + add_keyword_method("export",&Module::exporter, "export(list,string) -- Export a list of objects into a single file." ); add_varargs_method("readDXF",&Module::readDXF, @@ -109,11 +124,17 @@ class Module : public Py::ExtensionModule virtual ~Module() {} private: - Py::Object importer(const Py::Tuple& args) + Py::Object importer(const Py::Tuple& args, const Py::Dict &kwds) { char* Name; char* DocName=0; - if (!PyArg_ParseTuple(args.ptr(), "et|s","utf-8",&Name,&DocName)) + PyObject *importHidden = Py_None; + PyObject *merge = Py_None; + PyObject *useLinkGroup = Py_None; + int mode = -1; + static char* kwd_list[] = {"name", "docName","importHidden","merge","useLinkGroup","mode",0}; + if(!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "et|sOOOi", + kwd_list,"utf-8",&Name,&DocName,&importHidden,&merge,&useLinkGroup,&mode)) throw Py::Exception(); std::string Utf8Name = std::string(Name); @@ -135,6 +156,7 @@ class Module : public Py::ExtensionModule Handle(XCAFApp_Application) hApp = XCAFApp_Application::GetApplication(); Handle(TDocStd_Document) hDoc; hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc); + ImportOCAFExt ocaf(hDoc, pcDoc, file.fileNamePure()); if (file.hasExtension("stp") || file.hasExtension("step")) { try { @@ -201,19 +223,25 @@ class Module : public Py::ExtensionModule } #if 1 - Import::ImportOCAFCmd ocaf(hDoc, pcDoc, file.fileNamePure()); + if(merge!=Py_None) + ocaf.setMerge(PyObject_IsTrue(merge)); + if(importHidden!=Py_None) + ocaf.setImportHiddenObject(PyObject_IsTrue(importHidden)); + if(useLinkGroup!=Py_None) + ocaf.setUseLinkGroup(PyObject_IsTrue(useLinkGroup)); + if(mode>=0) + ocaf.setMode(mode); ocaf.loadShapes(); #else Import::ImportXCAF xcaf(hDoc, pcDoc, file.fileNamePure()); xcaf.loadShapes(); -#endif pcDoc->recompute(); +#endif hApp->Close(hDoc); - std::map > colorMap = ocaf.getPartColorsMap(); - if (!colorMap.empty()) { + if (!ocaf.partColors.size()) { Py::List list; - for (auto it : colorMap) { + for (auto &it : ocaf.partColors) { Py::Tuple tuple(2); tuple.setItem(0, Py::asObject(it.first->getPyObject())); @@ -236,11 +264,16 @@ class Module : public Py::ExtensionModule return Py::None(); } - Py::Object exporter(const Py::Tuple& args) + Py::Object exporter(const Py::Tuple& args, const Py::Dict &kwds) { PyObject* object; char* Name; - if (!PyArg_ParseTuple(args.ptr(), "Oet",&object,"utf-8",&Name)) + PyObject *exportHidden = Py_None; + PyObject *legacy = Py_None; + PyObject *keepPlacement = Py_None; + static char* kwd_list[] = {"obj", "name", "exportHidden", "legacy", "keepPlacement",0}; + if(!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "Oet|OOO", + kwd_list,&object,"utf-8",&Name,&exportHidden,&legacy,&keepPlacement)) throw Py::Exception(); std::string Utf8Name = std::string(Name); @@ -253,71 +286,46 @@ class Module : public Py::ExtensionModule Handle(TDocStd_Document) hDoc; hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc); - //bool keepExplicitPlacement = list.size() > 1; - bool keepExplicitPlacement = Standard_True; - Import::ExportOCAFCmd ocaf(hDoc, keepExplicitPlacement); - - std::map > partColors; - std::vector partObjects; - + std::vector objs; for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { PyObject* item = (*it).ptr(); - if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) { - App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); - if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* part = static_cast(obj); - partObjects.push_back(part); - } - else { - Base::Console().Message("'%s' is not a shape, export will be ignored.\n", obj->Label.getValue()); - } - } - else if (PyTuple_Check(item) && PyTuple_Size(item) == 2) { - Py::Tuple tuple(*it); - Py::Object item0 = tuple.getItem(0); - Py::Object item1 = tuple.getItem(1); - if (PyObject_TypeCheck(item0.ptr(), &(App::DocumentObjectPy::Type))) { - App::DocumentObject* obj = static_cast(item0.ptr())->getDocumentObjectPtr(); - if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* part = static_cast(obj); - App::PropertyColorList colors; - colors.setPyObject(item1.ptr()); - - partObjects.push_back(part); - partColors[part] = colors.getValues(); - } - else { - Base::Console().Message("'%s' is not a shape, export will be ignored.\n", obj->Label.getValue()); - } - } - } - } - - ocaf.setPartColorsMap(partColors); - - // That stuff is exporting a list of selected objects into FreeCAD Tree - std::vector hierarchical_label; - std::vector hierarchical_loc; - std::vector hierarchical_part; - - for (auto it : partObjects) { - ocaf.exportObject(it, hierarchical_label, hierarchical_loc, hierarchical_part); - } - - // Free Shapes must have absolute placement and not explicit - std::vector FreeLabels; - std::vector part_id; - ocaf.getFreeLabels(hierarchical_label, FreeLabels, part_id); - // Got issue with the colors as they are coming from the View Provider they can't be determined into - // the App Code. - std::vector< std::vector > Colors; - ocaf.getPartColors(hierarchical_part, FreeLabels, part_id, Colors); - ocaf.reallocateFreeShape(hierarchical_part, FreeLabels, part_id, Colors); - + if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) + objs.push_back(static_cast(item)->getDocumentObjectPtr()); + } + + if(legacy == Py_None) { + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Import"); + legacy = hGrp->GetBool("ExportLegacy",false)?Py_True:Py_False; + } + + Import::ExportOCAF2 ocaf(hDoc); + if(!PyObject_IsTrue(legacy) || !ocaf.canFallback(objs)) { + if(exportHidden!=Py_None) + ocaf.setExportHiddenObject(PyObject_IsTrue(exportHidden)); + if(keepPlacement!=Py_None) + ocaf.setKeepPlacement(PyObject_IsTrue(keepPlacement)); + ocaf.exportObjects(objs); + }else{ + bool keepExplicitPlacement = objs.size() > 1; + keepExplicitPlacement = Standard_True; + ExportOCAF ocaf(hDoc, keepExplicitPlacement); + // That stuff is exporting a list of selected objects into FreeCAD Tree + std::vector hierarchical_label; + std::vector hierarchical_loc; + std::vector hierarchical_part; + for(auto obj : objs) + ocaf.exportObject(obj,hierarchical_label, hierarchical_loc,hierarchical_part); + + // Free Shapes must have absolute placement and not explicit + std::vector FreeLabels; + std::vector part_id; + ocaf.getFreeLabels(hierarchical_label,FreeLabels, part_id); #if OCC_VERSION_HEX >= 0x070200 - // Update is not performed automatically anymore: https://tracker.dev.opencascade.org/view.php?id=28055 - XCAFDoc_DocumentTool::ShapeTool(hDoc->Main())->UpdateAssemblies(); + // Update is not performed automatically anymore: https://tracker.dev.opencascade.org/view.php?id=28055 + XCAFDoc_DocumentTool::ShapeTool(hDoc->Main())->UpdateAssemblies(); #endif + } Base::FileInfo file(Utf8Name.c_str()); if (file.hasExtension("stp") || file.hasExtension("step")) { diff --git a/src/Mod/Import/App/CMakeLists.txt b/src/Mod/Import/App/CMakeLists.txt index a8a8da6bb852..685e11eb6897 100644 --- a/src/Mod/Import/App/CMakeLists.txt +++ b/src/Mod/Import/App/CMakeLists.txt @@ -31,6 +31,8 @@ SET(Import_SRCS ExportOCAF.h ImportOCAF.cpp ImportOCAF.h + ImportOCAF2.cpp + ImportOCAF2.h #ImportOCAFAssembly.cpp #ImportOCAFAssembly.h StepShapePy.xml diff --git a/src/Mod/Import/App/ImportOCAF.cpp b/src/Mod/Import/App/ImportOCAF.cpp index 9327dcade23f..aa4a96259214 100644 --- a/src/Mod/Import/App/ImportOCAF.cpp +++ b/src/Mod/Import/App/ImportOCAF.cpp @@ -54,7 +54,9 @@ # include # include # include +# include # include +# include # include # include # include @@ -81,11 +83,14 @@ # endif #endif +#include +#include #include #include #include #include #include +#include #include #include #include "ImportOCAF.h" @@ -102,11 +107,8 @@ #include #endif - - using namespace Import; - #define OCAF_KEEP_PLACEMENT ImportOCAF::ImportOCAF(Handle(TDocStd_Document) h, App::Document* d, const std::string& name) diff --git a/src/Mod/Import/App/ImportOCAF.h b/src/Mod/Import/App/ImportOCAF.h index 0da9c8ee2a82..8c4d609265cb 100644 --- a/src/Mod/Import/App/ImportOCAF.h +++ b/src/Mod/Import/App/ImportOCAF.h @@ -29,10 +29,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include diff --git a/src/Mod/Import/App/ImportOCAF2.cpp b/src/Mod/Import/App/ImportOCAF2.cpp new file mode 100644 index 000000000000..980455019853 --- /dev/null +++ b/src/Mod/Import/App/ImportOCAF2.cpp @@ -0,0 +1,1338 @@ +/**************************************************************************** + * Copyright (c) 2018 Zheng, Lei (realthunder) * + * * + * 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" +#if defined(__MINGW32__) +# define WNT // avoid conflict with GUID +#endif +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ImportOCAF2.h" +#include +#include +#include + +#include +#include + +FC_LOG_LEVEL_INIT("Import",true,true) + +using namespace Import; + +///////////////////////////////////////////////////////////////////// + +static std::string labelName(TDF_Label label) { + std::string txt; + Handle(TDataStd_Name) name; + if (!label.IsNull() && label.FindAttribute(TDataStd_Name::GetID(),name)) { + TCollection_ExtendedString extstr = name->Get(); + char* str = new char[extstr.LengthOfCString()+1]; + extstr.ToUTF8CString(str); + txt = str; + delete[] str; + boost::trim(txt); + } + return txt; +} + +static void printLabel(TDF_Label label, Handle(XCAFDoc_ShapeTool) aShapeTool, + Handle(XCAFDoc_ColorTool) aColorTool, const char *msg = 0) +{ + if(label.IsNull() || !FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) + return; + if(!msg) msg = "Label: "; + TCollection_AsciiString entry; + TDF_Tool::Entry(label,entry); + std::ostringstream ss; + ss << msg << entry << ", " << labelName(label) + << (aShapeTool->IsShape(label)?", shape":"") + << (aShapeTool->IsTopLevel(label)?", topLevel":"") + << (aShapeTool->IsFree(label)?", free":"") + << (aShapeTool->IsAssembly(label)?", assembly":"") + << (aShapeTool->IsSimpleShape(label)?", simple":"") + << (aShapeTool->IsCompound(label)?", compound":"") + << (aShapeTool->IsReference(label)?", reference":"") + << (aShapeTool->IsComponent(label)?", component":"") + << (aShapeTool->IsSubShape(label)?", subshape":""); + if(aShapeTool->IsSubShape(label)) { + auto shape = aShapeTool->GetShape(label); + if(!shape.IsNull()) + ss << ", " << Part::TopoShape::shapeName(shape.ShapeType(),true); + } + if(aShapeTool->IsShape(label)) { + Quantity_Color c; + if(aColorTool->GetColor(label,XCAFDoc_ColorGen,c)) + ss << ", gc: " << c.StringName(c.Name()); + if(aColorTool->GetColor(label,XCAFDoc_ColorSurf,c)) + ss << ", sc: " << c.StringName(c.Name()); + if(aColorTool->GetColor(label,XCAFDoc_ColorCurv,c)) + ss << ", cc: " << c.StringName(c.Name()); + } + + ss << std::endl; + Base::Console().NotifyLog(ss.str().c_str()); +} + +static void dumpLabels(TDF_Label label, Handle(XCAFDoc_ShapeTool) aShapeTool, + Handle(XCAFDoc_ColorTool) aColorTool, int depth=0) +{ + std::string indent(depth*2,' '); + printLabel(label,aShapeTool,aColorTool,indent.c_str()); + TDF_ChildIterator it; + for (it.Initialize(label); it.More(); it.Next()) + dumpLabels(it.Value(),aShapeTool,aColorTool,depth+1); +} + +///////////////////////////////////////////////////////////////////// + +ImportOCAF2::ImportOCAF2(Handle(TDocStd_Document) h, App::Document* d, const std::string& name) + : pDoc(h), pDocument(d), default_name(name), sequencer(0) +{ + aShapeTool = XCAFDoc_DocumentTool::ShapeTool (pDoc->Main()); + aColorTool = XCAFDoc_DocumentTool::ColorTool(pDoc->Main()); + + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Import/hSTEP"); + merge = hGrp->GetBool("ReadShapeCompoundMode", true); + + hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Import"); + useLinkGroup = hGrp->GetBool("UseLinkGroup",true); + useBaseName = hGrp->GetBool("UseBaseName",true); + importHidden = hGrp->GetBool("ImportHiddenObject",true); + reduceObjects = hGrp->GetBool("ReduceObjects",true); + showProgress = hGrp->GetBool("ShowProgress",true); + expandCompound = hGrp->GetBool("ExpandCompound",true); + + if(d->isSaved()) { + Base::FileInfo fi(d->FileName.getValue()); + filePath = fi.dirPath(); + } + mode = hGrp->GetInt("ImportMode",SingleDoc); + + hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + defaultFaceColor.setPackedValue(hGrp->GetUnsigned("DefaultShapeColor",0xCCCCCC00)); + defaultFaceColor.a = 0; + + defaultEdgeColor.setPackedValue(hGrp->GetUnsigned("DefaultShapeLineColor",421075455UL)); + defaultEdgeColor.a = 0; + + if(useLinkGroup) { + // Interface_Static::SetIVal("read.stepcaf.subshapes.name",1); + aShapeTool->SetAutoNaming(Standard_False); + } +} + +ImportOCAF2::~ImportOCAF2() +{ +} + +void ImportOCAF2::setMode(int m) { + if(m<0 || m>=ModeMax) + FC_WARN("Invalid import mode " << m); + else + mode = m; + if(mode!=SingleDoc) { + if(pDocument->isSaved()) { + Base::FileInfo fi(pDocument->FileName.getValue()); + filePath = fi.dirPath(); + }else + FC_WARN("Diable multi-document mode because the input document is not saved."); + } +} + +static void setPlacement(App::PropertyPlacement *prop, const TopoDS_Shape &shape) { + prop->setValue(Base::Placement( + Part::TopoShape::convert(shape.Location().Transformation()))*prop->getValue()); +} + +std::string ImportOCAF2::getLabelName(TDF_Label label) { + std::string name; + if(label.IsNull()) + return name; + if(!XCAFDoc_ShapeTool::IsReference(label)) + return labelName(label); + if(!useBaseName) + name = labelName(label); + TDF_Label ref; + if(name.empty() && XCAFDoc_ShapeTool::GetReferredShape(label,ref)) + name = labelName(ref); + return name; +} + +void ImportOCAF2::setObjectName(Info &info, TDF_Label label) { + if(!info.obj) + return; + info.baseName = getLabelName(label); + if(info.baseName.size()) + info.obj->Label.setValue(info.baseName.c_str()); + else{ + auto linked = info.obj->getLinkedObject(false); + if(!linked || linked==info.obj) + return; + info.obj->Label.setValue(linked->Label.getValue()); + } +} + + +bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bool noDefault) { + bool ret = false; + Quantity_Color aColor; + if(aColorTool->GetColor(shape, XCAFDoc_ColorSurf, aColor)) { + App::Color c(aColor.Red(),aColor.Green(),aColor.Blue()); + if(!check || info.faceColor!=c) { + info.faceColor = c; + info.hasFaceColor = true; + ret = true; + } + } + if(!noDefault && !info.hasFaceColor && aColorTool->GetColor(shape, XCAFDoc_ColorGen, aColor)) { + App::Color c(aColor.Red(),aColor.Green(),aColor.Blue()); + if(!check || info.faceColor!=c) { + info.faceColor = c; + info.hasFaceColor = true; + ret = true; + } + } + if(aColorTool->GetColor(shape, XCAFDoc_ColorCurv, aColor)) { + App::Color c(aColor.Red(),aColor.Green(),aColor.Blue()); + // Some STEP include a curve color with the same value of the face + // color. And this will look weird in FC. So for shape with face + // we'll ignore the curve color, if it is the same as the face color. + if((c!=info.faceColor || !TopExp_Explorer(shape,TopAbs_FACE).More()) && + (!check || info.edgeColor!=c)) + { + info.edgeColor = c; + info.hasEdgeColor = true; + ret = true; + } + } + if(!check) { + if(!info.hasFaceColor) + info.faceColor = defaultFaceColor; + if(!info.hasEdgeColor) + info.edgeColor = defaultEdgeColor; + } + return ret; +} + +App::DocumentObject *ImportOCAF2::expandShape( + App::Document *doc, TDF_Label label, const TopoDS_Shape &shape) +{ + if(shape.IsNull() || !TopExp_Explorer(shape,TopAbs_VERTEX).More()) + return 0; + + // When saved as compound, STEP file does not support instance sharing, + // meaning that even if the source compound may contain child shapes of + // shared instances, or multiple hierarchies, those information are lost + // when saved to STEP, everything become flat and duplicated. So the code + // below is not necessary. +#if 0 + auto baseShape = shape.Located(TopLoc_Location()); + auto it = myShapes.find(baseShape); + if(it!=myShapes.end()) { + auto link = static_cast(doc->addObject("App::Link","Link")); + link->Visibility.setValue(false); + link->setLink(-1,it->second.obj); + setPlacement(&link->Placement,shape); + return link; + } +#endif + std::vector objs; + + if(shape.ShapeType() == TopAbs_COMPOUND) { + for(TopoDS_Iterator it(shape,0,0);it.More();it.Next()) { + TDF_Label childLabel; + if(!label.IsNull()) + aShapeTool->FindSubShape(label,it.Value(),childLabel); + auto child = expandShape(doc,childLabel,it.Value()); + if(child) { + objs.push_back(child); + Info info; + info.free = false; + info.obj = child; + myShapes.emplace(it.Value().Located(TopLoc_Location()),info); + } + } + if(objs.empty()) + return 0; + auto compound = static_cast(doc->addObject("Part::Compound2","Compound")); + compound->Links.setValues(objs); + // compound->Visibility.setValue(false); + setPlacement(&compound->Placement,shape); + return compound; + } + Info info; + info.obj = 0; + createObject(doc,label,shape,info,false); + return info.obj; +} + +bool ImportOCAF2::createObject(App::Document *doc, TDF_Label label, + const TopoDS_Shape &shape, Info &info, bool newDoc) +{ + if(shape.IsNull() || !TopExp_Explorer(shape,TopAbs_VERTEX).More()) { + FC_WARN(labelName(label) << " has empty shape"); + return false; + } + + getColor(shape,info); + bool hasFaceColors = false; + bool hasEdgeColors = false; + + Part::TopoShape tshape(shape); + std::vector faceColors; + std::vector edgeColors; + + TDF_LabelSequence seq; + if(!label.IsNull() && aShapeTool->GetSubShapes(label,seq)) { + + TopTools_IndexedMapOfShape faceMap,edgeMap; + TopExp::MapShapes(tshape.getShape(), TopAbs_FACE, faceMap); + TopExp::MapShapes(tshape.getShape(), TopAbs_EDGE, edgeMap); + + faceColors.assign(faceMap.Extent(),info.faceColor); + edgeColors.assign(edgeMap.Extent(),info.edgeColor); + // Two passes to get sub shape colors. First pass, look for solid, and + // second pass look for face and edges. This allows lower level + // subshape to override color of higher level ones. + for(int j=0;j<2;++j) { + for(int i=1;i<=seq.Length();++i) { + TDF_Label l = seq.Value(i); + TopoDS_Shape subShape = aShapeTool->GetShape(l); + if(subShape.IsNull()) + continue; + if(subShape.ShapeType()==TopAbs_FACE || subShape.ShapeType()==TopAbs_EDGE) { + if(j==0) + continue; + }else if(j!=0) + continue; + + bool foundFaceColor=false,foundEdgeColor=false; + App::Color faceColor,edgeColor; + Quantity_Color aColor; + if(aColorTool->GetColor(l, XCAFDoc_ColorSurf, aColor) || + aColorTool->GetColor(l, XCAFDoc_ColorGen, aColor)) + { + faceColor = App::Color(aColor.Red(),aColor.Green(),aColor.Blue()); + foundFaceColor = true; + } + if(aColorTool->GetColor(l, XCAFDoc_ColorCurv, aColor)) { + edgeColor = App::Color(aColor.Red(),aColor.Green(),aColor.Blue()); + foundEdgeColor = true; + if(j==0 && foundFaceColor && faceColors.size() && edgeColor==faceColor) { + // Do not set edge the same color as face + foundEdgeColor = false; + } + } + + if(foundFaceColor) { + for(TopExp_Explorer exp(subShape,TopAbs_FACE);exp.More();exp.Next()) { + int idx = faceMap.FindIndex(exp.Current())-1; + if(idx>=0 && idx<(int)faceColors.size()) { + faceColors[idx] = faceColor; + hasFaceColors = true; + info.hasFaceColor = true; + }else + assert(0); + } + } + if(foundEdgeColor) { + for(TopExp_Explorer exp(subShape,TopAbs_EDGE);exp.More();exp.Next()) { + int idx = edgeMap.FindIndex(exp.Current())-1; + if(idx>=0 && idx<(int)edgeColors.size()) { + edgeColors[idx] = edgeColor; + hasEdgeColors = true; + info.hasEdgeColor = true; + } + } + } + } + } + } + + Part::Feature *feature; + + if(newDoc && (mode==ObjectPerDoc || mode==ObjectPerDir)) + doc = getDocument(doc,label); + + if(expandCompound && + (tshape.countSubShapes(TopAbs_SOLID)>1 || + (!tshape.countSubShapes(TopAbs_SOLID) && tshape.countSubShapes(TopAbs_SHELL)>1))) + { + feature = dynamic_cast(expandShape(doc,label,shape)); + assert(feature); + } else { + feature = static_cast(doc->addObject("Part::Feature",tshape.shapeName().c_str())); + feature->Shape.setValue(shape); + // feature->Visibility.setValue(false); + } + applyFaceColors(feature,{info.faceColor}); + applyEdgeColors(feature,{info.edgeColor}); + if(hasFaceColors) + applyFaceColors(feature,faceColors); + if(hasEdgeColors) + applyEdgeColors(feature,edgeColors); + + info.propPlacement = &feature->Placement; + info.obj = feature; + return true; +} + +App::Document *ImportOCAF2::getDocument(App::Document *doc, TDF_Label label) { + if(filePath.empty() || mode==SingleDoc || merge) + return doc; + + auto name = getLabelName(label); + if(name.empty()) + return doc; + + auto newDoc = App::GetApplication().newDocument(name.c_str(),name.c_str(),false); + std::ostringstream ss; + Base::FileInfo fi(doc->FileName.getValue()); + std::string path = fi.dirPath(); + if(mode == GroupPerDir || mode == ObjectPerDir) { + for(int i=0;i<1000;++i) { + ss.str(""); + ss << path << '/' << fi.fileNamePure() << "_parts"; + if(i>0) + ss << '_' << std::setfill('0') << std::setw(3) << i; + Base::FileInfo fi2(ss.str()); + if(fi2.exists()) { + if(!fi2.isDir()) + continue; + }else if(!fi2.createDirectory()) { + FC_WARN("Failed to create directory " << fi2.filePath()); + break; + } + path = fi2.filePath(); + break; + } + } + for(int i=0;i<1000;++i) { + ss.str(""); + ss << path << '/' << newDoc->getName() << ".fcstd"; + if(i>0) + ss << '_' << std::setfill('0') << std::setw(3) << i; + Base::FileInfo fi(ss.str()); + if(!fi.exists()) { + if(!newDoc->saveAs(fi.filePath().c_str())) + break; + return newDoc; + } + } + + FC_WARN("Cannot save document for part '" << name << "'"); + return doc; +} + +bool ImportOCAF2::createGroup(App::Document *doc, Info &info, const TopoDS_Shape &shape, + std::vector &children, + const boost::dynamic_bitset<> &visibilities, + bool canReduce) +{ + assert(children.size() == visibilities.size()); + if(children.empty()) + return false; + bool hasColor = getColor(shape,info,false,true); + if(canReduce && !hasColor && reduceObjects && children.size()==1 && visibilities[0]) { + info.obj = children.front(); + info.free = true; + info.propPlacement = dynamic_cast(info.obj->getPropertyByName("Placement")); + myCollapsedObjects.emplace(info.obj,info.propPlacement); + return true; + } + auto group = static_cast(doc->addObject("App::LinkGroup","LinkGroup")); + for(auto &child : children) { + if(child->getDocument()!=doc) { + auto link = static_cast(doc->addObject("App::Link","Link")); + link->Label.setValue(child->Label.getValue()); + link->setLink(-1,child); + auto pla = Base::freecad_dynamic_cast( + child->getPropertyByName("Placement")); + if(pla) + link->Placement.setValue(pla->getValue()); + child = link; + } + // child->Visibility.setValue(false); + } + // group->Visibility.setValue(false); + group->ElementList.setValues(children); + group->VisibilityList.setValue(visibilities); + info.obj = group; + info.propPlacement = &group->Placement; + if(getColor(shape,info,false,true)) { + if(info.hasFaceColor) + applyLinkColor(group,-1,info.faceColor); + } + return true; +} + +App::DocumentObject* ImportOCAF2::loadShapes() +{ + if(!useLinkGroup) { + ImportLegacy legacy(*this); + legacy.setMerge(merge); + legacy.loadShapes(); + return 0; + } + + if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) + dumpLabels(pDoc->Main(),aShapeTool,aColorTool); + + TDF_LabelSequence labels; + aShapeTool->GetShapes(labels); + Base::SequencerLauncher seq("Importing...",labels.Length()); + FC_MSG("free shape count " << labels.Length()); + sequencer = showProgress?&seq:0; + + labels.Clear(); + myShapes.clear(); + myNames.clear(); + myCollapsedObjects.clear(); + + std::vector objs; + aShapeTool->GetFreeShapes (labels); + boost::dynamic_bitset<> vis; + int count = 0; + for (Standard_Integer i=1; i <= labels.Length(); i++ ) { + auto label = labels.Value(i); + if(!importHidden && !aColorTool->IsVisible(label)) + continue; + ++count; + } + for (Standard_Integer i=1; i <= labels.Length(); i++ ) { + auto label = labels.Value(i); + if(!importHidden && !aColorTool->IsVisible(label)) + continue; + auto obj = loadShape(pDocument, label, + aShapeTool->GetShape(label), false, count>1); + if(obj) { + objs.push_back(obj); + vis.push_back(aColorTool->IsVisible(label)); + } + } + App::DocumentObject *ret = 0; + if(objs.size()==1) { + ret = objs.front(); + }else { + Info info; + if(createGroup(pDocument,info,TopoDS_Shape(),objs,vis)) + ret = info.obj; + } + if(ret) { + // ret->Visibility.setValue(true); + ret->recomputeFeature(true); + } + if(merge && ret && !ret->isDerivedFrom(Part::Feature::getClassTypeId())) { + auto shape = Part::Feature::getTopoShape(ret); + auto feature = static_cast( + pDocument->addObject("Part::Feature", "Feature")); + auto name = labelName(pDoc->Main()); + feature->Label.setValue(name.empty()?default_name.c_str():name.c_str()); + feature->Shape.setValue(shape); + applyFaceColors(feature,{}); + + std::vector > objNames; + for(auto obj : App::Document::getDependencyList(objs,App::Document::DepSort)) + objNames.emplace_back(obj->getDocument(),obj->getNameInDocument()); + for(auto &v : objNames) + v.first->removeObject(v.second.c_str()); + ret = feature; + ret->recomputeFeature(true); + } + sequencer = 0; + return ret; +} + +void ImportOCAF2::getSHUOColors(TDF_Label label, + std::map &colors, bool appendFirst) +{ + TDF_AttributeSequence seq; + if(label.IsNull() || !aShapeTool->GetAllComponentSHUO(label,seq)) + return; + std::ostringstream ss; + for(int i=1;i<=seq.Length();++i) { + Handle(XCAFDoc_GraphNode) shuo = Handle(XCAFDoc_GraphNode)::DownCast(seq.Value(i)); + if(shuo.IsNull()) + continue; + + TDF_Label slabel = shuo->Label(); + + // We only want to process the main shuo, i.e. those without upper_usage + TDF_LabelSequence uppers; + aShapeTool->GetSHUOUpperUsage(slabel, uppers); + if(uppers.Length()) + continue; + + // appendFirst tells us whether we shall append the object name of the first label + bool skipFirst = !appendFirst; + ss.str(""); + while(1) { + if(skipFirst) + skipFirst = false; + else { + TDF_Label l = shuo->Label().Father(); + auto it = myNames.find(l); + if(it == myNames.end()) { + FC_WARN("Failed to find object of label " << labelName(l)); + ss.str(""); + break; + } + if(it->second.size()) + ss << it->second << '.'; + } + if(!shuo->NbChildren()) + break; + shuo = shuo->GetChild(1); + } + std::string subname = ss.str(); + if(subname.empty()) + continue; + if(!aColorTool->IsVisible(slabel)) { + subname += App::DocumentObject::hiddenMarker(); + colors.emplace(subname,App::Color()); + } else { + Quantity_Color aColor; + if(aColorTool->GetColor(slabel, XCAFDoc_ColorSurf, aColor) || + aColorTool->GetColor(slabel, XCAFDoc_ColorGen, aColor)) + { + colors.emplace(subname,App::Color(aColor.Red(),aColor.Green(),aColor.Blue())); + } + } + } +} + +App::DocumentObject *ImportOCAF2::loadShape(App::Document *doc, + TDF_Label label, const TopoDS_Shape &shape, bool baseOnly, bool newDoc) +{ + if(shape.IsNull()) + return 0; + + auto baseShape = shape.Located(TopLoc_Location()); + auto it = myShapes.find(baseShape); + if(it == myShapes.end()) { + Info info; + auto baseLabel = aShapeTool->FindShape(baseShape); + if(sequencer && !baseLabel.IsNull() && aShapeTool->IsTopLevel(baseLabel)) + sequencer->next(true); + bool res; + if(baseLabel.IsNull() || !aShapeTool->IsAssembly(baseLabel)) + res = createObject(doc,baseLabel,baseShape,info,newDoc); + else + res = createAssembly(doc,baseLabel,baseShape,info,newDoc); + if(!res) + return 0; + setObjectName(info,baseLabel); + it = myShapes.emplace(baseShape,info).first; + } + if(baseOnly) + return it->second.obj; + + std::map shuoColors; + if(!useLinkGroup) + getSHUOColors(label,shuoColors,false); + + auto info = it->second; + getColor(shape,info,true); + + if(shuoColors.empty() && info.free && doc==info.obj->getDocument()) { + it->second.free = false; + auto name = getLabelName(label); + if(info.faceColor!=it->second.faceColor || + info.edgeColor!=it->second.edgeColor || + (name.size() && info.baseName.size() && name!=info.baseName)) + { + auto compound = static_cast(doc->addObject("Part::Compound2","Compound")); + compound->Links.setValue(info.obj); + // compound->Visibility.setValue(false); + info.propPlacement = &compound->Placement; + if(info.faceColor!=it->second.faceColor) + applyFaceColors(compound,{info.faceColor}); + if(info.edgeColor!=it->second.edgeColor) + applyEdgeColors(compound,{info.edgeColor}); + info.obj = compound; + setObjectName(info,label); + } + setPlacement(info.propPlacement,shape); + myNames.emplace(label,info.obj->getNameInDocument()); + return info.obj; + } + + auto link = static_cast(doc->addObject("App::Link","Link")); + // link->Visibility.setValue(false); + link->setLink(-1,info.obj); + setPlacement(&link->Placement,shape); + info.obj = link; + setObjectName(info,label); + if(info.faceColor!=it->second.faceColor) + applyLinkColor(link,-1,info.faceColor); + + myNames.emplace(label,link->getNameInDocument()); + if(shuoColors.size()) + applyElementColors(link,shuoColors); + return link; +} + +struct ChildInfo { + std::vector plas; + boost::dynamic_bitset<> vis; + std::map colors; + std::vector labels; + TopoDS_Shape shape; +}; + +bool ImportOCAF2::createAssembly(App::Document *_doc, + TDF_Label label, const TopoDS_Shape &shape, Info &info, bool newDoc) +{ + (void)label; + + std::vector children; + std::map childrenMap; + boost::dynamic_bitset<> visibilities; + std::map shuoColors; + + auto doc = _doc; + if(newDoc) + doc = getDocument(_doc,label); + + for(TopoDS_Iterator it(shape,0,0);it.More();it.Next()) { + TopoDS_Shape childShape = it.Value(); + if(childShape.IsNull()) + continue; + TDF_Label childLabel; + aShapeTool->Search(childShape,childLabel,Standard_True,Standard_True,Standard_False); + if(!childLabel.IsNull() && !importHidden && !aColorTool->IsVisible(childLabel)) + continue; + auto obj = loadShape(doc,childLabel,childShape,reduceObjects); + if(!obj) + continue; + bool vis = true; + if(!childLabel.IsNull() && aShapeTool->IsComponent(childLabel)) + vis = aColorTool->IsVisible(childLabel); + if(!reduceObjects) { + visibilities.push_back(vis); + children.push_back(obj); + getSHUOColors(childLabel,shuoColors,true); + continue; + } + + auto &info = childrenMap[obj]; + if(info.plas.empty()) { + children.push_back(obj); + visibilities.push_back(vis); + info.shape = childShape; + } + info.vis.push_back(vis); + info.labels.push_back(childLabel); + info.plas.emplace_back(Part::TopoShape::convert(childShape.Location().Transformation())); + Quantity_Color aColor; + if (aColorTool->GetColor(childShape, XCAFDoc_ColorSurf, aColor)) { + auto &color = info.colors[info.plas.size()-1]; + color.r = (float)aColor.Red(); + color.g = (float)aColor.Green(); + color.b = (float)aColor.Blue(); + } + } + assert(visibilities.size() == children.size()); + + if(children.empty()) { + if(doc!=_doc) + App::GetApplication().closeDocument(doc->getName()); + return false; + } + + if(reduceObjects) { + int i=-1; + for(auto &child : children) { + ++i; + auto &info = childrenMap[child]; + if(info.plas.size()==1) { + child = loadShape(doc,info.labels.front(),info.shape); + getSHUOColors(info.labels.front(),shuoColors,true); + continue; + } + + visibilities[i] = true; + + // Okay, we are creating a link array + auto link = static_cast(doc->addObject("App::Link","Link")); + // link->Visibility.setValue(false); + link->setLink(-1,child); + link->ShowElement.setValue(false); + link->ElementCount.setValue(info.plas.size()); + auto it = myCollapsedObjects.find(child); + if(it!=myCollapsedObjects.end()) { + // child is a single component assembly that has been + // collapsed, so we have to honour its placement + for(auto &pla : info.plas) + pla *= it->second->getValue(); + } + link->PlacementList.setValue(info.plas); + link->VisibilityList.setValue(info.vis); + + for(auto &v : info.colors) + applyLinkColor(link,v.first,v.second); + + int i=0; + std::string name = link->getNameInDocument(); + name += '.'; + for(auto childLabel : info.labels) { + myNames.emplace(childLabel,name + std::to_string(i++)); + getSHUOColors(childLabel,shuoColors,true); + } + + child = link; + Info objInfo; + objInfo.obj = child; + setObjectName(objInfo,info.labels.front()); + } + } + + if(children.empty()) + return false; + + if(!createGroup(doc,info,shape,children,visibilities,shuoColors.empty())) + return false; + if(shuoColors.size()) + applyElementColors(info.obj,shuoColors); + return true; +} + +// ---------------------------------------------------------------------------- + +ExportOCAF2::ExportOCAF2(Handle(TDocStd_Document) h, GetShapeColorsFunc func) + : pDoc(h) , getShapeColors(func) +{ + aShapeTool = XCAFDoc_DocumentTool::ShapeTool(pDoc->Main()); + aColorTool = XCAFDoc_DocumentTool::ColorTool(pDoc->Main()); + + auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Import"); + exportHidden = hGrp->GetBool("ExportHiddenObject",true); + keepPlacement = hGrp->GetBool("ExportKeepPlacement",false); + + Interface_Static::SetIVal("write.step.assembly",2); + + auto handle = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + defaultColor.setPackedValue(handle->GetUnsigned("DefaultShapeColor",0xCCCCCC00)); + defaultColor.a = 0; +} + +void ExportOCAF2::setName(TDF_Label label, App::DocumentObject *obj, const char *name) { + if(!name) { + if(!obj) + return; + name = obj->Label.getValue(); + } + TDataStd_Name::Set(label, TCollection_ExtendedString(name, 1)); +} + +// Similar to XCAFDoc_ShapeTool::FindSHUO but return only main SHUO, i.e. SHUO +// with no upper_usage. It should not be necssary if we strictly export from +// bottom up, but let's make sure of it. +static Standard_Boolean FindSHUO (const TDF_LabelSequence& theLabels, + Handle(XCAFDoc_GraphNode)& theSHUOAttr) +{ + assert(theLabels.Length()>1); + theSHUOAttr.Nullify(); + TDF_AttributeSequence SHUOAttrs; + TDF_Label aCompLabel = theLabels.Value(1); + if (! ::XCAFDoc_ShapeTool::GetAllComponentSHUO( aCompLabel, SHUOAttrs ) ) + return Standard_False; + for (Standard_Integer i = 1; i <= SHUOAttrs.Length(); i++) { + Handle(XCAFDoc_GraphNode) anSHUO = Handle(XCAFDoc_GraphNode)::DownCast(SHUOAttrs.Value(i)); + TDF_LabelSequence aUpLabels; + // check for any upper_usage + ::XCAFDoc_ShapeTool::GetSHUOUpperUsage( anSHUO->Label(), aUpLabels ); + if ( aUpLabels.Length() > 0 ) + continue; // reject if there is one + int j=2; + for ( ; anSHUO->NbChildren() ; ++j ) { + if ( j>theLabels.Length() ) { + j=0; + break; + } + anSHUO = anSHUO->GetChild( 1 ); + if ( theLabels.Value(j)!=anSHUO->Label().Father() ) { + j=0; + break; + } + } + if( j!=theLabels.Length()+1 ) + continue; + + theSHUOAttr = Handle(XCAFDoc_GraphNode)::DownCast(SHUOAttrs.Value(i)); + break; + } + return ( !theSHUOAttr.IsNull() ); +} + +TDF_Label ExportOCAF2::findComponent(const char *subname, TDF_Label label, TDF_LabelSequence &labels) { + const char *dot = strchr(subname,'.'); + if(!dot) { + if(labels.Length()==1) + return labels.Value(1); + Handle(XCAFDoc_GraphNode) ret; + if(labels.Length() && (FindSHUO(labels,ret) || aShapeTool->SetSHUO(labels,ret))) + return ret->Label(); + return TDF_Label(); + } + TDF_LabelSequence components; + TDF_Label ref; + if(!aShapeTool->GetReferredShape(label,ref)) + ref = label; + if(aShapeTool->GetComponents(ref,components)) { + for(int i=1;i<=components.Length();++i) { + auto component = components.Value(i); + if(std::isdigit((int)subname[0])) { + auto n = std::to_string(i-1)+"."; + if(boost::starts_with(subname,n)) { + labels.Append(component); + return findComponent(subname+n.size(),component,labels); + } + } + auto it = myNames.find(component); + if(it == myNames.end()) + continue; + for(auto &n : it->second) { + if(boost::starts_with(subname,n)) { + labels.Append(component); + return findComponent(subname+n.size(),component,labels); + } + } + } + } + return TDF_Label(); +} + +void ExportOCAF2::setupObject(TDF_Label label, App::DocumentObject *obj, + const Part::TopoShape &shape, const std::string &prefix, const char *name, bool force) +{ + setName(label,obj,name); + if(aShapeTool->IsComponent(label)) { + auto &names = myNames[label]; + // The subname reference may contain several possible namings. + if(!name) { + // simple object internal name + names.push_back(prefix+obj->getNameInDocument()+"."); + } else { + // name is not NULL in case this is a collapsed link array element. + // Collapsed means that the element is not an actual object, and + // 'obj' here is actually the parent. The given 'name' is in fact + // the element index + names.push_back(prefix + name + "."); + // In case the subname reference is created when the link array is + // previously expanded, the element object will be named as the + // parent object internal name + '_i' + names.push_back(prefix + obj->getNameInDocument() + "_i" + name + "."); + } + // Finally, the subname reference allows to use the label for naming + // with preceeding '$' + names.push_back(prefix + "$" + obj->Label.getValue() + "."); + } + + if(!getShapeColors || (!force && !mySetups.emplace(obj,name?name:"").second)) + return; + + std::map > colors; + static std::string marker(App::DocumentObject::hiddenMarker()+"*"); + static std::array keys = {"Face*","Edge*",marker.c_str()}; + std::string childName; + if(name) { + childName = name; + childName += '.'; + } + for(auto key : keys) { + for(auto &v : getShapeColors(obj,key)) { + const char *subname = v.first.c_str(); + if(name) { + if(!boost::starts_with(v.first,childName)) + continue; + subname += childName.size(); + } + const char *dot = strrchr(subname,'.'); + if(!dot) + colors[""].emplace(subname,v.second); + else { + ++dot; + colors[std::string(subname,dot-subname)].emplace(dot,v.second); + } + } + } + + bool warned = false; + + for(auto &v : colors) { + TDF_Label nodeLabel = label; + if(v.first.size()) { + TDF_LabelSequence labels; + if(aShapeTool->IsComponent(label)) + labels.Append(label); + nodeLabel = findComponent(v.first.c_str(),label,labels); + if(nodeLabel.IsNull()) { + FC_WARN("Failed to find component " << v.first); + continue; + } + } + for(auto &vv : v.second) { + if(vv.first == App::DocumentObject::hiddenMarker()) { + aColorTool->SetVisibility(nodeLabel,Standard_False); + continue; + } + const App::Color& c = vv.second; + Quantity_Color color(c.r,c.g,c.b,Quantity_TOC_RGB); + auto colorType = vv.first[0]=='F'?XCAFDoc_ColorSurf:XCAFDoc_ColorCurv; + if(vv.first=="Face" || vv.first=="Edge") { + aColorTool->SetColor(nodeLabel, color, colorType); + continue; + } + + if(nodeLabel!=label || aShapeTool->IsComponent(label)) { + // OCCT 7 seems to only support "Recommended practices for + // model styling and organization" version 1.2 + // (https://www.cax-if.org/documents/rec_prac_styling_org_v12.pdf). + // The SHUO described in section 5.3 does not mention the + // capability of overriding context-depdendent element color, + // only whole shape color. Newer version of the same document + // (https://www.cax-if.org/documents/rec_prac_styling_org_v15.pdf) + // does support this, in section 5.1. + // + // The above observation is confirmed by further inspection of + // OCCT code, XCAFDoc_ShapeTool.cxx and STEPCAFControl_Writer.cxx. + if(!warned) { + warned = true; + FC_WARN("Current OCCT does not support element color override, for object " + << obj->getFullName()); + } + // continue; + } + + auto subShape = shape.getSubShape(vv.first.c_str(),true); + if(subShape.IsNull()) { + FC_WARN("Failed to get subshape " << vv.first); + continue; + } + + // The following code is copied from OCCT 7.3 and is a work around + // a bug in previous versions + Handle(XCAFDoc_ShapeMapTool) A; + if (!nodeLabel.FindAttribute(XCAFDoc_ShapeMapTool::GetID(), A)) { + TopoDS_Shape aShape = aShapeTool->GetShape(nodeLabel); + if (!aShape.IsNull()) { + A = XCAFDoc_ShapeMapTool::Set(nodeLabel); + A->SetShape(aShape); + } + } + + TDF_Label subLabel = aShapeTool->AddSubShape(nodeLabel, subShape); + if(subLabel.IsNull()) { + FC_WARN("Failed to add subshape " << vv.first); + continue; + } + aColorTool->SetColor(subLabel, color, colorType); + } + } +} + +void ExportOCAF2::exportObjects(std::vector &objs, const char *name) { + if(objs.empty()) + return; + myObjects.clear(); + myNames.clear(); + mySetups.clear(); + if(objs.size()==1) + exportObject(objs.front(),0,TDF_Label()); + else { + auto label = aShapeTool->NewShape(); + App::Document *doc = 0; + bool sameDoc = true; + for(auto obj : objs) { + if(doc) + sameDoc = sameDoc && doc==obj->getDocument(); + else + doc = obj->getDocument(); + exportObject(obj,0,label); + } + + if(!name && doc && sameDoc) + name = doc->getName(); + setName(label,0,name); + } + + if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) + dumpLabels(pDoc->Main(),aShapeTool,aColorTool); + +#if OCC_VERSION_HEX >= 0x070200 + // Update is not performed automatically anymore: https://tracker.dev.opencascade.org/view.php?id=28055 + aShapeTool->UpdateAssemblies(); +#endif +} + +TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj, + const char *sub, TDF_Label parent, const char *name) +{ + App::DocumentObject *obj; + auto shape = Part::Feature::getTopoShape(parentObj,sub,false,0,&obj,false,!sub); + if(!obj || shape.isNull()) { + FC_WARN(obj->getFullName() << " has null shape"); + return TDF_Label(); + } + + //sub may contain more than one hierarchy, e.g. Assembly container may use + //getSubObjects to skip some hierarchy containing constraints and stuff + //when exporting. We search for extra '.', and set it as prefix if found. + //When setting SHUO's, we'll need this prefix for matching. + std::string prefix; + if(sub) { + auto len = strlen(sub); + if(len>1) { + --len; + // The prefix ends with the second last '.', so search for it. + for(int i=0;len!=0;--len) { + if(sub[len]=='.' && ++i==2) { + prefix = std::string(sub,len+1); + break; + } + } + } + } + + TDF_Label label; + std::vector links; + + int depth = 0; + auto linked = obj; + auto linkedShape = shape; + while(1) { + auto s = Part::Feature::getTopoShape(linked); + if(s.isNull() || !s.getShape().IsPartner(shape.getShape())) + break; + linkedShape = s; + // Search using our own cache. We can't rely on ShapeTool::FindShape() + // in case this is an assembly. Because FindShape() search among its + // own computed shape, i.e. its own created compound, and thus will + // never match ours. + auto it = myObjects.find(linked); + if(it != myObjects.end()) { + for(auto l : links) + myObjects.emplace(l,it->second); + // Note: OCAF does not seem to support reference of references. We + // have to flaten all multi-level link without scales. In other + // word, all link will all be forced to refer to the same + // non-located shape + + // retrieve OCAF computed shape, in case the current object returns + // a new shape every time Part::Feature::getTopoShape() is called. + auto baseShape = aShapeTool->GetShape(it->second); + shape.setShape(baseShape.Located(shape.getShape().Location())); + if(!parent.IsNull()) + label = aShapeTool->AddComponent(parent,shape.getShape(),Standard_False); + else + label = aShapeTool->AddShape(shape.getShape(),Standard_False,Standard_False); + setupObject(label,name?parentObj:obj,shape,prefix,name); + return label; + } + auto next = linked->getLinkedObject(false,0,false,depth++); + if(!next || linked==next) + break; + linked = next; + links.push_back(linked); + } + + auto subs = obj->getSubObjects(); + // subs empty means obj is not a container. + if(subs.empty()) { + + if(!parent.IsNull()) { + // Search for non-located shape to see if we've stored the original shape before + if(!aShapeTool->FindShape(shape.getShape(),label)) { + auto baseShape = linkedShape; + auto linked = links.empty()?obj:links.back(); + baseShape.setShape(baseShape.getShape().Located(TopLoc_Location())); + label = aShapeTool->NewShape(); + aShapeTool->SetShape(label,baseShape.getShape()); + setupObject(label,linked,baseShape,prefix); + } + + label = aShapeTool->AddComponent(parent,shape.getShape(),Standard_False); + setupObject(label,name?parentObj:obj,shape,prefix,name); + + }else{ + // Here means we are exporting a single non-assembly object. We must + // not call setupObject() on a non-located baseshape like above, + // because OCCT does not respect shape style sharing when not + // exporting assembly + if(!keepPlacement) + shape.setShape(shape.getShape().Located(TopLoc_Location())); + label = aShapeTool->AddShape(shape.getShape(),Standard_False, Standard_False); + auto o = name?parentObj:obj; + if(o!=linked) + setupObject(label,linked,shape,prefix,0,true); + setupObject(label,o,shape,prefix,name,true); + } + + myObjects.emplace(obj, label); + for(auto link : links) + myObjects.emplace(link, label); + return label; + } + + if(obj->getExtensionByType(true) + || obj->getExtensionByType(true)) + groupLinks.push_back(obj); + + // Create a new assembly + label = aShapeTool->NewShape(); + + // check for link array + auto linkArray = obj->getLinkedObject(true)->getExtensionByType(true); + if(linkArray && (linkArray->getShowElementValue() || !linkArray->getElementCountValue())) + linkArray = 0; + for(auto &sub : subs) { + App::DocumentObject *parent = 0; + std::string childName; + auto sobj = obj->resolve(sub.c_str(),&parent,&childName); + if(!sobj) { + FC_WARN("Cannot find object " << obj->getFullName() << '.' << sub); + continue; + } + int vis = -1; + if(parent) { + if(groupLinks.size() + && parent->getExtensionByType(true,false)) + { + vis = groupLinks.back()->isElementVisible(childName.c_str()); + }else + vis = parent->isElementVisible(childName.c_str()); + } + + if(vis < 0) + vis = sobj->Visibility.getValue()?1:0; + + if(!vis && !exportHidden) + continue; + + TDF_Label childLabel = exportObject(obj,sub.c_str(),label,linkArray?childName.c_str():0); + if(childLabel.IsNull()) + continue; + + if(!vis) { + // Work around OCCT bug. If no color setting here, it will crash. + // The culprit is at STEPCAFControl_Writer::1093 as shown below + // + // surfColor = Styles.EncodeColor(Quantity_Color(1,1,1,Quantity_TOC_RGB),DPDCs,ColRGBs); + // PSA = Styles.MakeColorPSA ( item, surfColor, curvColor, isComponent ); + // if ( isComponent ) + // setDefaultInstanceColor( override, PSA); + // + // Can be fixed with following + // if ( !override.IsNull() && isComponent ) + // setDefaultInstanceColor( override, PSA); + // + auto childShape = aShapeTool->GetShape(childLabel); + Quantity_Color col; + if(!aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorGen,col) && + !aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorSurf,col) && + !aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorCurv,col)) + { + auto &c = defaultColor; + aColorTool->SetColor(childLabel, Quantity_Color(c.r,c.g,c.b,Quantity_TOC_RGB), XCAFDoc_ColorGen); + FC_WARN(labelName(childLabel) << " set default color"); + } + aColorTool->SetVisibility(childLabel,Standard_False); + } + } + + if(groupLinks.size() && groupLinks.back()==obj) + groupLinks.pop_back(); + + // Finished adding components. Now retrieve the computed non-located shape + auto baseShape = shape; + baseShape.setShape(aShapeTool->GetShape(label)); + + myObjects.emplace(obj, label); + for(auto link : links) + myObjects.emplace(link, label); + + if(!parent.IsNull() && links.size()) + linked = links.back(); + else + linked = obj; + setupObject(label,linked,baseShape,prefix); + + if(!parent.IsNull()) { + // If we are a component, swap in the base shape but keep our location. + shape.setShape(baseShape.getShape().Located(shape.getShape().Location())); + label = aShapeTool->AddComponent(parent,label,shape.getShape().Location()); + setupObject(label,name?parentObj:obj,shape,prefix,name); + } + return label; +} + +bool ExportOCAF2::canFallback(std::vector objs) { + for(size_t i=0;igetNameInDocument()) + continue; + if(obj->getExtensionByType(true)) + return false; + for(auto &sub : obj->getSubObjects()) + objs.push_back(obj->getSubObject(sub.c_str())); + } + return true; +} diff --git a/src/Mod/Import/App/ImportOCAF2.h b/src/Mod/Import/App/ImportOCAF2.h new file mode 100644 index 000000000000..cba6d0f51b75 --- /dev/null +++ b/src/Mod/Import/App/ImportOCAF2.h @@ -0,0 +1,212 @@ +/**************************************************************************** + * Copyright (c) 2018 Zheng, Lei (realthunder) * + * * + * 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 IMPORT_IMPORTOCAF2_H +#define IMPORT_IMPORTOCAF2_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ImportOCAF.h" +#include "ExportOCAF.h" + + +class TDF_Label; +class TopLoc_Location; + +namespace App { +class Document; +class DocumentObject; +} +namespace Part { +class Feature; +} + +namespace Import { + +struct ShapeHasher { + std::size_t operator()(const TopoDS_Shape &s) const { + return s.HashCode(INT_MAX); + } +}; + +struct LabelHasher { + std::size_t operator()(const TDF_Label &l) const { + return TDF_LabelMapHasher::HashCode(l,INT_MAX); + } +}; + +class ImportExport ImportOCAF2 +{ +public: + ImportOCAF2(Handle(TDocStd_Document) h, App::Document* d, const std::string& name); + virtual ~ImportOCAF2(); + App::DocumentObject* loadShapes(); + void setMerge(bool enable) { merge=enable;}; + void setUseLinkGroup(bool enable) { useLinkGroup=enable; } + void setBaseName(bool enable) { useBaseName=enable; } + void setImportHiddenObject(bool enable) {importHidden=enable;} + void setReduceObjects(bool enable) {reduceObjects=enable;} + void setShowProgress(bool enable) {showProgress=enable;} + void setExpandCompound(bool enable) {expandCompound=enable;} + + enum ImportMode { + SingleDoc = 0, + GroupPerDoc = 1, + GroupPerDir = 2, + ObjectPerDoc = 3, + ObjectPerDir = 4, + ModeMax, + }; + void setMode(int m); + int getMode() const {return mode;} + +private: + struct Info { + std::string baseName; + App::DocumentObject *obj = 0; + App::PropertyPlacement *propPlacement = 0; + App::Color faceColor; + App::Color edgeColor; + bool hasFaceColor = false; + bool hasEdgeColor = false; + int free = true; + }; + + App::DocumentObject *loadShape(App::Document *doc, TDF_Label label, + const TopoDS_Shape &shape, bool baseOnly=false, bool newDoc=true); + App::Document *getDocument(App::Document *doc, TDF_Label label); + bool createAssembly(App::Document *doc, TDF_Label label, + const TopoDS_Shape &shape, Info &info, bool newDoc); + bool createObject(App::Document *doc, TDF_Label label, + const TopoDS_Shape &shape, Info &info, bool newDoc); + bool createGroup(App::Document *doc, Info &info, + const TopoDS_Shape &shape, std::vector &children, + const boost::dynamic_bitset<> &visibilities, bool canReduce=false); + bool getColor(const TopoDS_Shape &shape, Info &info, bool check=false, bool noDefault=false); + void getSHUOColors(TDF_Label label, std::map &colors, bool appendFirst); + void setObjectName(Info &info, TDF_Label label); + std::string getLabelName(TDF_Label label); + App::DocumentObject *expandShape(App::Document *doc, TDF_Label label, const TopoDS_Shape &shape); + + virtual void applyEdgeColors(Part::Feature*, const std::vector&) {} + virtual void applyFaceColors(Part::Feature*, const std::vector&) {} + virtual void applyElementColors(App::DocumentObject*, const std::map&) {} + virtual void applyLinkColor(App::DocumentObject *, int /*index*/, App::Color){} + +private: + class ImportLegacy : public ImportOCAF { + public: + ImportLegacy(ImportOCAF2 &parent) + :ImportOCAF(parent.pDoc, parent.pDocument, parent.default_name),myParent(parent) + {} + + private: + void applyColors(Part::Feature* part, const std::vector& colors) { + myParent.applyFaceColors(part, colors); + } + + ImportOCAF2 &myParent; + }; + friend class ImportLegacy; + + Handle(TDocStd_Document) pDoc; + App::Document* pDocument; + Handle(XCAFDoc_ShapeTool) aShapeTool; + Handle(XCAFDoc_ColorTool) aColorTool; + bool merge; + std::string default_name; + bool useLinkGroup; + bool useBaseName; + bool importHidden; + bool reduceObjects; + bool showProgress; + bool expandCompound; + + int mode; + std::string filePath; + + std::unordered_map myShapes; + std::unordered_map myNames; + std::unordered_map myCollapsedObjects; + + App::Color defaultFaceColor; + App::Color defaultEdgeColor; + + Base::SequencerLauncher *sequencer; +}; + +class ImportExport ExportOCAF2 +{ +public: + typedef std::function( + App::DocumentObject*, const char*)> GetShapeColorsFunc; + ExportOCAF2(Handle(TDocStd_Document) h, GetShapeColorsFunc func=GetShapeColorsFunc()); + + void setExportHiddenObject(bool enable) {exportHidden=enable;} + void setKeepPlacement(bool enable) {keepPlacement=enable;} + void exportObjects(std::vector &objs, const char *name=0); + bool canFallback(std::vector objs); + +private: + TDF_Label exportObject(App::DocumentObject *obj, const char *sub, TDF_Label parent, const char *name=0); + void setupObject(TDF_Label label, App::DocumentObject *obj, + const Part::TopoShape &shape, const std::string &prefix, + const char *name=0, bool force=false); + void setName(TDF_Label label, App::DocumentObject *obj, const char *name=0); + TDF_Label findComponent(const char *subname, TDF_Label label, TDF_LabelSequence &labels); + +private: + Handle(TDocStd_Document) pDoc; + Handle(XCAFDoc_ShapeTool) aShapeTool; + Handle(XCAFDoc_ColorTool) aColorTool; + + std::unordered_map myObjects; + + std::unordered_map, LabelHasher> myNames; + + std::set > mySetups; + + std::vector groupLinks; + + GetShapeColorsFunc getShapeColors; + + App::Color defaultColor; + bool exportHidden; + bool keepPlacement; +}; + +} + +#endif //IMPORT_IMPORTOCAF2_H diff --git a/src/Mod/Import/Gui/AppImportGuiPy.cpp b/src/Mod/Import/Gui/AppImportGuiPy.cpp index 8f9ace29c7bb..f9f2a57abef9 100644 --- a/src/Mod/Import/Gui/AppImportGuiPy.cpp +++ b/src/Mod/Import/Gui/AppImportGuiPy.cpp @@ -82,14 +82,14 @@ #include #include #include +#include #include #include #include #include #include #include -#include -#include +#include #include #include @@ -121,7 +121,11 @@ #include #include #include +#include + +FC_LOG_LEVEL_INIT("Import", true, true) + class OCAFBrowser { public: @@ -286,23 +290,66 @@ void OCAFBrowser::load(const TDF_Label& label, QTreeWidgetItem* item, const QStr } } -class ImportOCAFGui : public Import::ImportOCAF +class ImportOCAFExt : public Import::ImportOCAF2 { public: - ImportOCAFGui(Handle(TDocStd_Document) h, App::Document* d, const std::string& name) - : ImportOCAF(h, d, name) + ImportOCAFExt(Handle(TDocStd_Document) h, App::Document* d, const std::string& name) + : ImportOCAF2(h, d, name) { } private: - void applyColors(Part::Feature* part, const std::vector& colors) - { - Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); - if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { - static_cast(vp)->ShapeColor.setValue(colors.front()); - static_cast(vp)->DiffuseColor.setValues(colors); - } - } + virtual void applyFaceColors(Part::Feature* part, const std::vector& colors) override { + auto vp = dynamic_cast(Gui::Application::Instance->getViewProvider(part)); + if (!vp) return; + if(colors.empty()) { + // vp->MapFaceColor.setValue(true); + // vp->MapLineColor.setValue(true); + // vp->updateColors(0,true); + return; + } + // vp->MapFaceColor.setValue(false); + if(colors.size() == 1) + vp->ShapeColor.setValue(colors.front()); + else + vp->DiffuseColor.setValues(colors); + } + virtual void applyEdgeColors(Part::Feature* part, const std::vector& colors) override { + auto vp = dynamic_cast(Gui::Application::Instance->getViewProvider(part)); + if (!vp) return; + // vp->MapLineColor.setValue(false); + if(colors.size() == 1) + vp->LineColor.setValue(colors.front()); + else + vp->LineColorArray.setValues(colors); + } + virtual void applyLinkColor(App::DocumentObject *obj, int index, App::Color color) override { + auto vp = dynamic_cast(Gui::Application::Instance->getViewProvider(obj)); + if(!vp) + return; + if(index<0) { + vp->OverrideMaterial.setValue(true); + vp->ShapeMaterial.setDiffuseColor(color); + return; + } + if(vp->OverrideMaterialList.getSize()<=index) + vp->OverrideMaterialList.setSize(index+1); + vp->OverrideMaterialList.set1Value(index,true); + App::Material mat(App::Material::DEFAULT); + if(vp->MaterialList.getSize()<=index) + vp->MaterialList.setSize(index+1,mat); + mat.diffuseColor = color; + vp->MaterialList.set1Value(index,mat); + } + virtual void applyElementColors(App::DocumentObject *obj, + const std::map &colors) override + { + auto vp = Gui::Application::Instance->getViewProvider(obj); + if(!vp) + return; + (void)colors; + // vp->setElementColors(colors); + } }; class ExportOCAFGui : public Import::ExportOCAF @@ -329,13 +376,13 @@ class Module : public Py::ExtensionModule public: Module() : Py::ExtensionModule("ImportGui") { - add_varargs_method("open",&Module::open, + add_keyword_method("open",&Module::insert, "open(string) -- Open the file and create a new document." ); - add_varargs_method("insert",&Module::insert, + add_keyword_method("insert",&Module::insert, "insert(string,string) -- Insert the file into the given document." ); - add_varargs_method("export",&Module::exporter, + add_keyword_method("export",&Module::exporter, "export(list,string) -- Export a list of objects into a single file." ); add_varargs_method("ocaf",&Module::ocaf, @@ -347,21 +394,23 @@ class Module : public Py::ExtensionModule virtual ~Module() {} private: - Py::Object open(const Py::Tuple& args) - { - return insert(args); - } - Py::Object insert(const Py::Tuple& args) + Py::Object insert(const Py::Tuple& args, const Py::Dict &kwds) { char* Name; char* DocName=0; - if (!PyArg_ParseTuple(args.ptr(), "et|s","utf-8",&Name,&DocName)) + PyObject *importHidden = Py_None; + PyObject *merge = Py_None; + PyObject *useLinkGroup = Py_None; + int mode = -1; + static char* kwd_list[] = {"name","docName","importHidden","merge","useLinkGroup","mode",0}; + if(!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "et|sOOOi", + kwd_list,"utf-8",&Name,&DocName,&importHidden,&merge,&useLinkGroup,&mode)) throw Py::Exception(); std::string Utf8Name = std::string(Name); PyMem_Free(Name); std::string name8bit = Part::encodeFilename(Utf8Name); - + try { //Base::Console().Log("Insert in Part with %s",Name); Base::FileInfo file(Utf8Name.c_str()); @@ -380,17 +429,29 @@ class Module : public Py::ExtensionModule hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Import/hSTEP"); optionReadShapeCompoundMode = hGrp->GetBool("ReadShapeCompoundMode", optionReadShapeCompoundMode); + ImportOCAFExt ocaf(hDoc, pcDoc, file.fileNamePure()); + FC_TIME_INIT(t); + FC_DURATION_DECL_INIT2(d1,d2); if (file.hasExtension("stp") || file.hasExtension("step")) { + + if(mode<0) + mode = ocaf.getMode(); + if(mode && !pcDoc->isSaved()) { + auto gdoc = Gui::Application::Instance->getDocument(pcDoc); + if(!gdoc->save()) + return Py::Object(); + } + try { STEPCAFControl_Reader aReader; aReader.SetColorMode(true); aReader.SetNameMode(true); aReader.SetLayerMode(true); + aReader.SetSHUOMode(true); if (aReader.ReadFile((const char*)name8bit.c_str()) != IFSelect_RetDone) { throw Py::Exception(PyExc_IOError, "cannot read STEP file"); } - Handle(Message_ProgressIndicator) pi = new Part::ProgressIndicator(100); aReader.Reader().WS()->MapReader()->SetProgress(pi); pi->NewScope(100, "Reading STEP file..."); @@ -445,18 +506,30 @@ class Module : public Py::ExtensionModule throw Py::Exception(Base::BaseExceptionFreeCADError, "no supported file format"); } - ImportOCAFGui ocaf(hDoc, pcDoc, file.fileNamePure()); - // We must recompute the doc before loading shapes as they are going to be - // inserted into the document and computed at the same time so we are going to - // purge the document before recomputing it to clear it and settle it in the proper - // way. This is drastically improving STEP rendering time on complex STEP files. - pcDoc->recompute(); - if (file.hasExtension("stp") || file.hasExtension("step")) - ocaf.setMerge(optionReadShapeCompoundMode); - ocaf.loadShapes(); - pcDoc->purgeTouched(); - pcDoc->recompute(); + FC_DURATION_PLUS(d1,t); + if(merge!=Py_None) + ocaf.setMerge(PyObject_IsTrue(merge)); + if(importHidden!=Py_None) + ocaf.setImportHiddenObject(PyObject_IsTrue(importHidden)); + if(useLinkGroup!=Py_None) + ocaf.setUseLinkGroup(PyObject_IsTrue(useLinkGroup)); + ocaf.setMode(mode); + auto ret = ocaf.loadShapes(); hApp->Close(hDoc); + FC_DURATION_PLUS(d2,t); + FC_DURATION_MSG(d1,"file read"); + FC_DURATION_MSG(d2,"import"); + FC_DURATION_MSG((d1+d2),"total"); + + if(ret) { + App::GetApplication().setActiveDocument(pcDoc); + auto gdoc = Gui::Application::Instance->getDocument(pcDoc); + if(gdoc) { + gdoc->setActiveView(); + Gui::Application::Instance->commandManager().runCommandByName("Std_ViewFitAll"); + } + return Py::asObject(ret->getPyObject()); + } } catch (Standard_Failure& e) { throw Py::Exception(Base::BaseExceptionFreeCADError, e.GetMessageString()); @@ -468,11 +541,23 @@ class Module : public Py::ExtensionModule return Py::None(); } - Py::Object exporter(const Py::Tuple& args) + static std::map getShapeColors(App::DocumentObject *obj, const char *subname) { + auto vp = Gui::Application::Instance->getViewProvider(obj); + if(vp) + return vp->getElementColors(subname); + return std::map(); + } + + Py::Object exporter(const Py::Tuple& args, const Py::Dict &kwds) { PyObject* object; char* Name; - if (!PyArg_ParseTuple(args.ptr(), "Oet",&object,"utf-8",&Name)) + PyObject *exportHidden = Py_None; + PyObject *legacy = Py_None; + PyObject *keepPlacement = Py_None; + static char* kwd_list[] = {"obj", "name", "exportHidden", "legacy", "keepPlacement",0}; + if(!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "Oet|OOO", + kwd_list,&object,"utf-8",&Name,&exportHidden,&legacy,&keepPlacement)) throw Py::Exception(); std::string Utf8Name = std::string(Name); @@ -485,37 +570,52 @@ class Module : public Py::ExtensionModule Handle(TDocStd_Document) hDoc; hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc); - //bool keepExplicitPlacement = list.size() > 1; - bool keepExplicitPlacement = Standard_True; - ExportOCAFGui ocaf(hDoc, keepExplicitPlacement); - - // That stuff is exporting a list of selected objects into FreeCAD Tree - std::vector hierarchical_label; - std::vector hierarchical_loc; - std::vector hierarchical_part; - + std::vector objs; for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { PyObject* item = (*it).ptr(); - if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) { - App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); - ocaf.exportObject(obj, hierarchical_label, hierarchical_loc, hierarchical_part); - } - } - - // Free Shapes must have absolute placement and not explicit - std::vector FreeLabels; - std::vector part_id; - ocaf.getFreeLabels(hierarchical_label, FreeLabels, part_id); - // Got issue with the colors as they are coming from the View Provider they can't be determined into - // the App Code. - std::vector< std::vector > Colors; - ocaf.getPartColors(hierarchical_part, FreeLabels, part_id, Colors); - ocaf.reallocateFreeShape(hierarchical_part, FreeLabels, part_id, Colors); + if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) + objs.push_back(static_cast(item)->getDocumentObjectPtr()); + } + + if(legacy == Py_None) { + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Import"); + legacy = hGrp->GetBool("ExportLegacy",false)?Py_True:Py_False; + } + + Import::ExportOCAF2 ocaf(hDoc, &getShapeColors); + if(!PyObject_IsTrue(legacy) || !ocaf.canFallback(objs)) { + if(exportHidden!=Py_None) + ocaf.setExportHiddenObject(PyObject_IsTrue(exportHidden)); + if(keepPlacement!=Py_None) + ocaf.setKeepPlacement(PyObject_IsTrue(keepPlacement)); + ocaf.exportObjects(objs); + } else { + bool keepExplicitPlacement = objs.size() > 1; + keepExplicitPlacement = Standard_True; + ExportOCAFGui ocaf(hDoc, keepExplicitPlacement); + // That stuff is exporting a list of selected objects into FreeCAD Tree + std::vector hierarchical_label; + std::vector hierarchical_loc; + std::vector hierarchical_part; + for(auto obj : objs) + ocaf.exportObject(obj,hierarchical_label, hierarchical_loc,hierarchical_part); + + // Free Shapes must have absolute placement and not explicit + std::vector FreeLabels; + std::vector part_id; + ocaf.getFreeLabels(hierarchical_label,FreeLabels, part_id); + // Got issue with the colors as they are coming from the View Provider they can't be determined into + // the App Code. + std::vector< std::vector > Colors; + ocaf.getPartColors(hierarchical_part,FreeLabels,part_id,Colors); + ocaf.reallocateFreeShape(hierarchical_part,FreeLabels,part_id,Colors); #if OCC_VERSION_HEX >= 0x070200 // Update is not performed automatically anymore: https://tracker.dev.opencascade.org/view.php?id=28055 - XCAFDoc_DocumentTool::ShapeTool(hDoc->Main())->UpdateAssemblies(); + XCAFDoc_DocumentTool::ShapeTool(hDoc->Main())->UpdateAssemblies(); #endif + } Base::FileInfo file(Utf8Name.c_str()); if (file.hasExtension("stp") || file.hasExtension("step")) { @@ -597,6 +697,7 @@ class Module : public Py::ExtensionModule aReader.SetColorMode(true); aReader.SetNameMode(true); aReader.SetLayerMode(true); + aReader.SetSHUOMode(true); if (aReader.ReadFile((Standard_CString)Name) != IFSelect_RetDone) { throw Py::Exception(PyExc_IOError, "cannot read STEP file"); } diff --git a/src/Mod/Part/Gui/DlgImportExportStep.ui b/src/Mod/Part/Gui/DlgImportExportStep.ui index 22afb2193c6e..bdc1c3bf541b 100644 --- a/src/Mod/Part/Gui/DlgImportExportStep.ui +++ b/src/Mod/Part/Gui/DlgImportExportStep.ui @@ -7,58 +7,75 @@ 0 0 445 - 323 + 637 STEP - - + + - Header + Export - - - - - Company + + + + + Scheme + + + + + AP 203 + + + true + + + + + + + AP 214 + + + + - - - - - + + + + Uncheck this to skip invisible object when exporting, which is useful for CADs that do not support invisibility STEP styling. + - Author + Export invisible objects + + + ExportHiddenObject + + + Mod/Import - - - - - + + - Product + Units for export of STEP - - + + + + Write out curves in parametric space of surface + + - - - - - - - Export - - @@ -91,50 +108,42 @@ - - + + - Units for export of STEP + Use legacy exporter - - - - - - Scheme + + Mod/Import + + + ExportLegacy - - - - - AP 203 - - - true - - - - - - - AP 214 - - - - - - + + + + Check this option to keep the placement information when exporting +a single object. Please note that when import back the STEP file, the +placement will be encoded into the shape geometry, instead of keeping +it inside the Placement property. + - Write out curves in parametric space of surface + Export single object placement + + + ExportKeepPlacement + + + Mod/Import - + Qt::Vertical @@ -147,12 +156,51 @@ - + + + + Header + + + + + + + + + + + + Author + + + + + + + Product + + + + + + + Company + + + + + + + + + + Import - + @@ -172,6 +220,154 @@ + + + + Select this to use App::LinkGroup as group container, or else use App::Part. + + + Use LinkGroup + + + UseLinkGroup + + + Mod/Import + + + + + + + Select this to not import any invisible objects. + + + Import invisible objects + + + ImportHiddenObject + + + Mod/Import + + + + + + + Reduce number of objects using Link array + + + Reduce number of objects + + + ReduceObjects + + + Mod/Import + + + + + + + Expand compound shape with multiple solids + + + Expand compound shape + + + ExpandCompound + + + Mod/Import + + + + + + + Show progress bar when importing + + + Show progress bar when importing + + + ShowProgress + + + Mod/Import + + + + + + + Do not use instance name. Useful for some legacy STEP file with non-meaningful auto generated instance names. + + + Ignore instance names + + + UseBaseName + + + Mod/Import + + + + + + + + + Mode + + + + + + + + 0 + 0 + + + + ImportMode + + + Mod/Import + + + + Single document + + + + + Assembly per document + + + + + Assembly per document in sub-directory + + + + + Object per document + + + + + Object per document in sub-directory + + + + + + @@ -183,12 +379,26 @@ QCheckBox
Gui/PrefWidgets.h
+ + Gui::PrefComboBox + QComboBox +
Gui/PrefWidgets.h
+
comboBoxUnits checkBoxPcurves + checkBoxExportHiddenObj radioButtonAP203 radioButtonAP214 + checkBoxMergeCompound + checkBoxUseLinkGroup + checkBoxImportHiddenObj + checkBoxReduceObjects + checkBoxExpandCompound + checkBoxShowProgress + checkBoxUseBaseName + comboBoxImportMode lineEditCompany lineEditAuthor lineEditProduct diff --git a/src/Mod/Part/Gui/DlgSettingsGeneral.cpp b/src/Mod/Part/Gui/DlgSettingsGeneral.cpp index 66b0bddceed9..783f954c2f77 100644 --- a/src/Mod/Part/Gui/DlgSettingsGeneral.cpp +++ b/src/Mod/Part/Gui/DlgSettingsGeneral.cpp @@ -1,322 +1,342 @@ -/*************************************************************************** - * Copyright (c) 2007 Werner Mayer * - * * - * This file is part of the FreeCAD CAx development system. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Library General Public * - * License as published by the Free Software Foundation; either * - * version 2 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Library General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this library; see the file COPYING.LIB. If not, * - * write to the Free Software Foundation, Inc., 59 Temple Place, * - * Suite 330, Boston, MA 02111-1307, USA * - * * - ***************************************************************************/ - - -#include "PreCompiled.h" -#ifndef _PreComp_ -# include -# include -# include -# include -#endif - -#include -#include - -#include "DlgSettingsGeneral.h" -#include "ui_DlgSettingsGeneral.h" -#include "ui_DlgImportExportIges.h" -#include "ui_DlgImportExportStep.h" - -using namespace PartGui; - -DlgSettingsGeneral::DlgSettingsGeneral(QWidget* parent) - : PreferencePage(parent) -{ - ui = new Ui_DlgSettingsGeneral(); - ui->setupUi(this); -} - -/** - * Destroys the object and frees any allocated resources - */ -DlgSettingsGeneral::~DlgSettingsGeneral() -{ - // no need to delete child widgets, Qt does it all for us - delete ui; -} - -void DlgSettingsGeneral::saveSettings() -{ - ui->checkBooleanCheck->onSave(); - ui->checkBooleanRefine->onSave(); - ui->checkSketchBaseRefine->onSave(); - ui->checkObjectNaming->onSave(); -} - -void DlgSettingsGeneral::loadSettings() -{ - ui->checkBooleanCheck->onRestore(); - ui->checkBooleanRefine->onRestore(); - ui->checkSketchBaseRefine->onRestore(); - ui->checkObjectNaming->onRestore(); -} - -/** - * Sets the strings of the subwidgets using the current language. - */ -void DlgSettingsGeneral::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - ui->retranslateUi(this); - } - else { - QWidget::changeEvent(e); - } -} - -// ---------------------------------------------------------------------------- - -DlgImportExportIges::DlgImportExportIges(QWidget* parent) - : PreferencePage(parent) -{ - ui = new Ui_DlgImportExportIges(); - ui->setupUi(this); - ui->lineEditProduct->setReadOnly(true); - - bg = new QButtonGroup(this); - bg->addButton(ui->radioButtonBRepOff, 0); - bg->addButton(ui->radioButtonBRepOn, 1); - - QRegExp rx; - rx.setPattern(QString::fromLatin1("[\\x00-\\x7F]+")); - QRegExpValidator* companyValidator = new QRegExpValidator(ui->lineEditCompany); - companyValidator->setRegExp(rx); - ui->lineEditCompany->setValidator(companyValidator); - QRegExpValidator* authorValidator = new QRegExpValidator(ui->lineEditAuthor); - authorValidator->setRegExp(rx); - ui->lineEditAuthor->setValidator(authorValidator); -} - -/** - * Destroys the object and frees any allocated resources - */ -DlgImportExportIges::~DlgImportExportIges() -{ - // no need to delete child widgets, Qt does it all for us - delete ui; -} - -void DlgImportExportIges::saveSettings() -{ - int unit = ui->comboBoxUnits->currentIndex(); - Base::Reference hGrp = App::GetApplication().GetUserParameter() - .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part")->GetGroup("IGES"); - hGrp->SetInt("Unit", unit); - switch (unit) { - case 1: - Interface_Static::SetCVal("write.iges.unit","M"); - break; - case 2: - Interface_Static::SetCVal("write.iges.unit","INCH"); - break; - default: - Interface_Static::SetCVal("write.iges.unit","MM"); - break; - } - - hGrp->SetBool("BrepMode", bg->checkedId() == 1); - Interface_Static::SetIVal("write.iges.brep.mode", bg->checkedId()); - - // Import - hGrp->SetBool("SkipBlankEntities", ui->checkSkipBlank->isChecked()); - - // header info - hGrp->SetASCII("Company", ui->lineEditCompany->text().toLatin1()); - hGrp->SetASCII("Author", ui->lineEditAuthor->text().toLatin1()); - //hGrp->SetASCII("Product", ui->lineEditProduct->text().toLatin1()); - - Interface_Static::SetCVal("write.iges.header.company", ui->lineEditCompany->text().toLatin1()); - Interface_Static::SetCVal("write.iges.header.author", ui->lineEditAuthor->text().toLatin1()); - //Interface_Static::SetCVal("write.iges.header.product", ui->lineEditProduct->text().toLatin1()); -} - -void DlgImportExportIges::loadSettings() -{ - Base::Reference hGrp = App::GetApplication().GetUserParameter() - .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part")->GetGroup("IGES"); - int unit = hGrp->GetInt("Unit", 0); - ui->comboBoxUnits->setCurrentIndex(unit); - - int value = Interface_Static::IVal("write.iges.brep.mode"); - bool brep = hGrp->GetBool("BrepMode", value > 0); - if (brep) - ui->radioButtonBRepOn->setChecked(true); - else - ui->radioButtonBRepOff->setChecked(true); - - // Import - ui->checkSkipBlank->setChecked(hGrp->GetBool("SkipBlankEntities", true)); - - // header info - ui->lineEditCompany->setText(QString::fromStdString(hGrp->GetASCII("Company", - Interface_Static::CVal("write.iges.header.company")))); - ui->lineEditAuthor->setText(QString::fromStdString(hGrp->GetASCII("Author", - Interface_Static::CVal("write.iges.header.author")))); - //ui->lineEditProduct->setText(QString::fromStdString(hGrp->GetASCII("Product"))); - ui->lineEditProduct->setText(QString::fromLatin1( - Interface_Static::CVal("write.iges.header.product"))); -} - -/** - * Sets the strings of the subwidgets using the current language. - */ -void DlgImportExportIges::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - ui->retranslateUi(this); - } - else { - QWidget::changeEvent(e); - } -} - -// ---------------------------------------------------------------------------- - -DlgImportExportStep::DlgImportExportStep(QWidget* parent) - : PreferencePage(parent) -{ - ui = new Ui_DlgImportExportStep(); - ui->setupUi(this); - ui->lineEditProduct->setReadOnly(true); - ui->radioButtonAP203->setToolTip(tr("Configuration controlled 3D designs of mechanical parts and assemblies")); - ui->radioButtonAP214->setToolTip(tr("Core data for automotive mechanical design processes")); - - // https://tracker.dev.opencascade.org/view.php?id=25654 - ui->checkBoxPcurves->setToolTip(tr("This parameter indicates whether parametric curves (curves in parametric space of surface)\n" - "should be written into the STEP file. This parameter can be set to off in order to minimize\n" - "the size of the resulting STEP file.")); - - QRegExp rx; - rx.setPattern(QString::fromLatin1("[\\x00-\\x7F]+")); - QRegExpValidator* companyValidator = new QRegExpValidator(ui->lineEditCompany); - companyValidator->setRegExp(rx); - ui->lineEditCompany->setValidator(companyValidator); - QRegExpValidator* authorValidator = new QRegExpValidator(ui->lineEditAuthor); - authorValidator->setRegExp(rx); - ui->lineEditAuthor->setValidator(authorValidator); -} - -/** - * Destroys the object and frees any allocated resources - */ -DlgImportExportStep::~DlgImportExportStep() -{ - // no need to delete child widgets, Qt does it all for us - delete ui; -} - -void DlgImportExportStep::saveSettings() -{ - int unit = ui->comboBoxUnits->currentIndex(); - Base::Reference hPartGrp = App::GetApplication().GetUserParameter() - .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part"); - - // General - Base::Reference hGenGrp = hPartGrp->GetGroup("General"); - int writesurfacecurve = ui->checkBoxPcurves->isChecked() ? 1 : 0; - hGenGrp->SetInt("WriteSurfaceCurveMode", writesurfacecurve); - Interface_Static::SetIVal("write.surfacecurve.mode", writesurfacecurve); - - // STEP - Base::Reference hStepGrp = hPartGrp->GetGroup("STEP"); - hStepGrp->SetInt("Unit", unit); - switch (unit) { - case 1: - Interface_Static::SetCVal("write.step.unit","M"); - break; - case 2: - Interface_Static::SetCVal("write.step.unit","INCH"); - break; - default: - Interface_Static::SetCVal("write.step.unit","MM"); - break; - } - - // scheme - if (ui->radioButtonAP203->isChecked()) { - Interface_Static::SetCVal("write.step.schema","AP203"); - hStepGrp->SetASCII("Scheme", "AP203"); - } - else { - // possible values: AP214CD (1996), AP214DIS (1998), AP214IS (2002) - Interface_Static::SetCVal("write.step.schema","AP214IS"); - hStepGrp->SetASCII("Scheme", "AP214IS"); - } - - // header info - hStepGrp->SetASCII("Company", ui->lineEditCompany->text().toLatin1()); - hStepGrp->SetASCII("Author", ui->lineEditAuthor->text().toLatin1()); - //hStepGrp->SetASCII("Product", ui->lineEditProduct->text().toLatin1()); - - // (h)STEP of Import module - ui->checkBoxMergeCompound->onSave(); -} - -void DlgImportExportStep::loadSettings() -{ - Base::Reference hPartGrp = App::GetApplication().GetUserParameter() - .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part"); - - // General - Base::Reference hGenGrp = hPartGrp->GetGroup("General"); - int writesurfacecurve = Interface_Static::IVal("write.surfacecurve.mode"); - writesurfacecurve = hGenGrp->GetInt("WriteSurfaceCurveMode", writesurfacecurve); - ui->checkBoxPcurves->setChecked(writesurfacecurve == 0 ? false : true); - - // STEP - Base::Reference hStepGrp = hPartGrp->GetGroup("STEP"); - int unit = hStepGrp->GetInt("Unit", 0); - ui->comboBoxUnits->setCurrentIndex(unit); - - // scheme - QString ap = QString::fromStdString(hStepGrp->GetASCII("Scheme", - Interface_Static::CVal("write.step.schema"))); - if (ap.startsWith(QLatin1String("AP203"))) - ui->radioButtonAP203->setChecked(true); - else - ui->radioButtonAP214->setChecked(true); - - // header info - ui->lineEditCompany->setText(QString::fromStdString(hStepGrp->GetASCII("Company"))); - ui->lineEditAuthor->setText(QString::fromStdString(hStepGrp->GetASCII("Author"))); - ui->lineEditProduct->setText(QString::fromLatin1( - Interface_Static::CVal("write.step.product.name"))); - - // (h)STEP of Import module - ui->checkBoxMergeCompound->onRestore(); -} - -/** - * Sets the strings of the subwidgets using the current language. - */ -void DlgImportExportStep::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - ui->retranslateUi(this); - } - else { - QWidget::changeEvent(e); - } -} - -#include "moc_DlgSettingsGeneral.cpp" +/*************************************************************************** + * Copyright (c) 2007 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +#endif + +#include +#include + +#include "DlgSettingsGeneral.h" +#include "ui_DlgSettingsGeneral.h" +#include "ui_DlgImportExportIges.h" +#include "ui_DlgImportExportStep.h" + +using namespace PartGui; + +DlgSettingsGeneral::DlgSettingsGeneral(QWidget* parent) + : PreferencePage(parent) +{ + ui = new Ui_DlgSettingsGeneral(); + ui->setupUi(this); +} + +/** + * Destroys the object and frees any allocated resources + */ +DlgSettingsGeneral::~DlgSettingsGeneral() +{ + // no need to delete child widgets, Qt does it all for us + delete ui; +} + +void DlgSettingsGeneral::saveSettings() +{ + ui->checkBooleanCheck->onSave(); + ui->checkBooleanRefine->onSave(); + ui->checkSketchBaseRefine->onSave(); + ui->checkObjectNaming->onSave(); +} + +void DlgSettingsGeneral::loadSettings() +{ + ui->checkBooleanCheck->onRestore(); + ui->checkBooleanRefine->onRestore(); + ui->checkSketchBaseRefine->onRestore(); + ui->checkObjectNaming->onRestore(); +} + +/** + * Sets the strings of the subwidgets using the current language. + */ +void DlgSettingsGeneral::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + else { + QWidget::changeEvent(e); + } +} + +// ---------------------------------------------------------------------------- + +DlgImportExportIges::DlgImportExportIges(QWidget* parent) + : PreferencePage(parent) +{ + ui = new Ui_DlgImportExportIges(); + ui->setupUi(this); + ui->lineEditProduct->setReadOnly(true); + + bg = new QButtonGroup(this); + bg->addButton(ui->radioButtonBRepOff, 0); + bg->addButton(ui->radioButtonBRepOn, 1); + + QRegExp rx; + rx.setPattern(QString::fromLatin1("[\\x00-\\x7F]+")); + QRegExpValidator* companyValidator = new QRegExpValidator(ui->lineEditCompany); + companyValidator->setRegExp(rx); + ui->lineEditCompany->setValidator(companyValidator); + QRegExpValidator* authorValidator = new QRegExpValidator(ui->lineEditAuthor); + authorValidator->setRegExp(rx); + ui->lineEditAuthor->setValidator(authorValidator); +} + +/** + * Destroys the object and frees any allocated resources + */ +DlgImportExportIges::~DlgImportExportIges() +{ + // no need to delete child widgets, Qt does it all for us + delete ui; +} + +void DlgImportExportIges::saveSettings() +{ + int unit = ui->comboBoxUnits->currentIndex(); + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part")->GetGroup("IGES"); + hGrp->SetInt("Unit", unit); + switch (unit) { + case 1: + Interface_Static::SetCVal("write.iges.unit","M"); + break; + case 2: + Interface_Static::SetCVal("write.iges.unit","INCH"); + break; + default: + Interface_Static::SetCVal("write.iges.unit","MM"); + break; + } + + hGrp->SetBool("BrepMode", bg->checkedId() == 1); + Interface_Static::SetIVal("write.iges.brep.mode", bg->checkedId()); + + // Import + hGrp->SetBool("SkipBlankEntities", ui->checkSkipBlank->isChecked()); + + // header info + hGrp->SetASCII("Company", ui->lineEditCompany->text().toLatin1()); + hGrp->SetASCII("Author", ui->lineEditAuthor->text().toLatin1()); + //hGrp->SetASCII("Product", ui->lineEditProduct->text().toLatin1()); + + Interface_Static::SetCVal("write.iges.header.company", ui->lineEditCompany->text().toLatin1()); + Interface_Static::SetCVal("write.iges.header.author", ui->lineEditAuthor->text().toLatin1()); + //Interface_Static::SetCVal("write.iges.header.product", ui->lineEditProduct->text().toLatin1()); +} + +void DlgImportExportIges::loadSettings() +{ + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part")->GetGroup("IGES"); + int unit = hGrp->GetInt("Unit", 0); + ui->comboBoxUnits->setCurrentIndex(unit); + + int value = Interface_Static::IVal("write.iges.brep.mode"); + bool brep = hGrp->GetBool("BrepMode", value > 0); + if (brep) + ui->radioButtonBRepOn->setChecked(true); + else + ui->radioButtonBRepOff->setChecked(true); + + // Import + ui->checkSkipBlank->setChecked(hGrp->GetBool("SkipBlankEntities", true)); + + // header info + ui->lineEditCompany->setText(QString::fromStdString(hGrp->GetASCII("Company", + Interface_Static::CVal("write.iges.header.company")))); + ui->lineEditAuthor->setText(QString::fromStdString(hGrp->GetASCII("Author", + Interface_Static::CVal("write.iges.header.author")))); + //ui->lineEditProduct->setText(QString::fromStdString(hGrp->GetASCII("Product"))); + ui->lineEditProduct->setText(QString::fromLatin1( + Interface_Static::CVal("write.iges.header.product"))); +} + +/** + * Sets the strings of the subwidgets using the current language. + */ +void DlgImportExportIges::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + else { + QWidget::changeEvent(e); + } +} + +// ---------------------------------------------------------------------------- + +DlgImportExportStep::DlgImportExportStep(QWidget* parent) + : PreferencePage(parent) +{ + ui = new Ui_DlgImportExportStep(); + ui->setupUi(this); + ui->lineEditProduct->setReadOnly(true); + ui->radioButtonAP203->setToolTip(tr("Configuration controlled 3D designs of mechanical parts and assemblies")); + ui->radioButtonAP214->setToolTip(tr("Core data for automotive mechanical design processes")); + + // https://tracker.dev.opencascade.org/view.php?id=25654 + ui->checkBoxPcurves->setToolTip(tr("This parameter indicates whether parametric curves (curves in parametric space of surface)\n" + "should be written into the STEP file. This parameter can be set to off in order to minimize\n" + "the size of the resulting STEP file.")); + + QRegExp rx; + rx.setPattern(QString::fromLatin1("[\\x00-\\x7F]+")); + QRegExpValidator* companyValidator = new QRegExpValidator(ui->lineEditCompany); + companyValidator->setRegExp(rx); + ui->lineEditCompany->setValidator(companyValidator); + QRegExpValidator* authorValidator = new QRegExpValidator(ui->lineEditAuthor); + authorValidator->setRegExp(rx); + ui->lineEditAuthor->setValidator(authorValidator); +} + +/** + * Destroys the object and frees any allocated resources + */ +DlgImportExportStep::~DlgImportExportStep() +{ + // no need to delete child widgets, Qt does it all for us + delete ui; +} + +void DlgImportExportStep::saveSettings() +{ + int unit = ui->comboBoxUnits->currentIndex(); + Base::Reference hPartGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part"); + + // General + Base::Reference hGenGrp = hPartGrp->GetGroup("General"); + int writesurfacecurve = ui->checkBoxPcurves->isChecked() ? 1 : 0; + hGenGrp->SetInt("WriteSurfaceCurveMode", writesurfacecurve); + Interface_Static::SetIVal("write.surfacecurve.mode", writesurfacecurve); + + // STEP + Base::Reference hStepGrp = hPartGrp->GetGroup("STEP"); + hStepGrp->SetInt("Unit", unit); + switch (unit) { + case 1: + Interface_Static::SetCVal("write.step.unit","M"); + break; + case 2: + Interface_Static::SetCVal("write.step.unit","INCH"); + break; + default: + Interface_Static::SetCVal("write.step.unit","MM"); + break; + } + + // scheme + if (ui->radioButtonAP203->isChecked()) { + Interface_Static::SetCVal("write.step.schema","AP203"); + hStepGrp->SetASCII("Scheme", "AP203"); + } + else { + // possible values: AP214CD (1996), AP214DIS (1998), AP214IS (2002) + Interface_Static::SetCVal("write.step.schema","AP214IS"); + hStepGrp->SetASCII("Scheme", "AP214IS"); + } + + // header info + hStepGrp->SetASCII("Company", ui->lineEditCompany->text().toLatin1()); + hStepGrp->SetASCII("Author", ui->lineEditAuthor->text().toLatin1()); + //hStepGrp->SetASCII("Product", ui->lineEditProduct->text().toLatin1()); + + // (h)STEP of Import module + ui->checkBoxMergeCompound->onSave(); + ui->checkBoxExportHiddenObj->onSave(); + ui->checkBoxExportLegacy->onSave(); + ui->checkBoxKeepPlacement->onSave(); + ui->checkBoxImportHiddenObj->onSave(); + ui->checkBoxUseLinkGroup->onSave(); + ui->checkBoxUseBaseName->onSave(); + ui->checkBoxReduceObjects->onSave(); + ui->checkBoxExpandCompound->onSave(); + ui->checkBoxShowProgress->onSave(); + ui->comboBoxImportMode->onSave(); +} + +void DlgImportExportStep::loadSettings() +{ + Base::Reference hPartGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part"); + + // General + Base::Reference hGenGrp = hPartGrp->GetGroup("General"); + int writesurfacecurve = Interface_Static::IVal("write.surfacecurve.mode"); + writesurfacecurve = hGenGrp->GetInt("WriteSurfaceCurveMode", writesurfacecurve); + ui->checkBoxPcurves->setChecked(writesurfacecurve == 0 ? false : true); + + // STEP + Base::Reference hStepGrp = hPartGrp->GetGroup("STEP"); + int unit = hStepGrp->GetInt("Unit", 0); + ui->comboBoxUnits->setCurrentIndex(unit); + + // scheme + QString ap = QString::fromStdString(hStepGrp->GetASCII("Scheme", + Interface_Static::CVal("write.step.schema"))); + if (ap.startsWith(QLatin1String("AP203"))) + ui->radioButtonAP203->setChecked(true); + else + ui->radioButtonAP214->setChecked(true); + + // header info + ui->lineEditCompany->setText(QString::fromStdString(hStepGrp->GetASCII("Company"))); + ui->lineEditAuthor->setText(QString::fromStdString(hStepGrp->GetASCII("Author"))); + ui->lineEditProduct->setText(QString::fromLatin1( + Interface_Static::CVal("write.step.product.name"))); + + // (h)STEP of Import module + ui->checkBoxMergeCompound->onRestore(); + ui->checkBoxExportHiddenObj->onRestore(); + ui->checkBoxExportLegacy->onRestore(); + ui->checkBoxKeepPlacement->onRestore(); + ui->checkBoxImportHiddenObj->onRestore(); + ui->checkBoxUseLinkGroup->onRestore(); + ui->checkBoxUseBaseName->onRestore(); + ui->checkBoxReduceObjects->onRestore(); + ui->checkBoxExpandCompound->onRestore(); + ui->checkBoxShowProgress->onRestore(); + ui->comboBoxImportMode->onRestore(); +} + +/** + * Sets the strings of the subwidgets using the current language. + */ +void DlgImportExportStep::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + else { + QWidget::changeEvent(e); + } +} + +#include "moc_DlgSettingsGeneral.cpp"