diff --git a/src/RWGltf/RWGltf_CafWriter.cxx b/src/RWGltf/RWGltf_CafWriter.cxx index e33eac3fab..ca0e88aacf 100644 --- a/src/RWGltf/RWGltf_CafWriter.cxx +++ b/src/RWGltf/RWGltf_CafWriter.cxx @@ -17,21 +17,21 @@ #include #include #include -#include -#include #include #include #include #include #include #include -#include #include #include #include #include #include +#include +#include #include +#include #include #include #include @@ -78,18 +78,18 @@ namespace theStream.write ((const char* )aVec2.GetData(), sizeof(aVec2)); } - //! Write triangle indices. - static void writeTriangle32 (std::ostream& theStream, - const Graphic3d_Vec3i& theTri) + //! General function to write triangle indices. + template + static void writeTriangle (std::ostream& theStream, const VecType& theTri) { - theStream.write ((const char* )theTri.GetData(), sizeof(theTri)); + theStream.write (reinterpret_cast(theTri.GetData()), sizeof(theTri)); } - //! Write triangle indices. - static void writeTriangle16 (std::ostream& theStream, - const NCollection_Vec3& theTri) + //! General function to write vertex index. + template + static void writeVertex (std::ostream& theStream, const T& theVertex) { - theStream.write ((const char* )theTri.GetData(), sizeof(theTri)); + theStream.write (reinterpret_cast(&theVertex), sizeof(T)); } #ifdef HAVE_DRACO @@ -287,12 +287,34 @@ TCollection_AsciiString RWGltf_CafWriter::formatName (RWMesh_NameFormat theForma } //================================================================ -// Function : toSkipFaceMesh +// Function : toSkipShape // Purpose : //================================================================ -Standard_Boolean RWGltf_CafWriter::toSkipFaceMesh (const RWMesh_FaceIterator& theFaceIter) +Standard_Boolean RWGltf_CafWriter::toSkipShape (const RWMesh_ShapeIterator& theShapeIter) const { - return theFaceIter.IsEmptyMesh(); + return theShapeIter.IsEmpty(); +} + +//================================================================ +// Function : hasTriangulation +// Purpose : +//================================================================ +Standard_Boolean RWGltf_CafWriter::hasTriangulation (const RWGltf_GltfFace& theGltfFace) const +{ + switch (theGltfFace.Shape.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; + } } // ======================================================================= @@ -301,7 +323,7 @@ Standard_Boolean RWGltf_CafWriter::toSkipFaceMesh (const RWMesh_FaceIterator& th // ======================================================================= void RWGltf_CafWriter::saveNodes (RWGltf_GltfFace& theGltfFace, std::ostream& theBinFile, - const RWMesh_FaceIterator& theFaceIter, + const RWMesh_ShapeIterator& theShapeIter, Standard_Integer& theAccessorNb, const std::shared_ptr& theMesh) const { @@ -320,15 +342,16 @@ void RWGltf_CafWriter::saveNodes (RWGltf_GltfFace& theGltfFace, Standard_ASSERT_RAISE(aPos == (int64_t)theBinFile.tellp(), "wrong offset"); } } - theGltfFace.NodePos.Count += theFaceIter.NbNodes(); + theGltfFace.NodePos.Count += theShapeIter.NbNodes(); - const Standard_Integer aNodeUpper = theFaceIter.NodeUpper(); - for (Standard_Integer aNodeIter = theFaceIter.NodeLower(); aNodeIter <= aNodeUpper; ++aNodeIter) + const Standard_Integer aNodeUpper = theShapeIter.NodeUpper(); + for (Standard_Integer aNodeIter = theShapeIter.NodeLower(); aNodeIter <= aNodeUpper; ++aNodeIter) { - gp_XYZ aNode = theFaceIter.NodeTransformed (aNodeIter).XYZ(); + gp_XYZ aNode = theShapeIter.NodeTransformed (aNodeIter).XYZ(); myCSTrsf.TransformPosition (aNode); theGltfFace.NodePos.BndBox.Add (Graphic3d_Vec3d(aNode.X(), aNode.Y(), aNode.Z())); - if (theMesh.get() != nullptr) + if (theMesh.get() != nullptr + && hasTriangulation (theGltfFace)) { theMesh->NodesVec.push_back(Graphic3d_Vec3(float(aNode.X()), float(aNode.Y()), float(aNode.Z()))); } @@ -345,7 +368,7 @@ void RWGltf_CafWriter::saveNodes (RWGltf_GltfFace& theGltfFace, // ======================================================================= void RWGltf_CafWriter::saveNormals (RWGltf_GltfFace& theGltfFace, std::ostream& theBinFile, - RWMesh_FaceIterator& theFaceIter, + const RWMesh_FaceIterator& theFaceIter, Standard_Integer& theAccessorNb, const std::shared_ptr& theMesh) const { @@ -404,16 +427,16 @@ void RWGltf_CafWriter::saveTextCoords (RWGltf_GltfFace& theGltfFace, } if (!myIsForcedUVExport) { - if (theFaceIter.FaceStyle().Material().IsNull()) + if (theFaceIter.Style().Material().IsNull()) { return; } - if (RWGltf_GltfMaterialMap::baseColorTexture (theFaceIter.FaceStyle().Material()).IsNull() - && theFaceIter.FaceStyle().Material()->PbrMaterial().MetallicRoughnessTexture.IsNull() - && theFaceIter.FaceStyle().Material()->PbrMaterial().EmissiveTexture.IsNull() - && theFaceIter.FaceStyle().Material()->PbrMaterial().OcclusionTexture.IsNull() - && theFaceIter.FaceStyle().Material()->PbrMaterial().NormalTexture.IsNull()) + if (RWGltf_GltfMaterialMap::baseColorTexture (theFaceIter.Style().Material()).IsNull() + && theFaceIter.Style().Material()->PbrMaterial().MetallicRoughnessTexture.IsNull() + && theFaceIter.Style().Material()->PbrMaterial().EmissiveTexture.IsNull() + && theFaceIter.Style().Material()->PbrMaterial().OcclusionTexture.IsNull() + && theFaceIter.Style().Material()->PbrMaterial().NormalTexture.IsNull()) { return; } @@ -452,13 +475,97 @@ void RWGltf_CafWriter::saveTextCoords (RWGltf_GltfFace& theGltfFace, } } +// ======================================================================= +// function : saveTriangleIndices +// purpose : +// ======================================================================= +void RWGltf_CafWriter::saveTriangleIndices (RWGltf_GltfFace& theGltfFace, + std::ostream& theBinFile, + const RWMesh_FaceIterator& theFaceIter, + const std::shared_ptr& theMesh) +{ + const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes - theFaceIter.ElemLower(); + theGltfFace.NbIndexedNodes += theFaceIter.NbNodes(); + theGltfFace.Indices.Count += theFaceIter.NbTriangles() * 3; + for (Standard_Integer anElemIter = theFaceIter.ElemLower(); anElemIter <= theFaceIter.ElemUpper(); ++anElemIter) + { + Poly_Triangle aTri = theFaceIter.TriangleOriented(anElemIter); + aTri(1) += aNodeFirst; + aTri(2) += aNodeFirst; + aTri(3) += aNodeFirst; + if (theMesh.get() != nullptr) + { + theMesh->IndicesVec.push_back(aTri); + } + else + { + if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16) + { + writeTriangle (theBinFile, NCollection_Vec3((uint16_t)aTri(1), (uint16_t)aTri(2), (uint16_t)aTri(3))); + } + else + { + writeTriangle (theBinFile, Graphic3d_Vec3i(aTri(1), aTri(2), aTri(3))); + } + } + } +} + +// ======================================================================= +// function : saveEdgeIndices +// purpose : +// ======================================================================= +void RWGltf_CafWriter::saveEdgeIndices (RWGltf_GltfFace& theGltfFace, + std::ostream& theBinFile, + const RWMesh_EdgeIterator& theFaceIter) +{ + 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) + { + if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16) + { + writeVertex (theBinFile, (uint16_t)(anElemIter + aNodeFirst)); + } + else + { + writeVertex (theBinFile, anElemIter + aNodeFirst); + } + } +} + +// ======================================================================= +// function : saveVertexIndices +// purpose : +// ======================================================================= +void RWGltf_CafWriter::saveVertexIndices (RWGltf_GltfFace& theGltfFace, + std::ostream& theBinFile, + const RWMesh_VertexIterator& theFaceIter) +{ + 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) + { + if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16) + { + writeVertex (theBinFile, (uint16_t)(anElemIter + aNodeFirst)); + } + else + { + writeVertex (theBinFile, anElemIter + aNodeFirst); + } + } +} + // ======================================================================= // function : saveIndices // purpose : // ======================================================================= void RWGltf_CafWriter::saveIndices (RWGltf_GltfFace& theGltfFace, std::ostream& theBinFile, - const RWMesh_FaceIterator& theFaceIter, + const RWMesh_ShapeIterator& theFaceIter, Standard_Integer& theAccessorNb, const std::shared_ptr& theMesh) { @@ -483,33 +590,17 @@ void RWGltf_CafWriter::saveIndices (RWGltf_GltfFace& theGltfFace, } } - const Standard_Integer aNodeFirst = theGltfFace.NbIndexedNodes - theFaceIter.ElemLower(); - theGltfFace.NbIndexedNodes += theFaceIter.NbNodes(); - theGltfFace.Indices.Count += theFaceIter.NbTriangles() * 3; - - const Standard_Integer anElemLower = theFaceIter.ElemLower(); - const Standard_Integer anElemUpper = theFaceIter.ElemUpper(); - for (Standard_Integer anElemIter = anElemLower; anElemIter <= anElemUpper; ++anElemIter) + if (const RWMesh_FaceIterator* aFaceIter = dynamic_cast(&theFaceIter)) { - Poly_Triangle aTri = theFaceIter.TriangleOriented (anElemIter); - aTri(1) += aNodeFirst; - aTri(2) += aNodeFirst; - aTri(3) += aNodeFirst; - if (theMesh.get() != nullptr) - { - theMesh->IndicesVec.push_back(aTri); - } - else - { - if (theGltfFace.Indices.ComponentType == RWGltf_GltfAccessorCompType_UInt16) - { - writeTriangle16(theBinFile, NCollection_Vec3((uint16_t)aTri(1), (uint16_t)aTri(2), (uint16_t)aTri(3))); - } - else - { - writeTriangle32(theBinFile, Graphic3d_Vec3i(aTri(1), aTri(2), aTri(3))); - } - } + saveTriangleIndices (theGltfFace, theBinFile, *aFaceIter, theMesh); + } + else if (const RWMesh_EdgeIterator* anEdgeIter = dynamic_cast(&theFaceIter)) + { + saveEdgeIndices (theGltfFace, theBinFile, *anEdgeIter); + } + else if (const RWMesh_VertexIterator* aVertexIter = dynamic_cast(&theFaceIter)) + { + saveVertexIndices (theGltfFace, theBinFile, *aVertexIter); } } @@ -560,6 +651,149 @@ bool RWGltf_CafWriter::Perform (const Handle(TDocStd_Document)& theDocument, return writeJson (theDocument, theRootLabels, theLabelFilter, theFileInfo, aPSentry.Next()); } +// ======================================================================= +// function : dispatchShapes +// purpose : +// ======================================================================= +void RWGltf_CafWriter::dispatchShapes (const XCAFPrs_DocumentNode& theDocNode, + const Message_ProgressScope& thePSentryBin, + NCollection_DataMap& theMergedFaces, + RWMesh_ShapeIterator& theShapeIter) +{ + if (myToMergeFaces) + { + RWGltf_StyledShape aStyledShape (theShapeIter.ExploredShape(), theDocNode.Style); + if (myBinDataMap.Contains (aStyledShape)) + { + return; + } + + Handle(RWGltf_GltfFaceList) aGltfFaceList = new RWGltf_GltfFaceList(); + myBinDataMap.Add (aStyledShape, aGltfFaceList); + for (; theShapeIter.More() && thePSentryBin.More(); theShapeIter.Next()) + { + if (toSkipShape (theShapeIter)) + { + continue; + } + + Handle(RWGltf_GltfFace) aGltfFace; + if (!theMergedFaces.Find (theShapeIter.Style(), aGltfFace)) + { + aGltfFace = new RWGltf_GltfFace(); + aGltfFaceList->Append (aGltfFace); + aGltfFace->Shape = theShapeIter.Shape(); + aGltfFace->Style = theShapeIter.Style(); + aGltfFace->NbIndexedNodes = theShapeIter.NbNodes(); + theMergedFaces.Bind (theShapeIter.Style(), aGltfFace); + } + else if (myToSplitIndices16 + && aGltfFace->NbIndexedNodes < std::numeric_limits::max() + && (aGltfFace->NbIndexedNodes + theShapeIter.NbNodes()) >= std::numeric_limits::max()) + { + theMergedFaces.UnBind (theShapeIter.Style()); + aGltfFace = new RWGltf_GltfFace(); + aGltfFaceList->Append(aGltfFace); + aGltfFace->Shape = theShapeIter.Shape(); + aGltfFace->Style = theShapeIter.Style(); + aGltfFace->NbIndexedNodes = theShapeIter.NbNodes(); + theMergedFaces.Bind (theShapeIter.Style(), aGltfFace); + } + else + { + if (aGltfFace->Shape.ShapeType() != TopAbs_COMPOUND) + { + TopoDS_Shape anOldShape = aGltfFace->Shape; + TopoDS_Compound aComp; + BRep_Builder().MakeCompound (aComp); + BRep_Builder().Add (aComp, anOldShape); + aGltfFace->Shape = aComp; + } + BRep_Builder().Add (aGltfFace->Shape, theShapeIter.Shape()); + aGltfFace->NbIndexedNodes += theShapeIter.NbNodes(); + } + } + } + else + { + for (; theShapeIter.More() && thePSentryBin.More(); theShapeIter.Next()) + { + RWGltf_StyledShape aStyledShape (theShapeIter.Shape(), theShapeIter.Style()); + if (toSkipShape (theShapeIter) + || myBinDataMap.Contains (aStyledShape)) + { + continue; + } + + Handle(RWGltf_GltfFaceList) aGltfFaceList = new RWGltf_GltfFaceList(); + Handle(RWGltf_GltfFace) aGltfFace = new RWGltf_GltfFace(); + aGltfFace->Shape = theShapeIter.Shape(); + aGltfFace->Style = theShapeIter.Style(); + aGltfFaceList->Append (aGltfFace); + myBinDataMap.Add (aStyledShape, aGltfFaceList); + } + } +} + +// ======================================================================= +// function : saveShapes +// purpose : +// ======================================================================= +Standard_Boolean RWGltf_CafWriter::writeShapesToBin( + RWGltf_GltfFace& theGltfFace, + std::ostream& theBinFile, + RWMesh_ShapeIterator& theShapeIter, + Standard_Integer& theAccessorNb, + const std::shared_ptr& theMesh, + const RWGltf_GltfArrayType theArrType, + const Message_ProgressScope& thePSentryBin) +{ + for (; theShapeIter.More() && thePSentryBin.More(); theShapeIter.Next()) + { + switch (theArrType) + { + case RWGltf_GltfArrayType_Position: { + // clang-format off + theGltfFace.NbIndexedNodes = 0; // reset to zero before RWGltf_GltfArrayType_Indices step + // clang-format on + saveNodes(theGltfFace, theBinFile, theShapeIter, theAccessorNb, theMesh); + break; + } + case RWGltf_GltfArrayType_Normal: { + if (const RWMesh_FaceIterator* aFaceIter = + dynamic_cast(&theShapeIter)) + { + saveNormals(theGltfFace, theBinFile, *aFaceIter, theAccessorNb, theMesh); + } + break; + } + case RWGltf_GltfArrayType_TCoord0: { + if (const RWMesh_FaceIterator* aFaceIter = + dynamic_cast(&theShapeIter)) + { + saveTextCoords(theGltfFace, theBinFile, *aFaceIter, theAccessorNb, theMesh); + } + break; + } + case RWGltf_GltfArrayType_Indices: { + saveIndices(theGltfFace, theBinFile, theShapeIter, theAccessorNb, theMesh); + break; + } + default: { + break; + } + } + + if (!theBinFile.good()) + { + Message::SendFail(TCollection_AsciiString("File '") + myBinFileNameFull + + "' cannot be written"); + return false; + } + } + return true; +} + // ======================================================================= // function : writeBinData // purpose : @@ -625,7 +859,7 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument RWGltf_GltfArrayType_Indices }; - // dispatch faces + // dispatch shapes NCollection_DataMap aMergedFaces; for (XCAFPrs_DocumentExplorer aDocExplorer (theDocument, theRootLabels, XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes); aDocExplorer.More() && aPSentryBin.More(); aDocExplorer.Next()) @@ -640,79 +874,20 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument // transformation will be stored at scene nodes aMergedFaces.Clear (false); - RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); - if (myToMergeFaces) + Standard_Integer aBinDataSize = myBinDataMap.Size(); { - RWGltf_StyledShape aStyledShape (aFaceIter.ExploredShape(), aDocNode.Style); - if (myBinDataMap.Contains (aStyledShape)) - { - continue; - } - - Handle(RWGltf_GltfFaceList) aGltfFaceList = new RWGltf_GltfFaceList(); - myBinDataMap.Add (aStyledShape, aGltfFaceList); - for (; aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) - { - if (toSkipFaceMesh (aFaceIter)) - { - continue; - } - - Handle(RWGltf_GltfFace) aGltfFace; - if (!aMergedFaces.Find (aFaceIter.FaceStyle(), aGltfFace)) - { - aGltfFace = new RWGltf_GltfFace(); - aGltfFaceList->Append (aGltfFace); - aGltfFace->Shape = aFaceIter.Face(); - aGltfFace->Style = aFaceIter.FaceStyle(); - aGltfFace->NbIndexedNodes = aFaceIter.NbNodes(); - aMergedFaces.Bind (aFaceIter.FaceStyle(), aGltfFace); - } - else if (myToSplitIndices16 - && aGltfFace->NbIndexedNodes < std::numeric_limits::max() - && (aGltfFace->NbIndexedNodes + aFaceIter.NbNodes()) >= std::numeric_limits::max()) - { - aMergedFaces.UnBind (aFaceIter.FaceStyle()); - aGltfFace = new RWGltf_GltfFace(); - aGltfFaceList->Append (aGltfFace); - aGltfFace->Shape = aFaceIter.Face(); - aGltfFace->Style = aFaceIter.FaceStyle(); - aGltfFace->NbIndexedNodes = aFaceIter.NbNodes(); - aMergedFaces.Bind (aFaceIter.FaceStyle(), aGltfFace); - } - else - { - if (aGltfFace->Shape.ShapeType() != TopAbs_COMPOUND) - { - TopoDS_Shape anOldShape = aGltfFace->Shape; - TopoDS_Compound aComp; - BRep_Builder().MakeCompound (aComp); - BRep_Builder().Add (aComp, anOldShape); - aGltfFace->Shape = aComp; - } - BRep_Builder().Add (aGltfFace->Shape, aFaceIter.Face()); - aGltfFace->NbIndexedNodes += aFaceIter.NbNodes(); - } - } + RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + dispatchShapes (aDocNode, aPSentryBin, aMergedFaces, aFaceIter); } - else + if (aBinDataSize == myBinDataMap.Size()) { - for (; aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) - { - RWGltf_StyledShape aStyledShape (aFaceIter.Face(), aFaceIter.FaceStyle()); - if (toSkipFaceMesh (aFaceIter) - || myBinDataMap.Contains (aStyledShape)) - { - continue; - } - - Handle(RWGltf_GltfFaceList) aGltfFaceList = new RWGltf_GltfFaceList(); - Handle(RWGltf_GltfFace) aGltfFace = new RWGltf_GltfFace(); - aGltfFace->Shape = aFaceIter.Face(); - aGltfFace->Style = aFaceIter.FaceStyle(); - aGltfFaceList->Append (aGltfFace); - myBinDataMap.Add (aStyledShape, aGltfFaceList); - } + RWMesh_EdgeIterator anEdgeIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + dispatchShapes (aDocNode, aPSentryBin, aMergedFaces, anEdgeIter); + } + if (aBinDataSize == myBinDataMap.Size()) + { + RWMesh_VertexIterator aVertexIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + dispatchShapes (aDocNode, aPSentryBin, aMergedFaces, aVertexIter); } } @@ -738,6 +913,8 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument #ifdef HAVE_DRACO size_t aMeshIndex = 0; #endif + + Standard_Boolean isFacesOnly = Standard_True; for (ShapeToGltfFaceMap::Iterator aBinDataIter (myBinDataMap); aBinDataIter.More() && aPSentryBin.More(); aBinDataIter.Next()) { const Handle(RWGltf_GltfFaceList)& aGltfFaceList = aBinDataIter.Value(); @@ -801,49 +978,44 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument } aWrittenPrimData.Bind (aGltfFace->Shape, aGltfFace); - for (RWMesh_FaceIterator aFaceIter (aGltfFace->Shape, aGltfFace->Style); aFaceIter.More() && aPSentryBin.More(); aFaceIter.Next()) + Standard_Boolean wasWrittenNonFace = Standard_False; + switch (aGltfFace->Shape.ShapeType()) { - switch (anArrType) + case TopAbs_EDGE: { - case RWGltf_GltfArrayType_Position: + RWMesh_EdgeIterator anIter(aGltfFace->Shape, aGltfFace->Style); + if (!writeShapesToBin (*aGltfFace, *aBinFile, anIter, aNbAccessors, aMeshPtr, anArrType, aPSentryBin)) { -// clang-format off - aGltfFace->NbIndexedNodes = 0; // reset to zero before RWGltf_GltfArrayType_Indices step -// clang-format on - saveNodes (*aGltfFace, *aBinFile, aFaceIter, aNbAccessors, aMeshPtr); - break; - } - case RWGltf_GltfArrayType_Normal: - { - saveNormals (*aGltfFace, *aBinFile, aFaceIter, aNbAccessors, aMeshPtr); - break; + return false; } - case RWGltf_GltfArrayType_TCoord0: - { - saveTextCoords (*aGltfFace, *aBinFile, aFaceIter, aNbAccessors, aMeshPtr); - break; - } - case RWGltf_GltfArrayType_Indices: - { - saveIndices (*aGltfFace, *aBinFile, aFaceIter, aNbAccessors, aMeshPtr); - break; - } - default: + wasWrittenNonFace = Standard_True; + break; + } + case TopAbs_VERTEX: + { + RWMesh_VertexIterator anIter(aGltfFace->Shape, aGltfFace->Style); + if (!writeShapesToBin (*aGltfFace, *aBinFile, anIter, aNbAccessors, aMeshPtr, anArrType, aPSentryBin)) { - break; + return false; } + wasWrittenNonFace = Standard_True; + break; } - - if (!aBinFile->good()) + default: { - Message::SendFail (TCollection_AsciiString ("File '") + myBinFileNameFull + "' cannot be written"); - return false; + RWMesh_FaceIterator anIter(aGltfFace->Shape, aGltfFace->Style); + if (!writeShapesToBin (*aGltfFace, *aBinFile, anIter, aNbAccessors, aMeshPtr, anArrType, aPSentryBin)) + { + return false; + } + break; } } // add alignment by 4 bytes (might happen on RWGltf_GltfAccessorCompType_UInt16 indices) - if (!myDracoParameters.DracoCompression) + if (!myDracoParameters.DracoCompression || wasWrittenNonFace) { + isFacesOnly = Standard_False; int64_t aContentLen64 = (int64_t)aBinFile->tellp(); while (aContentLen64 % 4 != 0) { @@ -854,7 +1026,7 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument } } - if (!myDracoParameters.DracoCompression) + if (!myDracoParameters.DracoCompression || !isFacesOnly) { aBuffView->ByteLength = (int64_t)aBinFile->tellp() - aBuffView->ByteOffset; } @@ -866,6 +1038,24 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument aPSentryBin.Next(); } + int aBuffViewId = 0; + if (myBuffViewPos.ByteLength > 0) + { + myBuffViewPos.Id = aBuffViewId++; + } + if (myBuffViewNorm.ByteLength > 0) + { + myBuffViewNorm.Id = aBuffViewId++; + } + if (myBuffViewTextCoord.ByteLength > 0) + { + myBuffViewTextCoord.Id = aBuffViewId++; + } + if (myBuffViewInd.ByteLength > 0) + { + myBuffViewInd.Id = aBuffViewId++; + } + if (myDracoParameters.DracoCompression) { #ifdef HAVE_DRACO @@ -883,15 +1073,23 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument DracoEncodingFunctor aFunctor (aScope.Next(), aDracoEncoder, aMeshes, anEncoderBuffers); OSD_Parallel::For (0, int(aMeshes.size()), aFunctor, !myToParallel); + int aNbSkippedBuffers = 0; for (size_t aBuffInd = 0; aBuffInd != anEncoderBuffers.size(); ++aBuffInd) { if (anEncoderBuffers.at(aBuffInd).get() == nullptr) { - Message::SendFail(TCollection_AsciiString("Error: mesh not encoded in draco buffer.")); - return false; + if (aBuffViewId == 0) + { + Message::SendFail() << "Error: mesh not encoded in draco buffer."; + return false; + } + Message::SendWarning() + << "Warning: mesh is not encoded as a Draco buffer and has been loaded into a regular buffer."; + aNbSkippedBuffers++; + continue; } RWGltf_GltfBufferView aBuffViewDraco; - aBuffViewDraco.Id = (int)aBuffInd; + aBuffViewDraco.Id = (int)aBuffInd + aBuffViewId - aNbSkippedBuffers; aBuffViewDraco.ByteOffset = aBinFile->tellp(); const draco::EncoderBuffer& anEncoderBuff = *anEncoderBuffers.at(aBuffInd); aBinFile->write(anEncoderBuff.data(), std::streamsize(anEncoderBuff.size())); @@ -933,33 +1131,15 @@ bool RWGltf_CafWriter::writeBinData (const Handle(TDocStd_Document)& theDocument for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) { - if (toSkipFaceMesh (aFaceIter)) + if (toSkipShape (aFaceIter)) { continue; } - myMaterialMap->AddGlbImages (*aBinFile, aFaceIter.FaceStyle()); + myMaterialMap->AddGlbImages (*aBinFile, aFaceIter.Style()); } } } - - int aBuffViewId = 0; - if (myBuffViewPos.ByteLength > 0) - { - myBuffViewPos.Id = aBuffViewId++; - } - if (myBuffViewNorm.ByteLength > 0) - { - myBuffViewNorm.Id = aBuffViewId++; - } - if (myBuffViewTextCoord.ByteLength > 0) - { - myBuffViewTextCoord.Id = aBuffViewId++; - } - if (myBuffViewInd.ByteLength > 0) - { - myBuffViewInd.Id = aBuffViewId++; - } // myMaterialMap->FlushGlbBufferViews() will put image bufferView's IDs at the end of list myBinDataLen64 = aBinFile->tellp(); @@ -1029,27 +1209,45 @@ bool RWGltf_CafWriter::writeJson (const Handle(TDocStd_Document)& theDocument, continue; } - bool hasMeshData = false; + bool hasShapeData = false; if (!aDocNode.IsAssembly) { - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) + auto checkShapeData = [&](RWMesh_ShapeIterator& anIter) { - if (!toSkipFaceMesh (aFaceIter)) + for (; anIter.More(); anIter.Next()) { - hasMeshData = true; - break; + if (!toSkipShape (anIter)) + { + return true; + } } + return false; + }; + { + RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + hasShapeData = checkShapeData (aFaceIter); + } + if (!hasShapeData) + { + RWMesh_EdgeIterator anEdgeIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + hasShapeData = checkShapeData (anEdgeIter); + } + if (!hasShapeData) + { + RWMesh_VertexIterator aVertIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + hasShapeData = checkShapeData (aVertIter); } } - if (hasMeshData) + + if (hasShapeData) { aSceneNodeMap.Add (aDocNode); } else { - // glTF disallows empty meshes / primitive arrays + // glTF disallows empty shapes / primitive arrays const TCollection_AsciiString aNodeName = formatName (RWMesh_NameFormat_ProductOrInstance, aDocNode.Label, aDocNode.RefLabel); - Message::SendWarning (TCollection_AsciiString("RWGltf_CafWriter skipped node '") + aNodeName + "' without triangulation data"); + Message::SendWarning (TCollection_AsciiString("RWGltf_CafWriter skipped node '") + aNodeName + "' without geometry data"); } } @@ -1307,7 +1505,8 @@ void RWGltf_CafWriter::writePositions (const RWGltf_GltfFace& theGltfFace) } myWriter->StartObject(); - if (!myDracoParameters.DracoCompression) + if (!myDracoParameters.DracoCompression + || !hasTriangulation (theGltfFace)) { myWriter->Key ("bufferView"); myWriter->Int (myBuffViewPos.Id); @@ -1460,12 +1659,13 @@ void RWGltf_CafWriter::writeIndices (const RWGltf_GltfFace& theGltfFace) } myWriter->StartObject(); - if (!myDracoParameters.DracoCompression) + if (!myDracoParameters.DracoCompression + || !hasTriangulation (theGltfFace)) { - myWriter->Key("bufferView"); - myWriter->Int(myBuffViewInd.Id); - myWriter->Key("byteOffset"); - myWriter->Int64(theGltfFace.Indices.ByteOffset); + myWriter->Key ("bufferView"); + myWriter->Int (myBuffViewInd.Id); + myWriter->Key ("byteOffset"); + myWriter->Int64 (theGltfFace.Indices.ByteOffset); } myWriter->Key ("componentType"); myWriter->Int (theGltfFace.Indices.ComponentType); @@ -1716,7 +1916,7 @@ void RWGltf_CafWriter::writeImages (const RWGltf_GltfSceneNodeMap& theSceneNodeM const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) { - myMaterialMap->AddImages (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); + myMaterialMap->AddImages (myWriter.get(), aFaceIter.Style(), anIsStarted); } } if (anIsStarted) @@ -1745,7 +1945,7 @@ void RWGltf_CafWriter::writeMaterials (const RWGltf_GltfSceneNodeMap& theSceneNo const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) { - myMaterialMap->AddMaterial (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); + myMaterialMap->AddMaterial (myWriter.get(), aFaceIter.Style(), anIsStarted); } } if (anIsStarted) @@ -1808,10 +2008,23 @@ void RWGltf_CafWriter::writePrimArray (const RWGltf_GltfFace& theGltfFace, myWriter->Key ("material"); myWriter->Int (aMatId.IntegerValue()); } + myWriter->Key ("mode"); - myWriter->Int (RWGltf_GltfPrimitiveMode_Triangles); + switch (theGltfFace.Shape.ShapeType()) + { + case TopAbs_EDGE: + myWriter->Int (RWGltf_GltfPrimitiveMode_Lines); + break; + case TopAbs_VERTEX: + myWriter->Int (RWGltf_GltfPrimitiveMode_Points); + break; + default: + myWriter->Int (RWGltf_GltfPrimitiveMode_Triangles); + break; + } - if (myDracoParameters.DracoCompression) + if (myDracoParameters.DracoCompression + && theGltfFace.Shape.ShapeType() == TopAbs_FACE) { myWriter->Key("extensions"); myWriter->StartObject(); @@ -1855,6 +2068,54 @@ void RWGltf_CafWriter::writePrimArray (const RWGltf_GltfFace& theGltfFace, #endif } +// ======================================================================= +// function : writeShapes +// purpose : +// ======================================================================= +void RWGltf_CafWriter::writeShapes (RWMesh_ShapeIterator& theShapeIter, + Standard_Integer& theNbFacesInNode, + Standard_Integer& theDracoBufInd, + Standard_Boolean& theToStartPrims, + const TCollection_AsciiString& theNodeName, + NCollection_Map& theWrittenShapes, + NCollection_IndexedDataMap& theDracoBufIndMap) +{ + for ( ; theShapeIter.More(); theShapeIter.Next(), ++theNbFacesInNode) + { + if (toSkipShape (theShapeIter)) + { + continue; + } + + RWGltf_StyledShape aStyledShape (theShapeIter.Shape(), theShapeIter.Style()); + const Handle(RWGltf_GltfFaceList)& aGltfShapeList = myBinDataMap.FindFromKey(aStyledShape); + if (!theWrittenShapes.Add (aGltfShapeList)) + { + continue; + } + + const Handle(RWGltf_GltfFace)& aGltfShape = aGltfShapeList->First(); + const int aPrevSize = theDracoBufIndMap.Size(); + const int aTempDracoBufInd = theDracoBufInd; + if (myDracoParameters.DracoCompression + && aGltfShape->Shape.ShapeType() == TopAbs_FACE + && !theDracoBufIndMap.FindFromKey (aGltfShape->NodePos.Id, theDracoBufInd)) + { + theDracoBufIndMap.Add (aGltfShape->NodePos.Id, theDracoBufInd); + } + + writePrimArray (*aGltfShape, theNodeName, theDracoBufInd, theToStartPrims); + if (aTempDracoBufInd != theDracoBufInd) + { + theDracoBufInd = aTempDracoBufInd; + } + if (!myDracoParameters.DracoCompression || theDracoBufIndMap.Size() > aPrevSize) + { + ++theDracoBufInd; + } + } +} + // ======================================================================= // function : writeMeshes // purpose : @@ -1868,16 +2129,16 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM myWriter->StartArray(); int aDracoBufInd = 0; - NCollection_IndexedDataMap aDracoBufIndMap; - NCollection_Map aWrittenFaces; + NCollection_IndexedDataMap aDracoBufMap; + NCollection_Map aWrittenShapes; for (RWGltf_GltfSceneNodeMap::Iterator aSceneNodeIter (theSceneNodeMap); aSceneNodeIter.More(); aSceneNodeIter.Next()) { const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); const TCollection_AsciiString aNodeName = formatName (myMeshNameFormat, aDocNode.Label, aDocNode.RefLabel); bool toStartPrims = true; - Standard_Integer aNbFacesInNode = 0; - aWrittenFaces.Clear (false); + Standard_Integer aNbShapes = 0; + aWrittenShapes.Clear (false); if (myToMergeFaces) { TopoDS_Shape aShape; @@ -1891,7 +2152,7 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM aShape.Location (TopLoc_Location()); RWGltf_StyledShape aStyledShape (aShape, aDocNode.Style); myBinDataMap.FindFromKey (aStyledShape, aGltfFaceList); - if (!aWrittenFaces.Add (aGltfFaceList)) + if (!aWrittenShapes.Add (aGltfFaceList)) { continue; } @@ -1899,12 +2160,12 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM for (RWGltf_GltfFaceList::Iterator aFaceGroupIter (*aGltfFaceList); aFaceGroupIter.More(); aFaceGroupIter.Next()) { const Handle(RWGltf_GltfFace)& aGltfFace = aFaceGroupIter.Value(); - const int aPrevSize = aDracoBufIndMap.Size(); + const int aPrevSize = aDracoBufMap.Size(); const int aTempDracoBufInd = aDracoBufInd; if (myDracoParameters.DracoCompression - && !aDracoBufIndMap.FindFromKey (aGltfFace->NodePos.Id, aDracoBufInd)) + && !aDracoBufMap.FindFromKey (aGltfFace->NodePos.Id, aDracoBufInd)) { - aDracoBufIndMap.Add (aGltfFace->NodePos.Id, aDracoBufInd); + aDracoBufMap.Add (aGltfFace->NodePos.Id, aDracoBufInd); } writePrimArray (*aGltfFace, aNodeName, aDracoBufInd, toStartPrims); @@ -1912,7 +2173,7 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM { aDracoBufInd = aTempDracoBufInd; } - if (!myDracoParameters.DracoCompression || aDracoBufIndMap.Size() > aPrevSize) + if (!myDracoParameters.DracoCompression || aDracoBufMap.Size() > aPrevSize) { ++aDracoBufInd; } @@ -1920,38 +2181,19 @@ void RWGltf_CafWriter::writeMeshes (const RWGltf_GltfSceneNodeMap& theSceneNodeM } else { - for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next(), ++aNbFacesInNode) { - if (toSkipFaceMesh (aFaceIter)) - { - continue; - } - - RWGltf_StyledShape aStyledShape (aFaceIter.Face(), aFaceIter.FaceStyle()); - const Handle(RWGltf_GltfFaceList)& aGltfFaceList = myBinDataMap.FindFromKey (aStyledShape); - if (!aWrittenFaces.Add (aGltfFaceList)) - { - continue; - } - - const Handle(RWGltf_GltfFace)& aGltfFace = aGltfFaceList->First(); - const int aPrevSize = aDracoBufIndMap.Size(); - const int aTempDracoBufInd = aDracoBufInd; - if (myDracoParameters.DracoCompression - && !aDracoBufIndMap.FindFromKey(aGltfFace->NodePos.Id, aDracoBufInd)) - { - aDracoBufIndMap.Add(aGltfFace->NodePos.Id, aDracoBufInd); - } - - writePrimArray (*aGltfFace, aNodeName, aDracoBufInd, toStartPrims); - if (aTempDracoBufInd != aDracoBufInd) - { - aDracoBufInd = aTempDracoBufInd; - } - if (!myDracoParameters.DracoCompression || aDracoBufIndMap.Size() > aPrevSize) - { - ++aDracoBufInd; - } + RWMesh_FaceIterator anIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + writeShapes (anIter, aNbShapes, aDracoBufInd, toStartPrims, aNodeName, aWrittenShapes, aDracoBufMap); + } + if (aNbShapes == 0) + { + RWMesh_EdgeIterator anIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + writeShapes (anIter, aNbShapes, aDracoBufInd, toStartPrims, aNodeName, aWrittenShapes, aDracoBufMap); + } + if (aNbShapes == 0) + { + RWMesh_VertexIterator anIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); + writeShapes (anIter, aNbShapes, aDracoBufInd, toStartPrims, aNodeName, aWrittenShapes, aDracoBufMap); } } @@ -2359,7 +2601,7 @@ void RWGltf_CafWriter::writeTextures (const RWGltf_GltfSceneNodeMap& theSceneNod const XCAFPrs_DocumentNode& aDocNode = aSceneNodeIter.Value(); for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, TopLoc_Location(), true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next()) { - myMaterialMap->AddTextures (myWriter.get(), aFaceIter.FaceStyle(), anIsStarted); + myMaterialMap->AddTextures (myWriter.get(), aFaceIter.Style(), anIsStarted); } } if (anIsStarted) diff --git a/src/RWGltf/RWGltf_CafWriter.hxx b/src/RWGltf/RWGltf_CafWriter.hxx index 2f3a55d0c5..c41c73be0c 100644 --- a/src/RWGltf/RWGltf_CafWriter.hxx +++ b/src/RWGltf/RWGltf_CafWriter.hxx @@ -14,23 +14,30 @@ #ifndef _RWGltf_CafWriter_HeaderFiler #define _RWGltf_CafWriter_HeaderFiler +#include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include class Message_ProgressRange; +class RWMesh_ShapeIterator; class RWMesh_FaceIterator; +class RWMesh_EdgeIterator; +class RWMesh_VertexIterator; class RWGltf_GltfOStreamWriter; class RWGltf_GltfMaterialMap; class RWGltf_GltfSceneNodeMap; @@ -194,8 +201,11 @@ protected: 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); + //! 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; + + //! Return TRUE if shape has triangulation (not vertex or edge). + Standard_EXPORT virtual Standard_Boolean hasTriangulation (const RWGltf_GltfFace& theShape) const; //! Generate name for specified labels. //! @param[in] theFormat name format to apply @@ -208,12 +218,12 @@ protected: //! Write mesh nodes into binary file. //! @param[out] theGltfFace glTF face definition //! @param[out] theBinFile output file to write into - //! @param[in] theFaceIter current face to write + //! @param[in] theShapeIter current shape to write //! @param[in][out] theAccessorNb last accessor index //! @param[in][out] theMesh mesh Standard_EXPORT virtual void saveNodes (RWGltf_GltfFace& theGltfFace, std::ostream& theBinFile, - const RWMesh_FaceIterator& theFaceIter, + const RWMesh_ShapeIterator& theShapeIter, Standard_Integer& theAccessorNb, const std::shared_ptr& theMesh) const; @@ -225,7 +235,7 @@ protected: //! @param[in][out] theMesh mesh Standard_EXPORT virtual void saveNormals (RWGltf_GltfFace& theGltfFace, std::ostream& theBinFile, - RWMesh_FaceIterator& theFaceIter, + const RWMesh_FaceIterator& theFaceIter, Standard_Integer& theAccessorNb, const std::shared_ptr& theMesh) const; @@ -244,15 +254,41 @@ protected: //! Write mesh indexes into binary file. //! @param[out] theGltfFace glTF face definition //! @param[out] theBinFile output file to write into - //! @param[in] theFaceIter current face to write + //! @param[in] theShapeIter current shape to write //! @param[in][out] theAccessorNb last accessor index //! @param[in][out] theMesh mesh Standard_EXPORT virtual void saveIndices (RWGltf_GltfFace& theGltfFace, std::ostream& theBinFile, - const RWMesh_FaceIterator& theFaceIter, + const RWMesh_ShapeIterator& theShapeIter, Standard_Integer& theAccessorNb, const std::shared_ptr& theMesh); + //! Write triangle indexes into binary file. + //! @param[out] theGltfFace glTF face definition + //! @param[out] theBinFile output file to write into + //! @param[in] theFaceIter current face to write + //! @param[in][out] theMesh mesh + Standard_EXPORT virtual void saveTriangleIndices (RWGltf_GltfFace& theGltfFace, + std::ostream& theBinFile, + const RWMesh_FaceIterator& theFaceIter, + const std::shared_ptr& theMesh); + + //! Write edge indexes into binary file. + //! @param[out] theGltfFace glTF face definition + //! @param[out] theBinFile output file to write into + //! @param[in] theEdgeIter current edge to write + Standard_EXPORT virtual void saveEdgeIndices (RWGltf_GltfFace& theGltfFace, + std::ostream& theBinFile, + const RWMesh_EdgeIterator& theEdgeIter); + + //! Write vertex indexes into binary file. + //! @param[out] theGltfFace glTF face definition + //! @param[out] theBinFile output file to write into + //! @param[in] theVertexIter current vertex to write + Standard_EXPORT virtual void saveVertexIndices (RWGltf_GltfFace& theGltfFace, + std::ostream& theBinFile, + const RWMesh_VertexIterator& theVertexIter); + protected: //! Write bufferView for vertex positions within RWGltf_GltfRootElement_Accessors section @@ -352,7 +388,50 @@ protected: //! Write nodes.extras section with key-value attributes. //! @param[in] theNamedData attributes map to process. - Standard_EXPORT virtual void writeExtrasAttributes(const Handle(TDataStd_NamedData)& theNamedData); + Standard_EXPORT virtual void writeExtrasAttributes (const Handle(TDataStd_NamedData)& theNamedData); + + //! Dispatch shapes + //! @param[in] theDocNode Document node containing shape data + //! @param[in] thePSentryBin Progress scope for the operation + //! @param[in,out] theMergedFaces Data map to store merged faces + //! @param[in,out] theShapeIter Shape iterator to traverse shapes + Standard_EXPORT virtual void dispatchShapes (const XCAFPrs_DocumentNode& theDocNode, + const Message_ProgressScope& thePSentryBin, + NCollection_DataMap& theMergedFaces, + RWMesh_ShapeIterator& theShapeIter); + + //! Write shape into binary file + //! @param[out] theGltfFace glTF face definition + //! @param[out] theBinFile Output file to write into + //! @param[in] theShapeIter Current shape iterator + //! @param[in,out] theAccessorNb Last accessor index + //! @param[in,out] theMesh Mesh data + //! @param[in] theArrType Array type for glTF + //! @param[in] thePSentryBin Progress scope for the operation + //! @return True if shapes were successfully written to the binary file, false otherwise + Standard_EXPORT bool writeShapesToBin (RWGltf_GltfFace& theGltfFace, + std::ostream& theBinFile, + RWMesh_ShapeIterator& theShapeIter, + Standard_Integer& theAccessorNb, + const std::shared_ptr& theMesh, + const RWGltf_GltfArrayType theArrType, + const Message_ProgressScope& thePSentryBin); + + //! Write shapes to RWGltf_GltfRootElement_Meshes section + //! @param[in] theShapeIter Shape iterator to traverse shapes + //! @param[in,out] theNbFacesInNode Number of faces in the current node + //! @param[in,out] theDracoBufInd Draco buffer index + //! @param[in,out] theToStartPrims Flag to indicate if primitives should be started + //! @param[in] theNodeName Name of the current node + //! @param[in,out] theWrittenShapes Map to store written shapes + //! @param[in,out] theDracoBufIndMap Map to store Draco buffer indices + Standard_EXPORT virtual void writeShapes (RWMesh_ShapeIterator& theShapeIter, + Standard_Integer& theNbFacesInNode, + Standard_Integer& theDracoBufInd, + Standard_Boolean& theToStartPrims, + const TCollection_AsciiString& theNodeName, + NCollection_Map& theWrittenShapes, + NCollection_IndexedDataMap& theDracoBufIndMap); protected: diff --git a/src/RWMesh/FILES b/src/RWMesh/FILES index 63bb91ee07..cbe8a51c98 100644 --- a/src/RWMesh/FILES +++ b/src/RWMesh/FILES @@ -5,13 +5,19 @@ RWMesh_CafReader.hxx RWMesh_CoordinateSystem.hxx RWMesh_CoordinateSystemConverter.cxx RWMesh_CoordinateSystemConverter.hxx +RWMesh_EdgeIterator.cxx +RWMesh_EdgeIterator.hxx RWMesh_FaceIterator.cxx RWMesh_FaceIterator.hxx RWMesh_MaterialMap.cxx RWMesh_MaterialMap.hxx RWMesh_NameFormat.hxx RWMesh_NodeAttributes.hxx +RWMesh_ShapeIterator.cxx +RWMesh_ShapeIterator.hxx RWMesh_TriangulationReader.cxx RWMesh_TriangulationReader.hxx RWMesh_TriangulationSource.cxx RWMesh_TriangulationSource.hxx +RWMesh_VertexIterator.cxx +RWMesh_VertexIterator.hxx diff --git a/src/RWMesh/RWMesh_EdgeIterator.cxx b/src/RWMesh/RWMesh_EdgeIterator.cxx new file mode 100644 index 0000000000..bdcbe8ce81 --- /dev/null +++ b/src/RWMesh/RWMesh_EdgeIterator.cxx @@ -0,0 +1,78 @@ +// Copyright (c) 2025 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 +#include +#include +#include + +// ======================================================================= +// function : RWMesh_EdgeIterator +// purpose : +// ======================================================================= +RWMesh_EdgeIterator::RWMesh_EdgeIterator(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const Standard_Boolean theToMapColors, + const XCAFPrs_Style& theStyle) + : RWMesh_ShapeIterator(theLabel, theLocation, TopAbs_EDGE, theToMapColors, theStyle) +{ + Next(); +} + +// ======================================================================= +// function : RWMesh_EdgeIterator +// purpose : +// ======================================================================= +RWMesh_EdgeIterator::RWMesh_EdgeIterator(const TopoDS_Shape& theShape, + const XCAFPrs_Style& theStyle) + : RWMesh_ShapeIterator(theShape, TopAbs_EDGE, theStyle) +{ + Next(); +} + +// ======================================================================= +// function : Next +// purpose : +// ======================================================================= +void RWMesh_EdgeIterator::Next() +{ + for (; myIter.More(); myIter.Next()) + { + myEdge = TopoDS::Edge(myIter.Current()); + myPolygon3D = BRep_Tool::Polygon3D(myEdge, myLocation); + myTrsf = myLocation.Transformation(); + if (myPolygon3D.IsNull() || myPolygon3D->NbNodes() == 0) + { + resetEdge(); + continue; + } + + initEdge(); + myIter.Next(); + return; + } + + resetEdge(); +} + +// ======================================================================= +// function : initEdge +// purpose : +// ======================================================================= +void RWMesh_EdgeIterator::initEdge() +{ + initShape(); +} diff --git a/src/RWMesh/RWMesh_EdgeIterator.hxx b/src/RWMesh/RWMesh_EdgeIterator.hxx new file mode 100644 index 0000000000..b71c012866 --- /dev/null +++ b/src/RWMesh/RWMesh_EdgeIterator.hxx @@ -0,0 +1,118 @@ +// Copyright (c) 2025 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_EdgeIterator_HeaderFile +#define _RWMesh_EdgeIterator_HeaderFile + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class TDF_Label; + +//! Auxiliary class to iterate through edges. +//! Provides functionality to iterate through the edges of a shape. +//! It inherits from `RWMesh_ShapeIterator` and implements +//! methods to access and manipulate edge data. +class RWMesh_EdgeIterator : public RWMesh_ShapeIterator +{ +public: + //! Main constructor. + //! @param[in] theLabel The label of the shape. + //! @param[in] theLocation The location of the shape. + //! @param[in] theToMapColors Flag to indicate if colors should be mapped. + //! @param[in] theStyle The style of the shape. + Standard_EXPORT RWMesh_EdgeIterator(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const Standard_Boolean theToMapColors = false, + const XCAFPrs_Style& theStyle = XCAFPrs_Style()); + + //! Auxiliary constructor. + //! @param[in] theShape The shape to iterate. + //! @param[in] theStyle The style of the shape. + Standard_EXPORT RWMesh_EdgeIterator(const TopoDS_Shape& theShape, + const XCAFPrs_Style& theStyle = XCAFPrs_Style()); + + //! Return true if iterator points to the valid triangulation. + bool More() const Standard_OVERRIDE { return !myPolygon3D.IsNull(); } + + //! Find next value. + Standard_EXPORT void Next() Standard_OVERRIDE; + + //! Return current edge. + const TopoDS_Edge& Edge() const { return myEdge; } + + //! Return current edge. + const TopoDS_Shape& Shape() const Standard_OVERRIDE { return myEdge; } + + //! Return current edge data. + const Handle(Poly_Polygon3D)& Polygon3D() const { return myPolygon3D; } + + //! Return true if geometry data is defined. + bool IsEmpty() const Standard_OVERRIDE + { + return myPolygon3D.IsNull() || myPolygon3D->NbNodes() < 1; + } + +public: + //! Lower element index in current triangulation. + Standard_Integer ElemLower() const Standard_OVERRIDE { return 1; } + + //! Upper element index in current triangulation. + Standard_Integer ElemUpper() const Standard_OVERRIDE { return myPolygon3D->NbNodes(); } + +public: + //! Return number of nodes for the current edge. + Standard_Integer NbNodes() const Standard_OVERRIDE + { + return !myPolygon3D.IsNull() ? myPolygon3D->NbNodes() : 0; + } + + //! Lower node index in current triangulation. + Standard_Integer NodeLower() const Standard_OVERRIDE { return 1; } + + //! Upper node index in current triangulation. + Standard_Integer NodeUpper() const Standard_OVERRIDE { return myPolygon3D->NbNodes(); } + +public: + //! Return the node with specified index with applied transformation. + gp_Pnt node(const Standard_Integer theNode) const Standard_OVERRIDE + { + return myPolygon3D->Nodes().Value(theNode); + } + +private: + //! Reset information for current edge. + void resetEdge() + { + myPolygon3D.Nullify(); + myEdge.Nullify(); + resetShape(); + } + + //! Initialize edge properties. + void initEdge(); + +private: + TopoDS_Edge myEdge; //!< current edge + Handle(Poly_Polygon3D) myPolygon3D; //!< geometry of current edge +}; + +#endif // _RWMesh_EdgeIterator_HeaderFile diff --git a/src/RWMesh/RWMesh_FaceIterator.cxx b/src/RWMesh/RWMesh_FaceIterator.cxx index a7f6d58ae5..2cdc3c923d 100644 --- a/src/RWMesh/RWMesh_FaceIterator.cxx +++ b/src/RWMesh/RWMesh_FaceIterator.cxx @@ -24,33 +24,15 @@ // function : RWMesh_FaceIterator // purpose : // ======================================================================= -RWMesh_FaceIterator::RWMesh_FaceIterator (const TDF_Label& theLabel, - const TopLoc_Location& theLocation, - const Standard_Boolean theToMapColors, - const XCAFPrs_Style& theStyle) -: myDefStyle (theStyle), - myToMapColors (theToMapColors), - mySLTool (1, 1e-12), - myHasNormals (false), - myIsMirrored (false), - myHasFaceColor (false) +RWMesh_FaceIterator::RWMesh_FaceIterator(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const Standard_Boolean theToMapColors, + const XCAFPrs_Style& theStyle) + : RWMesh_ShapeIterator(theLabel, theLocation, TopAbs_FACE, theToMapColors, theStyle), + mySLTool(1, 1e-12), + myHasNormals(false), + myIsMirrored(false) { - TopoDS_Shape aShape; - if (!XCAFDoc_ShapeTool::GetShape (theLabel, aShape) - || aShape.IsNull()) - { - return; - } - - aShape.Location (theLocation, false); - myFaceIter.Init (aShape, TopAbs_FACE); - - if (theToMapColors) - { - dispatchStyles (theLabel, theLocation, theStyle); - myStyles.Bind (aShape, theStyle); - } - Next(); } @@ -58,115 +40,36 @@ RWMesh_FaceIterator::RWMesh_FaceIterator (const TDF_Label& theLabel, // function : RWMesh_FaceIterator // purpose : // ======================================================================= -RWMesh_FaceIterator::RWMesh_FaceIterator (const TopoDS_Shape& theShape, - const XCAFPrs_Style& theStyle) -: myDefStyle (theStyle), - myToMapColors (true), - mySLTool (1, 1e-12), - myHasNormals (false), - myIsMirrored (false), - myHasFaceColor (false) +RWMesh_FaceIterator::RWMesh_FaceIterator(const TopoDS_Shape& theShape, + const XCAFPrs_Style& theStyle) + : RWMesh_ShapeIterator(theShape, TopAbs_FACE, theStyle), + mySLTool(1, 1e-12), + myHasNormals(false), + myIsMirrored(false) { - if (theShape.IsNull()) - { - return; - } - - myFaceIter.Init (theShape, TopAbs_FACE); Next(); } -// ======================================================================= -// function : dispatchStyles -// purpose : -// ======================================================================= -void RWMesh_FaceIterator::dispatchStyles (const TDF_Label& theLabel, - const TopLoc_Location& theLocation, - const XCAFPrs_Style& theStyle) -{ - TopLoc_Location aDummyLoc; - XCAFPrs_IndexedDataMapOfShapeStyle aStyles; - XCAFPrs::CollectStyleSettings (theLabel, aDummyLoc, aStyles); - - Standard_Integer aNbTypes[TopAbs_SHAPE] = {}; - for (Standard_Integer aTypeIter = TopAbs_FACE; aTypeIter >= TopAbs_COMPOUND; --aTypeIter) - { - if (aTypeIter != TopAbs_FACE - && aNbTypes[aTypeIter] == 0) - { - continue; - } - - for (XCAFPrs_IndexedDataMapOfShapeStyle::Iterator aStyleIter (aStyles); aStyleIter.More(); aStyleIter.Next()) - { - const TopoDS_Shape& aKeyShape = aStyleIter.Key(); - const TopAbs_ShapeEnum aKeyShapeType = aKeyShape.ShapeType(); - if (aTypeIter == TopAbs_FACE) - { - ++aNbTypes[aKeyShapeType]; - } - if (aTypeIter != aKeyShapeType) - { - continue; - } - - XCAFPrs_Style aCafStyle = aStyleIter.Value(); - if (!aCafStyle.IsSetColorCurv() - && theStyle.IsSetColorCurv()) - { - aCafStyle.SetColorCurv (theStyle.GetColorCurv()); - } - if (!aCafStyle.IsSetColorSurf() - && theStyle.IsSetColorSurf()) - { - aCafStyle.SetColorSurf (theStyle.GetColorSurfRGBA()); - } - if (aCafStyle.Material().IsNull() - && !theStyle.Material().IsNull()) - { - aCafStyle.SetMaterial (theStyle.Material()); - } - - TopoDS_Shape aKeyShapeLocated = aKeyShape.Located (theLocation); - if (aKeyShapeType == TopAbs_FACE) - { - myStyles.Bind (aKeyShapeLocated, aCafStyle); - } - else - { - for (TopExp_Explorer aFaceIter (aKeyShapeLocated, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next()) - { - if (!myStyles.IsBound (aFaceIter.Current())) - { - myStyles.Bind (aFaceIter.Current(), aCafStyle); - } - } - } - } - } -} - // ======================================================================= // function : normal // purpose : // ======================================================================= -gp_Dir RWMesh_FaceIterator::normal (Standard_Integer theNode) const +gp_Dir RWMesh_FaceIterator::normal(Standard_Integer theNode) const { - gp_Dir aNormal (gp::DZ()); + gp_Dir aNormal(gp::DZ()); if (myPolyTriang->HasNormals()) { Graphic3d_Vec3 aNormVec3; - myPolyTriang->Normal (theNode, aNormVec3); + myPolyTriang->Normal(theNode, aNormVec3); if (aNormVec3.Modulus() != 0.0f) { - aNormal.SetCoord (aNormVec3.x(), aNormVec3.y(), aNormVec3.z()); + aNormal.SetCoord(aNormVec3.x(), aNormVec3.y(), aNormVec3.z()); } } - else if (myHasNormals - && myPolyTriang->HasUVNodes()) + else if (myHasNormals && myPolyTriang->HasUVNodes()) { - const gp_XY anUV = myPolyTriang->UVNode (theNode).XY(); - mySLTool.SetParameters (anUV.X(), anUV.Y()); + const gp_XY anUV = myPolyTriang->UVNode(theNode).XY(); + mySLTool.SetParameters(anUV.X(), anUV.Y()); if (mySLTool.IsNormalDefined()) { aNormal = mySLTool.Normal(); @@ -181,20 +84,19 @@ gp_Dir RWMesh_FaceIterator::normal (Standard_Integer theNode) const // ======================================================================= void RWMesh_FaceIterator::Next() { - for (; myFaceIter.More(); myFaceIter.Next()) + for (; myIter.More(); myIter.Next()) { - myFace = TopoDS::Face (myFaceIter.Current()); - myPolyTriang = BRep_Tool::Triangulation (myFace, myFaceLocation); - myTrsf = myFaceLocation.Transformation(); - if (myPolyTriang.IsNull() - || myPolyTriang->NbTriangles() == 0) + myFace = TopoDS::Face(myIter.Current()); + myPolyTriang = BRep_Tool::Triangulation(myFace, myLocation); + myTrsf = myLocation.Transformation(); + if (myPolyTriang.IsNull() || myPolyTriang->NbTriangles() == 0) { resetFace(); continue; } initFace(); - myFaceIter.Next(); + myIter.Next(); return; } @@ -207,43 +109,24 @@ void RWMesh_FaceIterator::Next() // ======================================================================= void RWMesh_FaceIterator::initFace() { - myHasNormals = false; - myHasFaceColor = false; - myIsMirrored = myTrsf.VectorialPart().Determinant() < 0.0; + myHasNormals = false; + myIsMirrored = myTrsf.VectorialPart().Determinant() < 0.0; if (myPolyTriang->HasNormals()) { myHasNormals = true; } if (myPolyTriang->HasUVNodes() && !myHasNormals) { - TopoDS_Face aFaceFwd = TopoDS::Face (myFace.Oriented (TopAbs_FORWARD)); - aFaceFwd.Location (TopLoc_Location()); + TopoDS_Face aFaceFwd = TopoDS::Face(myFace.Oriented(TopAbs_FORWARD)); + aFaceFwd.Location(TopLoc_Location()); TopLoc_Location aLoc; - if (!BRep_Tool::Surface (aFaceFwd, aLoc).IsNull()) + if (!BRep_Tool::Surface(aFaceFwd, aLoc).IsNull()) { - myFaceAdaptor.Initialize (aFaceFwd, false); - mySLTool.SetSurface (myFaceAdaptor); + myFaceAdaptor.Initialize(aFaceFwd, false); + mySLTool.SetSurface(myFaceAdaptor); myHasNormals = true; } } - if (!myToMapColors) - { - return; - } - - if (!myStyles.Find (myFace, myFaceStyle)) - { - myFaceStyle = myDefStyle; - } - if (!myFaceStyle.Material().IsNull()) - { - myHasFaceColor = true; - myFaceColor = myFaceStyle.Material()->BaseColor(); - } - else if (myFaceStyle.IsSetColorSurf()) - { - myHasFaceColor = true; - myFaceColor = myFaceStyle.GetColorSurfRGBA(); - } + initShape(); } diff --git a/src/RWMesh/RWMesh_FaceIterator.hxx b/src/RWMesh/RWMesh_FaceIterator.hxx index 8705862070..ebd98f728e 100644 --- a/src/RWMesh/RWMesh_FaceIterator.hxx +++ b/src/RWMesh/RWMesh_FaceIterator.hxx @@ -14,104 +14,111 @@ #ifndef _RWMesh_FaceIterator_HeaderFile #define _RWMesh_FaceIterator_HeaderFile +#include + #include -#include -#include #include -#include #include -#include -#include #include class TDF_Label; //! Auxiliary class to iterate through triangulated faces. -class RWMesh_FaceIterator +//! Class is designed to provide an interface for iterating over the faces +//! of a shape, specifically focusing on triangulated faces. +//! It inherits from the `RWMesh_ShapeIterator` base class and +//! extends its functionality to handle faces with triangulation data. +class RWMesh_FaceIterator : public RWMesh_ShapeIterator { public: - //! Main constructor. - Standard_EXPORT RWMesh_FaceIterator (const TDF_Label& theLabel, - const TopLoc_Location& theLocation, - const Standard_Boolean theToMapColors = false, - const XCAFPrs_Style& theStyle = XCAFPrs_Style()); + //! @param[in] theLabel Label containing the face data + //! @param[in] theLocation Location of the face + //! @param[in] theToMapColors Flag to indicate if colors should be mapped + //! @param[in] theStyle Style information for the face + Standard_EXPORT RWMesh_FaceIterator(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const Standard_Boolean theToMapColors = false, + const XCAFPrs_Style& theStyle = XCAFPrs_Style()); //! Auxiliary constructor. - Standard_EXPORT RWMesh_FaceIterator (const TopoDS_Shape& theShape, - const XCAFPrs_Style& theStyle = XCAFPrs_Style()); - - //! Return explored shape. - const TopoDS_Shape& ExploredShape() const { return myFaceIter.ExploredShape(); } + //! @param[in] theShape Shape containing the face data + //! @param[in] theStyle Style information for the face + Standard_EXPORT RWMesh_FaceIterator(const TopoDS_Shape& theShape, + const XCAFPrs_Style& theStyle = XCAFPrs_Style()); //! Return true if iterator points to the valid triangulation. - bool More() const { return !myPolyTriang.IsNull(); } + bool More() const Standard_OVERRIDE { return !myPolyTriang.IsNull(); } //! Find next value. - Standard_EXPORT void Next(); + Standard_EXPORT void Next() Standard_OVERRIDE; //! Return current face. const TopoDS_Face& Face() const { return myFace; } + //! Return current face. + const TopoDS_Shape& Shape() const Standard_OVERRIDE { return myFace; } + //! Return current face triangulation. const Handle(Poly_Triangulation)& Triangulation() const { return myPolyTriang; } //! Return true if mesh data is defined. - bool IsEmptyMesh() const + bool IsEmptyMesh() const { return IsEmpty(); } + + //! Return true if mesh data is defined. + bool IsEmpty() const Standard_OVERRIDE { return myPolyTriang.IsNull() - || (myPolyTriang->NbNodes() < 1 && myPolyTriang->NbTriangles() < 1); + || (myPolyTriang->NbNodes() < 1 && myPolyTriang->NbTriangles() < 1); } public: - //! Return face material. - const XCAFPrs_Style& FaceStyle() const { return myFaceStyle; } + const XCAFPrs_Style& FaceStyle() const { return myStyle; } //! Return TRUE if face color is set. - bool HasFaceColor() const { return myHasFaceColor; } + bool HasFaceColor() const { return myHasColor; } //! Return face color. - const Quantity_ColorRGBA& FaceColor() const { return myFaceColor; } + const Quantity_ColorRGBA& FaceColor() const { return myColor; } public: - //! Return number of elements of specific type for the current face. Standard_Integer NbTriangles() const { return myPolyTriang->NbTriangles(); } //! Lower element index in current triangulation. - Standard_Integer ElemLower() const { return 1; } + Standard_Integer ElemLower() const Standard_OVERRIDE { return 1; } //! Upper element index in current triangulation. - Standard_Integer ElemUpper() const { return myPolyTriang->NbTriangles(); } + Standard_Integer ElemUpper() const Standard_OVERRIDE { return myPolyTriang->NbTriangles(); } //! Return triangle with specified index with applied Face orientation. - Poly_Triangle TriangleOriented (Standard_Integer theElemIndex) const + Poly_Triangle TriangleOriented(Standard_Integer theElemIndex) const { - Poly_Triangle aTri = triangle (theElemIndex); + Poly_Triangle aTri = triangle(theElemIndex); if ((myFace.Orientation() == TopAbs_REVERSED) ^ myIsMirrored) { - return Poly_Triangle (aTri.Value (1), aTri.Value (3), aTri.Value (2)); + return Poly_Triangle(aTri.Value(1), aTri.Value(3), aTri.Value(2)); } return aTri; } public: - //! Return true if triangulation has defined normals. bool HasNormals() const { return myHasNormals; } //! Return true if triangulation has defined normals. bool HasTexCoords() const { return !myPolyTriang.IsNull() && myPolyTriang->HasUVNodes(); } - //! Return normal at specified node index with face transformation applied and face orientation applied. - gp_Dir NormalTransformed (Standard_Integer theNode) const + //! Return normal at specified node index with face transformation applied and face orientation + //! applied. + gp_Dir NormalTransformed(Standard_Integer theNode) const { - gp_Dir aNorm = normal (theNode); + gp_Dir aNorm = normal(theNode); if (myTrsf.Form() != gp_Identity) { - aNorm.Transform (myTrsf); + aNorm.Transform(myTrsf); } if (myFace.Orientation() == TopAbs_REVERSED) { @@ -121,87 +128,61 @@ public: } //! Return number of nodes for the current face. - Standard_Integer NbNodes() const + Standard_Integer NbNodes() const Standard_OVERRIDE { - return !myPolyTriang.IsNull() - ? myPolyTriang->NbNodes() - : 0; + return !myPolyTriang.IsNull() ? myPolyTriang->NbNodes() : 0; } //! Lower node index in current triangulation. - Standard_Integer NodeLower() const { return 1; } + Standard_Integer NodeLower() const Standard_OVERRIDE { return 1; } //! Upper node index in current triangulation. - Standard_Integer NodeUpper() const { return myPolyTriang->NbNodes(); } - - //! Return the node with specified index with applied transformation. - gp_Pnt NodeTransformed (const Standard_Integer theNode) const - { - gp_Pnt aNode = node (theNode); - aNode.Transform (myTrsf); - return aNode; - } + Standard_Integer NodeUpper() const Standard_OVERRIDE { return myPolyTriang->NbNodes(); } //! Return texture coordinates for the node. - gp_Pnt2d NodeTexCoord (const Standard_Integer theNode) const + gp_Pnt2d NodeTexCoord(const Standard_Integer theNode) const { - return myPolyTriang->HasUVNodes() ? myPolyTriang->UVNode (theNode) : gp_Pnt2d(); + return myPolyTriang->HasUVNodes() ? myPolyTriang->UVNode(theNode) : gp_Pnt2d(); } public: - //! Return the node with specified index with applied transformation. - gp_Pnt node (const Standard_Integer theNode) const { return myPolyTriang->Node (theNode); } + gp_Pnt node(const Standard_Integer theNode) const Standard_OVERRIDE + { + return myPolyTriang->Node(theNode); + } //! Return normal at specified node index without face transformation applied. - Standard_EXPORT gp_Dir normal (Standard_Integer theNode) const; + Standard_EXPORT gp_Dir normal(Standard_Integer theNode) const; //! Return triangle with specified index. - Poly_Triangle triangle (Standard_Integer theElemIndex) const { return myPolyTriang->Triangle (theElemIndex); } + Poly_Triangle triangle(Standard_Integer theElemIndex) const + { + return myPolyTriang->Triangle(theElemIndex); + } private: - - //! Dispatch face styles. - void dispatchStyles (const TDF_Label& theLabel, - const TopLoc_Location& theLocation, - const XCAFPrs_Style& theStyle); - //! Reset information for current face. void resetFace() { myPolyTriang.Nullify(); myFace.Nullify(); myHasNormals = false; - myHasFaceColor = false; - myFaceColor = Quantity_ColorRGBA(); - myFaceStyle = XCAFPrs_Style(); + resetShape(); } //! Initialize face properties. void initFace(); private: - - NCollection_DataMap - myStyles; //!< Face -> Style map -// clang-format off - XCAFPrs_Style myDefStyle; //!< default style for faces without dedicated style - Standard_Boolean myToMapColors; //!< flag to dispatch styles - - TopExp_Explorer myFaceIter; //!< face explorer - TopoDS_Face myFace; //!< current face - Handle(Poly_Triangulation) myPolyTriang; //!< triangulation of current face - TopLoc_Location myFaceLocation; //!< current face location - mutable BRepLProp_SLProps mySLTool; //!< auxiliary tool for fetching normals from surface - BRepAdaptor_Surface myFaceAdaptor; //!< surface adaptor for fetching normals from surface - Standard_Boolean myHasNormals; //!< flag indicating that current face has normals - gp_Trsf myTrsf; //!< current face transformation - Standard_Boolean myIsMirrored; //!< flag indicating that face triangles should be mirrored - XCAFPrs_Style myFaceStyle; //!< current face style - Quantity_ColorRGBA myFaceColor; //!< current face color - Standard_Boolean myHasFaceColor; //!< flag indicating that current face has assigned color -// clang-format on - + // clang-format off + TopoDS_Face myFace; //!< current face + Handle(Poly_Triangulation) myPolyTriang; //!< triangulation of current face + mutable BRepLProp_SLProps mySLTool; //!< auxiliary tool for fetching normals from surface + BRepAdaptor_Surface myFaceAdaptor; //!< surface adaptor for fetching normals from surface + Standard_Boolean myHasNormals; //!< flag indicating that current face has normals + Standard_Boolean myIsMirrored; //!< flag indicating that face triangles should be mirrored + // clang-format on }; #endif // _RWMesh_FaceIterator_HeaderFile diff --git a/src/RWMesh/RWMesh_ShapeIterator.cxx b/src/RWMesh/RWMesh_ShapeIterator.cxx new file mode 100644 index 0000000000..63c3fccaf3 --- /dev/null +++ b/src/RWMesh/RWMesh_ShapeIterator.cxx @@ -0,0 +1,163 @@ +// Copyright (c) 2025 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 +#include +#include + +// ======================================================================= +// function : RWMesh_ShapeIterator +// purpose : +// ======================================================================= +RWMesh_ShapeIterator::RWMesh_ShapeIterator(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const TopAbs_ShapeEnum theShapeType, + const Standard_Boolean theToMapColors, + const XCAFPrs_Style& theStyle) + : myDefStyle(theStyle), + myToMapColors(theToMapColors), + myShapeType(theShapeType), + myHasColor(false) +{ + TopoDS_Shape aShape; + if (!XCAFDoc_ShapeTool::GetShape(theLabel, aShape) || aShape.IsNull()) + { + return; + } + + aShape.Location(theLocation, false); + myIter.Init(aShape, myShapeType); + + if (theToMapColors) + { + dispatchStyles(theLabel, theLocation, theStyle); + myStyles.Bind(aShape, theStyle); + } +} + +// ======================================================================= +// function : RWMesh_ShapeIterator +// purpose : +// ======================================================================= +RWMesh_ShapeIterator::RWMesh_ShapeIterator(const TopoDS_Shape& theShape, + const TopAbs_ShapeEnum theShapeType, + const XCAFPrs_Style& theStyle) + : myDefStyle(theStyle), + myToMapColors(true), + myShapeType(theShapeType), + myHasColor(false) +{ + if (theShape.IsNull()) + { + return; + } + myIter.Init(theShape, myShapeType); +} + +// ======================================================================= +// function : dispatchStyles +// purpose : +// ======================================================================= +void RWMesh_ShapeIterator::dispatchStyles(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const XCAFPrs_Style& theStyle) +{ + TopLoc_Location aDummyLoc; + XCAFPrs_IndexedDataMapOfShapeStyle aStyles; + XCAFPrs::CollectStyleSettings(theLabel, aDummyLoc, aStyles); + + Standard_Integer aNbTypes[TopAbs_SHAPE] = {}; + for (Standard_Integer aTypeIter = myShapeType; aTypeIter >= TopAbs_COMPOUND; --aTypeIter) + { + if (aTypeIter != myShapeType && aNbTypes[aTypeIter] == 0) + { + continue; + } + + for (XCAFPrs_IndexedDataMapOfShapeStyle::Iterator aStyleIter(aStyles); aStyleIter.More(); + aStyleIter.Next()) + { + const TopoDS_Shape& aKeyShape = aStyleIter.Key(); + const TopAbs_ShapeEnum aKeyShapeType = aKeyShape.ShapeType(); + if (aTypeIter == myShapeType) + { + ++aNbTypes[aKeyShapeType]; + } + if (aTypeIter != aKeyShapeType) + { + continue; + } + + XCAFPrs_Style aCafStyle = aStyleIter.Value(); + if (!aCafStyle.IsSetColorCurv() && theStyle.IsSetColorCurv()) + { + aCafStyle.SetColorCurv(theStyle.GetColorCurv()); + } + if (!aCafStyle.IsSetColorSurf() && theStyle.IsSetColorSurf()) + { + aCafStyle.SetColorSurf(theStyle.GetColorSurfRGBA()); + } + if (aCafStyle.Material().IsNull() && !theStyle.Material().IsNull()) + { + aCafStyle.SetMaterial(theStyle.Material()); + } + + TopoDS_Shape aKeyShapeLocated = aKeyShape.Located(theLocation); + if (aKeyShapeType == myShapeType) + { + myStyles.Bind(aKeyShapeLocated, aCafStyle); + } + else + { + for (TopExp_Explorer aShapeIter(aKeyShapeLocated, myShapeType); aShapeIter.More(); + aShapeIter.Next()) + { + if (!myStyles.IsBound(aShapeIter.Current())) + { + myStyles.Bind(aShapeIter.Current(), aCafStyle); + } + } + } + } + } +} + +// ======================================================================= +// function : initEdge +// purpose : +// ======================================================================= +void RWMesh_ShapeIterator::initShape() +{ + myHasColor = false; + if (!myToMapColors) + { + return; + } + if (!myStyles.Find(Shape(), myStyle)) + { + myStyle = myDefStyle; + } + if (!myStyle.Material().IsNull()) + { + myHasColor = true; + myColor = myStyle.Material()->BaseColor(); + } + else if (myStyle.IsSetColorSurf()) + { + myHasColor = true; + myColor = myStyle.GetColorSurfRGBA(); + } +} \ No newline at end of file diff --git a/src/RWMesh/RWMesh_ShapeIterator.hxx b/src/RWMesh/RWMesh_ShapeIterator.hxx new file mode 100644 index 0000000000..6efdfa915c --- /dev/null +++ b/src/RWMesh/RWMesh_ShapeIterator.hxx @@ -0,0 +1,131 @@ +// Copyright (c) 2025 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_ShapeIterator_HeaderFile +#define _RWMesh_ShapeIterator_HeaderFile + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class TDF_Label; + +//! This is a virtual base class for other shape iterators. +//! Provides an abstract interface for iterating over the elements of a shape. +//! It defines a set of pure virtual methods that must be implemented by +//! derived classes to handle specific types of shapes and their elements. +class RWMesh_ShapeIterator +{ +public: + //! Return explored shape. + const TopoDS_Shape& ExploredShape() const { return myIter.ExploredShape(); } + + //! Return shape. + Standard_EXPORT virtual const TopoDS_Shape& Shape() const = 0; + + //! Return true if iterator points to the valid triangulation. + Standard_EXPORT virtual bool More() const = 0; + + //! Find next value. + Standard_EXPORT virtual void Next() = 0; + + //! Return true if mesh data is defined. + Standard_EXPORT virtual bool IsEmpty() const = 0; + + //! Return shape material. + const XCAFPrs_Style& Style() const { return myStyle; } + + //! Return TRUE if shape color is set. + bool HasColor() const { return myHasColor; } + + //! Return shape color. + const Quantity_ColorRGBA& Color() const { return myColor; } + + //! Lower element index in current triangulation. + Standard_EXPORT virtual Standard_Integer ElemLower() const = 0; + + //! Upper element index in current triangulation. + Standard_EXPORT virtual Standard_Integer ElemUpper() const = 0; + + //! Return number of nodes for the current shape. + Standard_EXPORT virtual Standard_Integer NbNodes() const = 0; + + //! Lower node index in current shape. + Standard_EXPORT virtual Standard_Integer NodeLower() const = 0; + + //! Upper node index in current shape. + Standard_EXPORT virtual Standard_Integer NodeUpper() const = 0; + + //! Return the node with specified index with applied transformation. + gp_Pnt NodeTransformed(const Standard_Integer theNode) const + { + gp_Pnt aNode = node(theNode); + aNode.Transform(myTrsf); + return aNode; + } + +protected: + //! Return the node with specified index with applied transformation. + virtual gp_Pnt node(const Standard_Integer theNode) const = 0; + + //! Main constructor. + RWMesh_ShapeIterator(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const TopAbs_ShapeEnum theShapeType, + const Standard_Boolean theToMapColors = false, + const XCAFPrs_Style& theStyle = XCAFPrs_Style()); + + //! Auxiliary constructor. + RWMesh_ShapeIterator(const TopoDS_Shape& theShape, + const TopAbs_ShapeEnum theShapeType, + const XCAFPrs_Style& theStyle = XCAFPrs_Style()); + + //! Dispatch shape styles. + void dispatchStyles(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const XCAFPrs_Style& theStyle); + + //! Reset information for current shape. + void resetShape() + { + myHasColor = false; + myColor = Quantity_ColorRGBA(); + myStyle = XCAFPrs_Style(); + } + + //! Initialize shape properties. + void initShape(); + +protected: + NCollection_DataMap + myStyles; //!< Shape -> Style map + XCAFPrs_Style myDefStyle; //!< default style for shapes without dedicated style + Standard_Boolean myToMapColors; //!< flag to dispatch styles + + TopExp_Explorer myIter; //!< shape explorer + TopLoc_Location myLocation; //!< current shape location + gp_Trsf myTrsf; //!< current shape transformation + XCAFPrs_Style myStyle; //!< current shape style + Quantity_ColorRGBA myColor; //!< current shape color + TopAbs_ShapeEnum myShapeType; //!< type of shape + Standard_Boolean myHasColor; //!< flag indicating that current shape has assigned color +}; + +#endif // _RWMesh_ShapeIterator_HeaderFile diff --git a/src/RWMesh/RWMesh_VertexIterator.cxx b/src/RWMesh/RWMesh_VertexIterator.cxx new file mode 100644 index 0000000000..ce9d3deb47 --- /dev/null +++ b/src/RWMesh/RWMesh_VertexIterator.cxx @@ -0,0 +1,78 @@ +// Copyright (c) 2025 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 +#include +#include +#include + +// ======================================================================= +// function : RWMesh_VertexIterator +// purpose : +// ======================================================================= +RWMesh_VertexIterator::RWMesh_VertexIterator(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const Standard_Boolean theToMapColors, + const XCAFPrs_Style& theStyle) + : RWMesh_ShapeIterator(theLabel, theLocation, TopAbs_VERTEX, theToMapColors, theStyle) +{ + Next(); +} + +// ======================================================================= +// function : RWMesh_VertexIterator +// purpose : +// ======================================================================= +RWMesh_VertexIterator::RWMesh_VertexIterator(const TopoDS_Shape& theShape, + const XCAFPrs_Style& theStyle) + : RWMesh_ShapeIterator(theShape, TopAbs_VERTEX, theStyle) +{ + Next(); +} + +// ======================================================================= +// function : Next +// purpose : +// ======================================================================= +void RWMesh_VertexIterator::Next() +{ + for (; myIter.More(); myIter.Next()) + { + myVertex = TopoDS::Vertex(myIter.Current()); + myPoint = BRep_Tool::Pnt(myVertex); + myTrsf = myLocation.Transformation(); + if (myVertex.IsNull()) + { + resetVertex(); + continue; + } + + initVertex(); + myIter.Next(); + return; + } + + resetVertex(); +} + +// ======================================================================= +// function : initEdge +// purpose : +// ======================================================================= +void RWMesh_VertexIterator::initVertex() +{ + initShape(); +} diff --git a/src/RWMesh/RWMesh_VertexIterator.hxx b/src/RWMesh/RWMesh_VertexIterator.hxx new file mode 100644 index 0000000000..c57945a300 --- /dev/null +++ b/src/RWMesh/RWMesh_VertexIterator.hxx @@ -0,0 +1,108 @@ +// Copyright (c) 2025 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_VertexIterator_HeaderFile +#define _RWMesh_VertexIterator_HeaderFile + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class TDF_Label; + +//! Auxiliary class to iterate through vertices. +//! Provides functionality to iterate through the vertices of a shape. +//! It inherits from `RWMesh_ShapeIterator` and implements +//! methods to access and manipulate vertex data. +class RWMesh_VertexIterator : public RWMesh_ShapeIterator +{ +public: + //! Main constructor. + //! @param[in] theLabel The label of the shape. + //! @param[in] theLocation The location of the shape. + //! @param[in] theToMapColors Flag to indicate if colors should be mapped. + //! @param[in] theStyle The style of the shape. + Standard_EXPORT RWMesh_VertexIterator(const TDF_Label& theLabel, + const TopLoc_Location& theLocation, + const Standard_Boolean theToMapColors = false, + const XCAFPrs_Style& theStyle = XCAFPrs_Style()); + + //! Auxiliary constructor. + //! @param[in] theShape The shape to iterate. + //! @param[in] theStyle The style of the shape. + Standard_EXPORT RWMesh_VertexIterator(const TopoDS_Shape& theShape, + const XCAFPrs_Style& theStyle = XCAFPrs_Style()); + + //! Return true if iterator points to the valid triangulation. + bool More() const Standard_OVERRIDE { return !myVertex.IsNull(); } + + //! Find next value. + Standard_EXPORT void Next() Standard_OVERRIDE; + + //! Return current edge. + const TopoDS_Vertex& Vertex() const { return myVertex; } + + //! Return current vertex. + const TopoDS_Shape& Shape() const Standard_OVERRIDE { return myVertex; } + + //! Return current vertex data. + const gp_Pnt& Point() const { return myPoint; } + + //! Return true if geometry data is defined. + bool IsEmpty() const Standard_OVERRIDE { return myVertex.IsNull(); } + +public: + //! Lower element index in current triangulation. + Standard_Integer ElemLower() const Standard_OVERRIDE { return 1; } + + //! Upper element index in current triangulation. + Standard_Integer ElemUpper() const Standard_OVERRIDE { return 1; } + +public: + //! Return number of nodes for the current edge. + Standard_Integer NbNodes() const Standard_OVERRIDE { return 1; } + + //! Lower node index in current triangulation. + Standard_Integer NodeLower() const Standard_OVERRIDE { return 1; } + + //! Upper node index in current triangulation. + Standard_Integer NodeUpper() const Standard_OVERRIDE { return 1; } + +public: + //! Return the node with specified index with applied transformation. + gp_Pnt node(const Standard_Integer /*theNode*/) const Standard_OVERRIDE { return myPoint; } + +private: + //! Reset information for current vertex. + void resetVertex() + { + myVertex.Nullify(); + resetShape(); + } + + //! Initialize vertex properties. + void initVertex(); + +private: + TopoDS_Vertex myVertex; //!< current vertex + gp_Pnt myPoint; //!< geometry of current vertex +}; + +#endif // _RWMesh_VertexIterator_HeaderFile