0032527: Data Exchange, RWGltf_CafWriter - make name format configurable
authorkgv <kgv@opencascade.com>
Wed, 11 Aug 2021 13:11:45 +0000 (16:11 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 12 Aug 2021 16:07:52 +0000 (19:07 +0300)
Added properties RWGltf_CafWriter::NodeNameFormat() and ::MeshNameFormat().

src/RWGltf/RWGltf_CafWriter.cxx
src/RWGltf/RWGltf_CafWriter.hxx
src/RWMesh/FILES
src/RWMesh/RWMesh.cxx [new file with mode: 0644]
src/RWMesh/RWMesh.hxx [new file with mode: 0644]
src/RWMesh/RWMesh_NameFormat.hxx [new file with mode: 0644]
src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx

index 3888e72..f06f803 100644 (file)
@@ -27,6 +27,7 @@
 #include <RWGltf_GltfPrimitiveMode.hxx>
 #include <RWGltf_GltfRootElement.hxx>
 #include <RWGltf_GltfSceneNodeMap.hxx>
+#include <RWMesh.hxx>
 #include <RWMesh_FaceIterator.hxx>
 #include <TDataStd_Name.hxx>
 #include <TDF_Tool.hxx>
@@ -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();
   }
index 0d84cb1..5aad88a 100644 (file)
@@ -22,6 +22,7 @@
 #include <RWGltf_GltfFace.hxx>
 #include <RWGltf_WriterTrsfFormat.hxx>
 #include <RWMesh_CoordinateSystemConverter.hxx>
+#include <RWMesh_NameFormat.hxx>
 #include <XCAFPrs_Style.hxx>
 
 #include <memory>
@@ -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
index 6cf9889..b2b4299 100644 (file)
@@ -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 (file)
index 0000000..19a94ab
--- /dev/null
@@ -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 <RWMesh.hxx>
+
+#include <TDataStd_Name.hxx>
+#include <TDF_Tool.hxx>
+
+// ================================================================
+// 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 (file)
index 0000000..d5f5157
--- /dev/null
@@ -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 <TDF_Label.hxx>
+#include <RWMesh_NameFormat.hxx>
+
+//! 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 (file)
index 0000000..9a9aca8
--- /dev/null
@@ -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
index 4569f87..6a847af 100644 (file)
@@ -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",