From 95efad737b29282b4c85a3927e2e6b3fb15aea6f Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 28 Sep 2018 14:58:49 +0200 Subject: [PATCH] fixes 0003491: Import.export not preserving placement of Part Features in STP file export --- src/Mod/Import/App/AppImportPy.cpp | 46 +++++++++--- src/Mod/Import/App/ImportOCAF.cpp | 78 +++++++++++++++++-- src/Mod/Import/App/ImportOCAF.h | 35 ++++++++- src/Mod/Import/Gui/AppImportGuiPy.cpp | 103 ++++++++------------------ 4 files changed, 169 insertions(+), 93 deletions(-) diff --git a/src/Mod/Import/App/AppImportPy.cpp b/src/Mod/Import/App/AppImportPy.cpp index cc8ce86f6a..060907dd8a 100644 --- a/src/Mod/Import/App/AppImportPy.cpp +++ b/src/Mod/Import/App/AppImportPy.cpp @@ -252,7 +252,10 @@ private: bool keepExplicitPlacement = list.size() > 1; keepExplicitPlacement = Standard_True; - Import::ExportOCAF ocaf(hDoc, keepExplicitPlacement); + Import::ExportOCAFCmd ocaf(hDoc, keepExplicitPlacement); + + std::map > partColors; + std::vector partObjects; for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { PyObject* item = (*it).ptr(); @@ -260,11 +263,7 @@ private: App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { Part::Feature* part = static_cast(obj); - std::vector colors; - std::vector hierarchical_label; - std::vector hierarchical_loc; - std::vector hierarchical_part; - ocaf.saveShape(part, colors, hierarchical_label, hierarchical_loc, hierarchical_part); + partObjects.push_back(part); } else { Base::Console().Message("'%s' is not a shape, export will be ignored.\n", obj->Label.getValue()); @@ -280,10 +279,9 @@ private: Part::Feature* part = static_cast(obj); App::PropertyColorList colors; colors.setPyObject(item1.ptr()); - std::vector hierarchical_label; - std::vector hierarchical_loc; - std::vector hierarchical_part; - ocaf.saveShape(part, colors.getValues(), hierarchical_label, hierarchical_loc, hierarchical_part); + + 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()); @@ -292,10 +290,38 @@ private: } } + 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 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(); +#endif + Base::FileInfo file(Utf8Name.c_str()); if (file.hasExtension("stp") || file.hasExtension("step")) { //Interface_Static::SetCVal("write.step.schema", "AP214IS"); STEPCAFControl_Writer writer; + Interface_Static::SetIVal("write.step.assembly",1); + // writer.SetColorMode(Standard_False); writer.Transfer(hDoc, STEPControl_AsIs); // edit STEP header diff --git a/src/Mod/Import/App/ImportOCAF.cpp b/src/Mod/Import/App/ImportOCAF.cpp index 0cc39ccbf5..839f6c878c 100644 --- a/src/Mod/Import/App/ImportOCAF.cpp +++ b/src/Mod/Import/App/ImportOCAF.cpp @@ -507,9 +507,52 @@ ExportOCAF::ExportOCAF(Handle(TDocStd_Document) h, bool explicitPlacement) } } +ExportOCAF::~ExportOCAF() +{ +} + +int ExportOCAF::exportObject(App::DocumentObject* obj, + std::vector & hierarchical_label, + std::vector & hierarchical_loc, + std::vector & hierarchical_part) +{ + std::vector local_label; + int root_id; + int return_label = -1; + + if (obj->getTypeId().isDerivedFrom(App::Part::getClassTypeId())) { + App::Part* part = static_cast(obj); + // I shall recusrively select the elements and call back + std::vector entries = part->Group.getValues(); + std::vector::iterator it; + + for ( it = entries.begin(); it != entries.end(); it++ ) { + int new_label=0; + new_label = exportObject((*it), hierarchical_label, hierarchical_loc, hierarchical_part); + local_label.push_back(new_label); + } + + createNode(part,root_id, hierarchical_label, hierarchical_loc, hierarchical_part); + std::vector::iterator label_it; + for (label_it = local_label.begin(); label_it != local_label.end(); ++label_it) { + pushNode(root_id,(*label_it), hierarchical_label,hierarchical_loc); + } + + return_label = root_id; + } + + if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* part = static_cast(obj); + std::vector colors; + findColors(part, colors); + + return_label = saveShape(part, colors, hierarchical_label, hierarchical_loc, hierarchical_part); + } + + return return_label; +} // This function creates an Assembly node in an XCAF document with its relative placement information - void ExportOCAF::createNode(App::Part* part, int& root_id, std::vector & hierarchical_label, std::vector & hierarchical_loc, @@ -657,6 +700,21 @@ void ExportOCAF::getFreeLabels(std::vector & hierarchical_label, } } +void ExportOCAF::getPartColors(std::vector hierarchical_part, + std::vector FreeLabels, + std::vector part_id, + std::vector < std::vector >& Colors) const +{ + // I am seeking for the colors of each parts + std::size_t n = FreeLabels.size(); + for (std::size_t i = 0; i < n; i++) { + std::vector colors; + Part::Feature * part = static_cast(hierarchical_part.at(part_id.at(i))); + findColors(part, colors); + Colors.push_back(colors); + } +} + void ExportOCAF::reallocateFreeShape(std::vector hierarchical_part, std::vector FreeLabels, std::vector part_id, @@ -720,11 +778,7 @@ void ExportOCAF::reallocateFreeShape(std::vector hierarch } } - - - // This function is moving a "standard" node into an Assembly node within an XCAF doc - void ExportOCAF::pushNode(int root_id, int node_id, std::vector & hierarchical_label,std::vector & hierarchical_loc) { TDF_Label root; @@ -737,6 +791,20 @@ void ExportOCAF::pushNode(int root_id, int node_id, std::vector & hie // ---------------------------------------------------------------------------- +ExportOCAFCmd::ExportOCAFCmd(Handle(TDocStd_Document) h, bool explicitPlacement) + : ExportOCAF(h, explicitPlacement) +{ +} + +void ExportOCAFCmd::findColors(Part::Feature* part, std::vector& colors) const +{ + std::map >::const_iterator it = partColors.find(part); + if (it != partColors.end()) + colors = it->second; +} + +// ---------------------------------------------------------------------------- + ImportXCAF::ImportXCAF(Handle(TDocStd_Document) h, App::Document* d, const std::string& name) : hdoc(h), doc(d), default_name(name) { diff --git a/src/Mod/Import/App/ImportOCAF.h b/src/Mod/Import/App/ImportOCAF.h index 598872b687..abda172c6f 100644 --- a/src/Mod/Import/App/ImportOCAF.h +++ b/src/Mod/Import/App/ImportOCAF.h @@ -95,15 +95,20 @@ private: class ImportExport ExportOCAF { public: - void createNode(App::Part* part, int& root_it, - std::vector & hierarchical_label, - std::vector & hierarchical_loc, - std::vector & hierarchical_part); ExportOCAF(Handle(TDocStd_Document) h, bool explicitPlacement); + virtual ~ExportOCAF(); + int exportObject(App::DocumentObject* obj, + std::vector & hierarchical_label, + std::vector & hierarchical_loc, + std::vector & hierarchical_part); int saveShape(Part::Feature* part, const std::vector&, std::vector & hierarchical_label, std::vector & hierarchical_loc, std::vector & hierarchical_part); + void getPartColors(std::vector hierarchical_part, + std::vector FreeLabels, + std::vector part_id, + std::vector < std::vector >& Colors) const; void reallocateFreeShape(std::vector hierarchical_part, std::vector FreeLabels, std::vector part_id, @@ -111,9 +116,16 @@ public: void getFreeLabels(std::vector & hierarchical_label, std::vector & labels, std::vector & label_part_id); + void createNode(App::Part* part, int& root_it, + std::vector & hierarchical_label, + std::vector & hierarchical_loc, + std::vector & hierarchical_part); void pushNode(int root, int node, std::vector & hierarchical_label, std::vector & hierarchical_loc); +private: + virtual void findColors(Part::Feature*, std::vector&) const {} + private: Handle(TDocStd_Document) pDoc; Handle(XCAFDoc_ShapeTool) aShapeTool; @@ -122,6 +134,21 @@ private: bool keepExplicitPlacement; }; +class ImportExport ExportOCAFCmd : public ExportOCAF +{ +public: + ExportOCAFCmd(Handle(TDocStd_Document) h, bool explicitPlacement); + void setPartColorsMap(const std::map >& colors) { + partColors = colors; + } + +private: + virtual void findColors(Part::Feature*, std::vector&) const; + +private: + std::map > partColors; +}; + class ImportXCAF { diff --git a/src/Mod/Import/Gui/AppImportGuiPy.cpp b/src/Mod/Import/Gui/AppImportGuiPy.cpp index aa7906d554..8ae9b93463 100644 --- a/src/Mod/Import/Gui/AppImportGuiPy.cpp +++ b/src/Mod/Import/Gui/AppImportGuiPy.cpp @@ -271,10 +271,10 @@ void OCAFBrowser::load(const TDF_Label& label, QTreeWidgetItem* item, const QStr } } -class ImportOCAFExt : public Import::ImportOCAF +class ImportOCAFGui : public Import::ImportOCAF { public: - ImportOCAFExt(Handle(TDocStd_Document) h, App::Document* d, const std::string& name) + ImportOCAFGui(Handle(TDocStd_Document) h, App::Document* d, const std::string& name) : ImportOCAF(h, d, name) { } @@ -290,6 +290,24 @@ private: } }; +class ExportOCAFGui : public Import::ExportOCAF +{ +public: + ExportOCAFGui(Handle(TDocStd_Document) h, bool explicitPlacement) + : ExportOCAF(h, explicitPlacement) + { + } + virtual void findColors(Part::Feature* part, std::vector& colors) const + { + Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); + if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { + colors = static_cast(vp)->DiffuseColor.getValues(); + if (colors.empty()) + colors.push_back(static_cast(vp)->ShapeColor.getValue()); + } + } +}; + namespace ImportGui { class Module : public Py::ExtensionModule { @@ -412,7 +430,7 @@ private: throw Py::Exception(Base::BaseExceptionFreeCADError, "no supported file format"); } - ImportOCAFExt ocaf(hDoc, pcDoc, file.fileNamePure()); + 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 @@ -434,70 +452,6 @@ private: return Py::None(); } - int export_app_object(App::DocumentObject* obj, Import::ExportOCAF ocaf, - std::vector & hierarchical_label, - std::vector & hierarchical_loc, - std::vector & hierarchical_part) - { - std::vector local_label; - int root_id; - int return_label = -1; - - - if (obj->getTypeId().isDerivedFrom(App::Part::getClassTypeId())) { - App::Part* part = static_cast(obj); - // I shall recusrively select the elements and call back - std::vector entries = part->Group.getValues(); - std::vector::iterator it; - - for ( it = entries.begin(); it != entries.end(); it++ ) { - int new_label=0; - new_label=export_app_object((*it),ocaf,hierarchical_label,hierarchical_loc, hierarchical_part); - local_label.push_back(new_label); - } - - ocaf.createNode(part,root_id,hierarchical_label,hierarchical_loc, hierarchical_part); - std::vector::iterator label_it; - for (label_it = local_label.begin(); label_it != local_label.end(); ++label_it) { - ocaf.pushNode(root_id,(*label_it), hierarchical_label,hierarchical_loc); - } - - return_label=root_id; - } - - if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* part = static_cast(obj); - std::vector colors; - Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); - if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { - colors = static_cast(vp)->DiffuseColor.getValues(); - if (colors.empty()) - colors.push_back(static_cast(vp)->ShapeColor.getValue()); - } - - return_label=ocaf.saveShape(part, colors, hierarchical_label, hierarchical_loc, hierarchical_part); - } - - return(return_label); - } - - void get_parts_colors(std::vector hierarchical_part, std::vector FreeLabels, - std::vector part_id, std::vector< std::vector >& Colors) - { - // I am seeking for the colors of each parts - int n = FreeLabels.size(); - for (int i = 0; i < n; i++) { - std::vector colors; - Part::Feature * part = static_cast(hierarchical_part.at(part_id.at(i))); - Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); - if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { - colors = static_cast(vp)->DiffuseColor.getValues(); - if (colors.empty()) - colors.push_back(static_cast(vp)->ShapeColor.getValue()); - Colors.push_back(colors); - } - } - } Py::Object exporter(const Py::Tuple& args) { @@ -518,7 +472,7 @@ private: bool keepExplicitPlacement = list.size() > 1; keepExplicitPlacement = Standard_True; - Import::ExportOCAF ocaf(hDoc, keepExplicitPlacement); + ExportOCAFGui ocaf(hDoc, keepExplicitPlacement); // That stuff is exporting a list of selected objects into FreeCAD Tree std::vector hierarchical_label; @@ -529,19 +483,19 @@ private: PyObject* item = (*it).ptr(); if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) { App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); - export_app_object(obj,ocaf, hierarchical_label, hierarchical_loc,hierarchical_part); + 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); + 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; - get_parts_colors(hierarchical_part,FreeLabels,part_id,Colors); - ocaf.reallocateFreeShape(hierarchical_part,FreeLabels,part_id,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 @@ -571,12 +525,12 @@ private: Base::Reference hGrp = App::GetApplication().GetUserParameter() .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part")->GetGroup("STEP"); - makeHeader.SetName(new TCollection_HAsciiString((Standard_CString)(Utf8Name.c_str()))); + makeHeader.SetName(new TCollection_HAsciiString((Standard_CString)Utf8Name.c_str())); makeHeader.SetAuthorValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Author", "Author").c_str())); makeHeader.SetOrganizationValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Company").c_str())); makeHeader.SetOriginatingSystem(new TCollection_HAsciiString(App::GetApplication().getExecutableName())); makeHeader.SetDescriptionValue(1, new TCollection_HAsciiString("FreeCAD Model")); - IFSelect_ReturnStatus ret = writer.Write((const char*)name8bit.c_str()); + IFSelect_ReturnStatus ret = writer.Write(name8bit.c_str()); if (ret == IFSelect_RetError || ret == IFSelect_RetFail || ret == IFSelect_RetStop) { PyErr_Format(PyExc_IOError, "Cannot open file '%s'", Utf8Name.c_str()); throw Py::Exception(); @@ -606,6 +560,7 @@ private: catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); } + return Py::None(); } Py::Object ocaf(const Py::Tuple& args)