From fd42e7645d24214c081c9839d4a5f0816b1c76d4 Mon Sep 17 00:00:00 2001 From: kgv Date: Wed, 11 Aug 2021 16:11:45 +0300 Subject: [PATCH] 0032527: Data Exchange, RWGltf_CafWriter - make name format configurable Added properties RWGltf_CafWriter::NodeNameFormat() and ::MeshNameFormat(). --- src/RWGltf/RWGltf_CafWriter.cxx | 47 ++++++------ src/RWGltf/RWGltf_CafWriter.hxx | 23 ++++++ src/RWMesh/FILES | 3 + src/RWMesh/RWMesh.cxx | 112 ++++++++++++++++++++++++++++ src/RWMesh/RWMesh.hxx | 38 ++++++++++ src/RWMesh/RWMesh_NameFormat.hxx | 30 ++++++++ src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx | 90 +++++++++++++++++++++- 7 files changed, 320 insertions(+), 23 deletions(-) create mode 100644 src/RWMesh/RWMesh.cxx create mode 100644 src/RWMesh/RWMesh.hxx create mode 100644 src/RWMesh/RWMesh_NameFormat.hxx diff --git a/src/RWGltf/RWGltf_CafWriter.cxx b/src/RWGltf/RWGltf_CafWriter.cxx index 3888e725f3..f06f8034af 100644 --- a/src/RWGltf/RWGltf_CafWriter.cxx +++ b/src/RWGltf/RWGltf_CafWriter.cxx @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -79,19 +80,6 @@ namespace { theStream.write ((const char* )theTri.GetData(), sizeof(theTri)); } - -#ifdef HAVE_RAPIDJSON - //! Read name attribute. - static TCollection_AsciiString readNameAttribute (const TDF_Label& theRefLabel) - { - Handle(TDataStd_Name) aNodeName; - if (!theRefLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName)) - { - return TCollection_AsciiString(); - } - return TCollection_AsciiString (aNodeName->Get()); - } -#endif } //================================================================ @@ -102,6 +90,8 @@ RWGltf_CafWriter::RWGltf_CafWriter (const TCollection_AsciiString& theFile, Standard_Boolean theIsBinary) : myFile (theFile), myTrsfFormat (RWGltf_WriterTrsfFormat_Compact), + myNodeNameFormat(RWMesh_NameFormat_InstanceOrProduct), + myMeshNameFormat(RWMesh_NameFormat_Product), myIsBinary (theIsBinary), myIsForcedUVExport (false), myToEmbedTexturesInGlb (true), @@ -127,6 +117,17 @@ RWGltf_CafWriter::~RWGltf_CafWriter() myWriter.reset(); } +//================================================================ +// Function : formatName +// Purpose : +//================================================================ +TCollection_AsciiString RWGltf_CafWriter::formatName (RWMesh_NameFormat theFormat, + const TDF_Label& theLabel, + const TDF_Label& theRefLabel) const +{ + return RWMesh::FormatName (theFormat, theLabel, theRefLabel); +} + //================================================================ // Function : toSkipFaceMesh // Purpose : @@ -660,7 +661,7 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument, else { // glTF disallows empty meshes / primitive arrays - const TCollection_AsciiString aNodeName = readNameAttribute (aDocNode.RefLabel); + const TCollection_AsciiString aNodeName = formatName (RWMesh_NameFormat_ProductOrInstance, aDocNode.Label, aDocNode.RefLabel); Message::SendWarning (TCollection_AsciiString("RWGltf_CafWriter skipped node '") + aNodeName + "' without triangulation data"); } } @@ -1294,7 +1295,7 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter (theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next()) { const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); - const TCollection_AsciiString aNodeName = readNameAttribute (aDocNode.RefLabel); + const TCollection_AsciiString aNodeName = formatName (myMeshNameFormat, aDocNode.Label, aDocNode.RefLabel); bool toStartPrims = true; Standard_Integer aNbFacesInNode = 0; @@ -1309,8 +1310,11 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM { toStartPrims = false; myWriter->StartObject(); - myWriter->Key ("name"); - myWriter->String (aNodeName.ToCString()); + if (!aNodeName.IsEmpty()) + { + myWriter->Key ("name"); + myWriter->String (aNodeName.ToCString()); + } myWriter->Key ("primitives"); myWriter->StartArray(); } @@ -1520,13 +1524,12 @@ void RWGltf_CafWriter::writeNodes (const Handle(TDocStd_Document)& theDocument, } } { - TCollection_AsciiString aNodeName = readNameAttribute (aDocNode.Label); - if (aNodeName.IsEmpty()) + const TCollection_AsciiString aNodeName = formatName (myNodeNameFormat, aDocNode.Label, aDocNode.RefLabel); + if (!aNodeName.IsEmpty()) { - aNodeName = readNameAttribute (aDocNode.RefLabel); + myWriter->Key ("name"); + myWriter->String (aNodeName.ToCString()); } - myWriter->Key ("name"); - myWriter->String (aNodeName.ToCString()); } myWriter->EndObject(); } diff --git a/src/RWGltf/RWGltf_CafWriter.hxx b/src/RWGltf/RWGltf_CafWriter.hxx index 0d84cb1998..5aad88a326 100644 --- a/src/RWGltf/RWGltf_CafWriter.hxx +++ b/src/RWGltf/RWGltf_CafWriter.hxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,18 @@ public: //! Set preferred transformation format for writing into glTF file. void SetTransformationFormat (RWGltf_WriterTrsfFormat theFormat) { myTrsfFormat = theFormat; } + //! Return name format for exporting Nodes; RWMesh_NameFormat_InstanceOrProduct by default. + RWMesh_NameFormat NodeNameFormat() const { return myNodeNameFormat; } + + //! Set name format for exporting Nodes. + void SetNodeNameFormat (RWMesh_NameFormat theFormat) { myNodeNameFormat = theFormat; } + + //! Return name format for exporting Meshes; RWMesh_NameFormat_Product by default. + RWMesh_NameFormat MeshNameFormat() const { return myMeshNameFormat; } + + //! Set name format for exporting Meshes. + void SetMeshNameFormat (RWMesh_NameFormat theFormat) { myMeshNameFormat = theFormat; } + //! Return TRUE to export UV coordinates even if there are no mapped texture; FALSE by default. bool IsForcedUVExport() const { return myIsForcedUVExport; } @@ -145,6 +158,14 @@ protected: //! Return TRUE if face mesh should be skipped (e.g. because it is invalid or empty). Standard_EXPORT virtual Standard_Boolean toSkipFaceMesh (const RWMesh_FaceIterator& theFaceIter); + //! Generate name for specified labels. + //! @param[in] theFormat name format to apply + //! @param[in] theLabel instance label + //! @param[in] theRefLabel product label + Standard_EXPORT virtual TCollection_AsciiString formatName (RWMesh_NameFormat theFormat, + const TDF_Label& theLabel, + const TDF_Label& theRefLabel) const; + //! Write mesh nodes into binary file. //! @param theGltfFace [out] glTF face definition //! @param theBinFile [out] output file to write into @@ -278,6 +299,8 @@ protected: TCollection_AsciiString myBinFileNameFull; //!< output file with binary data (full path) TCollection_AsciiString myBinFileNameShort; //!< output file with binary data (short path) RWGltf_WriterTrsfFormat myTrsfFormat; //!< transformation format to write into glTF file + RWMesh_NameFormat myNodeNameFormat; //!< name format for exporting Nodes + RWMesh_NameFormat myMeshNameFormat; //!< name format for exporting Meshes Standard_Boolean myIsBinary; //!< flag to write into binary glTF format (.glb) Standard_Boolean myIsForcedUVExport; //!< export UV coordinates even if there are no mapped texture Standard_Boolean myToEmbedTexturesInGlb; //!< flag to write image textures into GLB file diff --git a/src/RWMesh/FILES b/src/RWMesh/FILES index 6cf988993f..b2b4299722 100644 --- a/src/RWMesh/FILES +++ b/src/RWMesh/FILES @@ -1,3 +1,5 @@ +RWMesh.cxx +RWMesh.hxx RWMesh_CoordinateSystem.hxx RWMesh_CoordinateSystemConverter.cxx RWMesh_CoordinateSystemConverter.hxx @@ -7,6 +9,7 @@ RWMesh_FaceIterator.cxx RWMesh_FaceIterator.hxx RWMesh_MaterialMap.cxx RWMesh_MaterialMap.hxx +RWMesh_NameFormat.hxx RWMesh_NodeAttributes.hxx RWMesh_TriangulationReader.cxx RWMesh_TriangulationReader.hxx diff --git a/src/RWMesh/RWMesh.cxx b/src/RWMesh/RWMesh.cxx new file mode 100644 index 0000000000..19a94ab3a4 --- /dev/null +++ b/src/RWMesh/RWMesh.cxx @@ -0,0 +1,112 @@ +// Copyright (c) 2021 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include + +// ================================================================ +// Function : ReadNameAttribute +// Purpose : +// ================================================================ +TCollection_AsciiString RWMesh::ReadNameAttribute (const TDF_Label& theLabel) +{ + Handle(TDataStd_Name) aNodeName; + return theLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName) + ? TCollection_AsciiString (aNodeName->Get()) + : TCollection_AsciiString(); +} + +// ================================================================ +// Function : FormatName +// Purpose : +// ================================================================ +TCollection_AsciiString RWMesh::FormatName (RWMesh_NameFormat theFormat, + const TDF_Label& theLabel, + const TDF_Label& theRefLabel) +{ + switch (theFormat) + { + case RWMesh_NameFormat_Empty: + { + return TCollection_AsciiString(); + } + case RWMesh_NameFormat_Product: + { + Handle(TDataStd_Name) aRefNodeName; + return theRefLabel.FindAttribute (TDataStd_Name::GetID(), aRefNodeName) + ? TCollection_AsciiString (aRefNodeName->Get()) + : TCollection_AsciiString(); + } + case RWMesh_NameFormat_Instance: + { + Handle(TDataStd_Name) aNodeName; + return theLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName) + ? TCollection_AsciiString (aNodeName->Get()) + : TCollection_AsciiString(); + } + case RWMesh_NameFormat_InstanceOrProduct: + { + Handle(TDataStd_Name) aNodeName; + if (theLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName) + && !aNodeName->Get().IsEmpty()) + { + return TCollection_AsciiString (aNodeName->Get()); + } + + Handle(TDataStd_Name) aRefNodeName; + return theRefLabel.FindAttribute (TDataStd_Name::GetID(), aRefNodeName) + ? TCollection_AsciiString (aRefNodeName->Get()) + : TCollection_AsciiString(); + } + case RWMesh_NameFormat_ProductOrInstance: + { + Handle(TDataStd_Name) aRefNodeName; + if (theRefLabel.FindAttribute (TDataStd_Name::GetID(), aRefNodeName) + && !aRefNodeName->Get().IsEmpty()) + { + return TCollection_AsciiString (aRefNodeName->Get()); + } + + Handle(TDataStd_Name) aNodeName; + return theLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName) + ? TCollection_AsciiString (aNodeName->Get()) + : TCollection_AsciiString(); + } + case RWMesh_NameFormat_ProductAndInstance: + { + const TCollection_AsciiString anInstName = ReadNameAttribute (theLabel); + const TCollection_AsciiString aProdName = ReadNameAttribute (theRefLabel); + return !anInstName.IsEmpty() + && aProdName != anInstName + ? aProdName + " [" + anInstName + "]" + : (!aProdName.IsEmpty() + ? aProdName + : TCollection_AsciiString("")); + } + case RWMesh_NameFormat_ProductAndInstanceAndOcaf: + { + const TCollection_AsciiString anInstName = ReadNameAttribute (theLabel); + const TCollection_AsciiString aProdName = ReadNameAttribute (theRefLabel); + TCollection_AsciiString anEntryId; + TDF_Tool::Entry (theLabel, anEntryId); + return !anInstName.IsEmpty() + && aProdName != anInstName + ? aProdName + " [" + anInstName + "]" + " [" + anEntryId + "]" + : aProdName + " [" + anEntryId + "]"; + } + } + + return TCollection_AsciiString(); +} diff --git a/src/RWMesh/RWMesh.hxx b/src/RWMesh/RWMesh.hxx new file mode 100644 index 0000000000..d5f5157f18 --- /dev/null +++ b/src/RWMesh/RWMesh.hxx @@ -0,0 +1,38 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _RWMesh_HeaderFile +#define _RWMesh_HeaderFile + +#include +#include + +//! Auxiliary tools for RWMesh package. +class RWMesh +{ +public: + + //! Read name attribute from label. + Standard_EXPORT static TCollection_AsciiString ReadNameAttribute (const TDF_Label& theLabel); + + //! Generate name for specified labels. + //! @param[in] theFormat name format to apply + //! @param[in] theLabel instance label + //! @param[in] theRefLabel product label + Standard_EXPORT static TCollection_AsciiString FormatName (RWMesh_NameFormat theFormat, + const TDF_Label& theLabel, + const TDF_Label& theRefLabel); +}; + +#endif // _RWMesh_HeaderFile diff --git a/src/RWMesh/RWMesh_NameFormat.hxx b/src/RWMesh/RWMesh_NameFormat.hxx new file mode 100644 index 0000000000..9a9aca80d4 --- /dev/null +++ b/src/RWMesh/RWMesh_NameFormat.hxx @@ -0,0 +1,30 @@ +// Copyright: Open CASCADE 2021 +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _RWMesh_NameFormat_HeaderFile +#define _RWMesh_NameFormat_HeaderFile + +//! Name format preference for XCAF shape labels. +enum RWMesh_NameFormat +{ + RWMesh_NameFormat_Empty, //!< omit the name + RWMesh_NameFormat_Product, //!< return Product name + //! (e.g. from XCAFDoc_ShapeTool::GetReferredShape(), which could be shared by multiple Instances) + RWMesh_NameFormat_Instance, //!< return Instance name + RWMesh_NameFormat_InstanceOrProduct, //!< return Instance name when available and Product name otherwise + RWMesh_NameFormat_ProductOrInstance, //!< return Product name when available and Instance name otherwise + RWMesh_NameFormat_ProductAndInstance, //!< generate "Product [Instance]" name + RWMesh_NameFormat_ProductAndInstanceAndOcaf, //!< generate name combining Product+Instance+Ocaf (useful for debugging purposes) +}; + +#endif // _RWMesh_NameFormat_HeaderFile diff --git a/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx b/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx index 4569f8785f..6a847af543 100644 --- a/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx +++ b/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx @@ -90,6 +90,64 @@ extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theNam const Handle(AIS_InteractiveObject)& theAISObj, Standard_Boolean theReplaceIfExists = Standard_True); +//! Parse RWMesh_NameFormat enumeration. +static bool parseNameFormat (const char* theArg, + RWMesh_NameFormat& theFormat) +{ + TCollection_AsciiString aName (theArg); + aName.LowerCase(); + if (aName == "empty") + { + theFormat = RWMesh_NameFormat_Empty; + } + else if (aName == "product" + || aName == "prod") + { + theFormat = RWMesh_NameFormat_Product; + } + else if (aName == "instance" + || aName == "inst") + { + theFormat = RWMesh_NameFormat_Instance; + } + else if (aName == "instanceorproduct" + || aName == "instance||product" + || aName == "instance|product" + || aName == "instorprod" + || aName == "inst||prod" + || aName == "inst|prod") + { + theFormat = RWMesh_NameFormat_InstanceOrProduct; + } + else if (aName == "productorinstance" + || aName == "product||instance" + || aName == "product|instance" + || aName == "prodorinst" + || aName == "prod||inst" + || aName == "prod|inst") + { + theFormat = RWMesh_NameFormat_ProductOrInstance; + } + else if (aName == "productandinstance" + || aName == "prodandinst" + || aName == "product&instance" + || aName == "prod&inst") + { + theFormat = RWMesh_NameFormat_ProductAndInstance; + } + else if (aName == "productandinstanceandocaf" + || aName == "verbose" + || aName == "debug") + { + theFormat = RWMesh_NameFormat_ProductAndInstanceAndOcaf; + } + else + { + return false; + } + return true; +} + //============================================================================= //function : ReadGltf //purpose : Reads glTF file @@ -276,6 +334,8 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI, TColStd_IndexedDataMapOfStringString aFileInfo; RWGltf_WriterTrsfFormat aTrsfFormat = RWGltf_WriterTrsfFormat_Compact; bool toForceUVExport = false, toEmbedTexturesInGlb = true; + RWMesh_NameFormat aNodeNameFormat = RWMesh_NameFormat_InstanceOrProduct; + RWMesh_NameFormat aMeshNameFormat = RWMesh_NameFormat_Product; for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter) { TCollection_AsciiString anArgCase (theArgVec[anArgIter]); @@ -323,6 +383,28 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI, return 1; } } + else if (anArgCase == "-nodenameformat" + || anArgCase == "-nodename") + { + ++anArgIter; + if (anArgIter >= theNbArgs + || !parseNameFormat (theArgVec[anArgIter], aNodeNameFormat)) + { + Message::SendFail() << "Syntax error at '" << anArgCase << "'"; + return 1; + } + } + else if (anArgCase == "-meshnameformat" + || anArgCase == "-meshname") + { + ++anArgIter; + if (anArgIter >= theNbArgs + || !parseNameFormat (theArgVec[anArgIter], aMeshNameFormat)) + { + Message::SendFail() << "Syntax error at '" << anArgCase << "'"; + return 1; + } + } else if (aDoc.IsNull()) { Standard_CString aNameVar = theArgVec[anArgIter]; @@ -370,6 +452,8 @@ static Standard_Integer WriteGltf (Draw_Interpretor& theDI, RWGltf_CafWriter aWriter (aGltfFilePath, anExt.EndsWith (".glb")); aWriter.SetTransformationFormat (aTrsfFormat); + aWriter.SetNodeNameFormat (aNodeNameFormat); + aWriter.SetMeshNameFormat (aMeshNameFormat); aWriter.SetForcedUVExport (toForceUVExport); aWriter.SetToEmbedTexturesInGlb (toEmbedTexturesInGlb); aWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit (aSystemUnitFactor); @@ -1904,10 +1988,14 @@ void XSDRAWSTLVRML::InitCommands (Draw_Interpretor& theCommands) "WriteGltf Doc file [-trsfFormat {compact|TRS|mat4}=compact]" "\n\t\t: [-comments Text] [-author Name]" "\n\t\t: [-forceUVExport] [-texturesSeparate]" + "\n\t\t: [-nodeNameFormat {empty|product|instance|instOrProd|prodOrInst|prodAndInst|verbose}=instOrProd]" + "\n\t\t: [-meshNameFormat {empty|product|instance|instOrProd|prodOrInst|prodAndInst|verbose}=product]" "\n\t\t: Write XDE document into glTF file." "\n\t\t: -trsfFormat preferred transformation format" "\n\t\t: -forceUVExport always export UV coordinates" - "\n\t\t: -texturesSeparate write textures to separate files", + "\n\t\t: -texturesSeparate write textures to separate files" + "\n\t\t: -nodeNameFormat name format for Nodes" + "\n\t\t: -meshNameFormat name format for Meshes", __FILE__, WriteGltf, g); theCommands.Add ("writegltf", "writegltf shape file",