]> OCCT Git - occt.git/commitdiff
Data Exchange, GLTF - fix saving edges when Merge Faces is enabled #554
authorElias Cohenca <elias@bananaz.ai>
Fri, 23 May 2025 11:24:13 +0000 (14:24 +0300)
committerGitHub <noreply@github.com>
Fri, 23 May 2025 11:24:13 +0000 (12:24 +0100)
Removed check for LineStrip mode to force use of Lines for merged faces
Updated primitive mode checks by removing LineStrip references
Added getShapeType to correctly determine the underlying shape type from compounds and updated index calculation logic

src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.cxx
src/DataExchange/TKDEGLTF/RWGltf/RWGltf_CafWriter.hxx
src/DataExchange/TKDEGLTF/RWGltf/RWGltf_GltfJsonParser.cxx
src/DataExchange/TKDEGLTF/RWGltf/RWGltf_TriangulationReader.cxx

index d2cff43a6689cd541feeebcb0143b2a90ccdd4dc..630eca3d5a7c18cfad7456ab77f838b0c798c8e6 100644 (file)
@@ -278,6 +278,23 @@ TCollection_AsciiString RWGltf_CafWriter::formatName(RWMesh_NameFormat theFormat
 
 //=================================================================================================
 
+TopAbs_ShapeEnum RWGltf_CafWriter::getShapeType(const TopoDS_Shape& theShape) const
+{
+  TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
+  if (aShapeType == TopAbs_COMPOUND)
+  {
+    // Compounds are created in the case of merged faces.
+    // Assuming that all shapes in the compound are of the same type
+    TopoDS_Iterator it(theShape);
+    Standard_ProgramError_Raise_if(!it.More(), "Empty compound");
+    aShapeType = it.Value().ShapeType();
+  }
+
+  return aShapeType;
+}
+
+//=================================================================================================
+
 Standard_Boolean RWGltf_CafWriter::toSkipShape(const RWMesh_ShapeIterator& theShapeIter) const
 {
   return theShapeIter.IsEmpty();
@@ -287,19 +304,17 @@ Standard_Boolean RWGltf_CafWriter::toSkipShape(const RWMesh_ShapeIterator& theSh
 
 Standard_Boolean RWGltf_CafWriter::hasTriangulation(const RWGltf_GltfFace& theGltfFace) const
 {
-  switch (theGltfFace.Shape.ShapeType())
+  TopAbs_ShapeEnum shapeType = getShapeType(theGltfFace.Shape);
+
+  switch (shapeType)
   {
-    case TopAbs_COMPOUND:
-    case TopAbs_COMPSOLID:
-    case TopAbs_SOLID:
-    case TopAbs_SHELL:
     case TopAbs_FACE:
       return true;
-    case TopAbs_WIRE:
     case TopAbs_EDGE:
     case TopAbs_VERTEX:
-    default:
       return false;
+    default:
+      throw Standard_ProgramError("Unsupported shape type");
   }
 }
 
@@ -499,21 +514,29 @@ void RWGltf_CafWriter::saveTriangleIndices(RWGltf_GltfFace&           theGltfFac
 
 void RWGltf_CafWriter::saveEdgeIndices(RWGltf_GltfFace&           theGltfFace,
                                        std::ostream&              theBinFile,
-                                       const RWMesh_EdgeIterator& theFaceIter)
+                                       const RWMesh_EdgeIterator& theEdgeIter)
 {
-  const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes - theFaceIter.ElemLower();
-  theGltfFace.NbIndexedNodes += theFaceIter.NbNodes();
-  theGltfFace.Indices.Count += theFaceIter.NbNodes();
-  for (Standard_Integer anElemIter = theFaceIter.ElemLower(); anElemIter <= theFaceIter.ElemUpper();
-       ++anElemIter)
+  const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes;
+  theGltfFace.NbIndexedNodes += theEdgeIter.NbNodes();
+
+  const Standard_Integer numSegments = Max(0, theEdgeIter.NbNodes() - 1);
+  // each segment writes two indices
+  theGltfFace.Indices.Count += numSegments * 2;
+
+  for (Standard_Integer i = 0; i < numSegments; ++i)
   {
+    Standard_Integer i0 = aNodeFirst + i;
+    Standard_Integer i1 = aNodeFirst + i + 1;
+
     if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16)
     {
-      writeVertex(theBinFile, (uint16_t)(anElemIter + aNodeFirst));
+      writeVertex(theBinFile, (uint16_t)i0);
+      writeVertex(theBinFile, (uint16_t)i1);
     }
     else
     {
-      writeVertex(theBinFile, anElemIter + aNodeFirst);
+      writeVertex(theBinFile, i0);
+      writeVertex(theBinFile, i1);
     }
   }
 }
@@ -522,12 +545,13 @@ void RWGltf_CafWriter::saveEdgeIndices(RWGltf_GltfFace&           theGltfFace,
 
 void RWGltf_CafWriter::saveVertexIndices(RWGltf_GltfFace&             theGltfFace,
                                          std::ostream&                theBinFile,
-                                         const RWMesh_VertexIterator& theFaceIter)
+                                         const RWMesh_VertexIterator& theVertexIter)
 {
-  const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes - theFaceIter.ElemLower();
-  theGltfFace.NbIndexedNodes += theFaceIter.NbNodes();
-  theGltfFace.Indices.Count += theFaceIter.NbNodes();
-  for (Standard_Integer anElemIter = theFaceIter.ElemLower(); anElemIter <= theFaceIter.ElemUpper();
+  const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes - theVertexIter.ElemLower();
+  theGltfFace.NbIndexedNodes += theVertexIter.NbNodes();
+  theGltfFace.Indices.Count += theVertexIter.NbNodes();
+  for (Standard_Integer anElemIter = theVertexIter.ElemLower();
+       anElemIter <= theVertexIter.ElemUpper();
        ++anElemIter)
   {
     if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16)
@@ -545,7 +569,7 @@ void RWGltf_CafWriter::saveVertexIndices(RWGltf_GltfFace&             theGltfFac
 
 void RWGltf_CafWriter::saveIndices(RWGltf_GltfFace&                               theGltfFace,
                                    std::ostream&                                  theBinFile,
-                                   const RWMesh_ShapeIterator&                    theFaceIter,
+                                   const RWMesh_ShapeIterator&                    theShapeIter,
                                    Standard_Integer&                              theAccessorNb,
                                    const std::shared_ptr<RWGltf_CafWriter::Mesh>& theMesh)
 {
@@ -574,17 +598,18 @@ void RWGltf_CafWriter::saveIndices(RWGltf_GltfFace&
     }
   }
 
-  if (const RWMesh_FaceIterator* aFaceIter = dynamic_cast<const RWMesh_FaceIterator*>(&theFaceIter))
+  if (const RWMesh_FaceIterator* aFaceIter =
+        dynamic_cast<const RWMesh_FaceIterator*>(&theShapeIter))
   {
     saveTriangleIndices(theGltfFace, theBinFile, *aFaceIter, theMesh);
   }
   else if (const RWMesh_EdgeIterator* anEdgeIter =
-             dynamic_cast<const RWMesh_EdgeIterator*>(&theFaceIter))
+             dynamic_cast<const RWMesh_EdgeIterator*>(&theShapeIter))
   {
     saveEdgeIndices(theGltfFace, theBinFile, *anEdgeIter);
   }
   else if (const RWMesh_VertexIterator* aVertexIter =
-             dynamic_cast<const RWMesh_VertexIterator*>(&theFaceIter))
+             dynamic_cast<const RWMesh_VertexIterator*>(&theShapeIter))
   {
     saveVertexIndices(theGltfFace, theBinFile, *aVertexIter);
   }
@@ -963,7 +988,9 @@ bool RWGltf_CafWriter::writeBinData(const Handle(TDocStd_Document)& theDocument,
         aWrittenPrimData.Bind(aGltfFace->Shape, aGltfFace);
 
         Standard_Boolean wasWrittenNonFace = Standard_False;
-        switch (aGltfFace->Shape.ShapeType())
+        TopAbs_ShapeEnum shapeType         = getShapeType(aGltfFace->Shape);
+
+        switch (shapeType)
         {
           case TopAbs_EDGE: {
             RWMesh_EdgeIterator anIter(aGltfFace->Shape, aGltfFace->Style);
@@ -2027,10 +2054,13 @@ void RWGltf_CafWriter::writePrimArray(const RWGltf_GltfFace&         theGltfFace
     }
 
     myWriter->Key("mode");
-    switch (theGltfFace.Shape.ShapeType())
+
+    TopAbs_ShapeEnum shapeType = getShapeType(theGltfFace.Shape);
+
+    switch (shapeType)
     {
       case TopAbs_EDGE:
-        myWriter->Int(RWGltf_GltfPrimitiveMode_LineStrip);
+        myWriter->Int(RWGltf_GltfPrimitiveMode_Lines);
         break;
       case TopAbs_VERTEX:
         myWriter->Int(RWGltf_GltfPrimitiveMode_Points);
index b06838fb45eca04eea89ce78f449c0451f3dc529..5c4f8e0be68270e54d4c91d254331e31caa96dc7 100644 (file)
@@ -209,6 +209,9 @@ protected:
                                          const Message_ProgressRange&                theProgress);
 
 protected:
+  //! Returns the underlying shape in case of a compound.
+  Standard_EXPORT virtual TopAbs_ShapeEnum getShapeType(const TopoDS_Shape& theShape) const;
+
   //! Return TRUE if face shape should be skipped (e.g. because it is invalid or empty).
   Standard_EXPORT virtual Standard_Boolean toSkipShape(
     const RWMesh_ShapeIterator& theShapeIter) const;
index 922ac6d27f84077d621dc037a0ecc68532731fc2..e517be7bf546cbb726a2585183c8c4a37a559e45 100644 (file)
@@ -1808,7 +1808,7 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray(TopoDS_Shape&                  th
     }
   }
   if (aMode != RWGltf_GltfPrimitiveMode_Triangles && aMode != RWGltf_GltfPrimitiveMode_Lines
-      && aMode != RWGltf_GltfPrimitiveMode_LineStrip && aMode != RWGltf_GltfPrimitiveMode_Points)
+      && aMode != RWGltf_GltfPrimitiveMode_Points)
   {
     Message::SendWarning(TCollection_AsciiString() + "Primitive array within Mesh '" + theMeshId
                          + "' skipped due to unsupported mode");
@@ -1976,8 +1976,7 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray(TopoDS_Shape&                  th
         aShape = aVertices;
         break;
       }
-      case RWGltf_GltfPrimitiveMode_Lines:
-      case RWGltf_GltfPrimitiveMode_LineStrip: {
+      case RWGltf_GltfPrimitiveMode_Lines: {
         TColgp_Array1OfPnt aNodes(1, aMeshData->NbEdges());
         for (Standard_Integer anEdgeIdx = 1; anEdgeIdx <= aMeshData->NbEdges(); ++anEdgeIdx)
         {
@@ -2012,7 +2011,7 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray(TopoDS_Shape&                  th
       aShapeAttribs.RawName = theMeshName;
 
       // assign material and not color
-      if (aMode == RWGltf_GltfPrimitiveMode_Lines || aMode == RWGltf_GltfPrimitiveMode_LineStrip)
+      if (aMode == RWGltf_GltfPrimitiveMode_Lines)
       {
         aShapeAttribs.Style.SetColorCurv(aMeshData->BaseColor().GetRGB());
       }
index 3542a2637513d0e8e80cc3382b893ffd6f72166d..77dfdf4a3a95a130b84ae508e0dcbcc8c88da1c1 100644 (file)
@@ -579,7 +579,6 @@ bool RWGltf_TriangulationReader::ReadStream(
   const TCollection_AsciiString& aName     = theSourceMesh->Id();
   const RWGltf_GltfPrimitiveMode aPrimMode = theSourceMesh->PrimitiveMode();
   if (aPrimMode != RWGltf_GltfPrimitiveMode_Triangles && aPrimMode != RWGltf_GltfPrimitiveMode_Lines
-      && aPrimMode != RWGltf_GltfPrimitiveMode_LineStrip
       && aPrimMode != RWGltf_GltfPrimitiveMode_Points)
   {
     Message::SendWarning(TCollection_AsciiString("Buffer '") + aName