From 0bab2704ae134830197b63708349e51f5a875564 Mon Sep 17 00:00:00 2001 From: ona Date: Fri, 1 Jul 2022 11:30:01 +0300 Subject: [PATCH] 0031080: Data Exchange, STL reader - improve API for reading multi-domain STL files reading of multidomain stl files into separate Poly_Triangulation objects --- src/RWStl/RWStl.cxx | 47 ++++++++++++++++++++++ src/RWStl/RWStl.hxx | 13 +++++- src/RWStl/RWStl_Reader.cxx | 6 +++ src/RWStl/RWStl_Reader.hxx | 6 ++- src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx | 62 ++++++++++++++++++++++++----- tests/bugs/stlvrml/bug31080 | 44 ++++++++++++++++++++ 6 files changed, 166 insertions(+), 12 deletions(-) create mode 100644 tests/bugs/stlvrml/bug31080 diff --git a/src/RWStl/RWStl.cxx b/src/RWStl/RWStl.cxx index 86eaeb601e..49807eb7a2 100644 --- a/src/RWStl/RWStl.cxx +++ b/src/RWStl/RWStl.cxx @@ -99,11 +99,42 @@ namespace return aPoly; } + protected: + void Clear() + { + myNodes.Clear(); + myTriangles.Clear(); + } + private: NCollection_Vector myNodes; NCollection_Vector myTriangles; }; + class MultiDomainReader : public Reader + { + public: + //! Add new solid + //! Add triangulation to triangulation list for multi-domain case + virtual void AddSolid() Standard_OVERRIDE + { + if (Handle(Poly_Triangulation) aCurrentTri = GetTriangulation()) + { + myTriangulationList.Append(aCurrentTri); + } + Clear(); + } + + //! Returns triangulation list for multi-domain case + NCollection_Sequence& ChangeTriangulationList() + { + return myTriangulationList; + } + + private: + NCollection_Sequence myTriangulationList; + }; + } //============================================================================= @@ -122,6 +153,22 @@ Handle(Poly_Triangulation) RWStl::ReadFile (const Standard_CString theFile, return aReader.GetTriangulation(); } +//============================================================================= +//function : ReadFile +//purpose : +//============================================================================= +void RWStl::ReadFile(const Standard_CString theFile, + const Standard_Real theMergeAngle, + NCollection_Sequence& theTriangList, + const Message_ProgressRange& theProgress) +{ + MultiDomainReader aReader; + aReader.SetMergeAngle (theMergeAngle); + aReader.Read (theFile, theProgress); + theTriangList.Clear(); + theTriangList.Append (aReader.ChangeTriangulationList()); +} + //============================================================================= //function : ReadFile //purpose : diff --git a/src/RWStl/RWStl.hxx b/src/RWStl/RWStl.hxx index d513ce1a69..f329bba495 100644 --- a/src/RWStl/RWStl.hxx +++ b/src/RWStl/RWStl.hxx @@ -20,6 +20,7 @@ #include #include #include +#include //! This class provides methods to read and write triangulation from / to the STL files. class RWStl @@ -61,7 +62,17 @@ public: Standard_EXPORT static Handle(Poly_Triangulation) ReadFile (const Standard_CString theFile, const Standard_Real theMergeAngle, const Message_ProgressRange& theProgress = Message_ProgressRange()); - + + //! Read specified STL file and fills triangulation list for multi-domain case. + //! @param[in] theFile file path to read + //! @param[in] theMergeAngle maximum angle in radians between triangles to merge equal nodes; M_PI/2 means ignore angle + //! @param[out] theTriangList triangulation list for multi-domain case + //! @param[in] theProgress progress indicator + Standard_EXPORT static void ReadFile(const Standard_CString theFile, + const Standard_Real theMergeAngle, + NCollection_Sequence& theTriangList, + const Message_ProgressRange& theProgress = Message_ProgressRange()); + //! Read triangulation from a binary STL file //! In case of error, returns Null handle. Standard_EXPORT static Handle(Poly_Triangulation) ReadBinary (const OSD_Path& thePath, diff --git a/src/RWStl/RWStl_Reader.cxx b/src/RWStl/RWStl_Reader.cxx index ad7ad321ed..10801140fc 100644 --- a/src/RWStl/RWStl_Reader.cxx +++ b/src/RWStl/RWStl_Reader.cxx @@ -180,6 +180,7 @@ Standard_Boolean RWStl_Reader::Read (const char* theFile, } } *aStream >> std::ws; // skip any white spaces + AddSolid(); } return ! aStream->fail(); } @@ -300,6 +301,11 @@ Standard_Boolean RWStl_Reader::ReadAscii (Standard_IStream& theStream, // skip header "solid ..." aLine = theBuffer.ReadLine (theStream, aLineLen); + // skip empty lines + while (aLine && !*aLine) + { + aLine = theBuffer.ReadLine (theStream, aLineLen); + } if (aLine == NULL) { Message::SendFail ("Error: premature end of file"); diff --git a/src/RWStl/RWStl_Reader.hxx b/src/RWStl/RWStl_Reader.hxx index 0a6955b748..d09098773a 100644 --- a/src/RWStl/RWStl_Reader.hxx +++ b/src/RWStl/RWStl_Reader.hxx @@ -39,7 +39,8 @@ public: Standard_EXPORT RWStl_Reader(); //! Reads data from STL file (either binary or Ascii). - //! This function supports reading multi-domain STL files formed by concatenation of several "plain" files. + //! This function supports reading multi-domain STL files formed by concatenation + //! of several "plain" files. //! The mesh nodes are not merged between domains. //! Unicode paths can be given in UTF-8 encoding. //! Format is recognized automatically by analysis of the file header. @@ -84,6 +85,9 @@ public: //! Should create new triangle built on specified nodes in the target model. virtual void AddTriangle (Standard_Integer theN1, Standard_Integer theN2, Standard_Integer theN3) = 0; + //! Callback function to be implemented in descendant. + //! Should create a new triangulation for a solid in multi-domain case. + virtual void AddSolid() {} public: //! Return merge tolerance; M_PI/2 by default - all nodes are merged regardless angle between triangles. diff --git a/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx b/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx index 7976a23ecb..f0c2c917e0 100644 --- a/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx +++ b/src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx @@ -626,6 +626,7 @@ static Standard_Integer readstl(Draw_Interpretor& theDI, { TCollection_AsciiString aShapeName, aFilePath; bool toCreateCompOfTris = false; + bool anIsMulti = false; double aMergeAngle = M_PI / 2.0; for (Standard_Integer anArgIter = 1; anArgIter < theArgc; ++anArgIter) { @@ -648,6 +649,15 @@ static Standard_Integer readstl(Draw_Interpretor& theDI, ++anArgIter; } } + else if (anArg == "-multi") + { + anIsMulti = true; + if (anArgIter + 1 < theArgc + && Draw::ParseOnOff (theArgv[anArgIter + 1], anIsMulti)) + { + ++anArgIter; + } + } else if (anArg == "-mergeangle" || anArg == "-smoothangle" || anArg == "-nomergeangle" @@ -689,15 +699,46 @@ static Standard_Integer readstl(Draw_Interpretor& theDI, TopoDS_Shape aShape; if (!toCreateCompOfTris) { - // Read STL file to the triangulation. - Handle(Draw_ProgressIndicator) aProgress = new Draw_ProgressIndicator (theDI, 1); - Handle(Poly_Triangulation) aTriangulation = RWStl::ReadFile (aFilePath.ToCString(), aMergeAngle, aProgress->Start()); + Handle(Draw_ProgressIndicator) aProgress = new Draw_ProgressIndicator (theDI,1); + if(anIsMulti) + { + NCollection_Sequence aTriangList; + // Read STL file to the triangulation list. + RWStl::ReadFile(aFilePath.ToCString(),aMergeAngle,aTriangList,aProgress->Start()); + BRep_Builder aB; + TopoDS_Face aFace; + if (aTriangList.Size() == 1) + { + aB.MakeFace (aFace); + aB.UpdateFace (aFace,aTriangList.First()); + aShape = aFace; + } + else + { + TopoDS_Compound aCmp; + aB.MakeCompound (aCmp); + + NCollection_Sequence::Iterator anIt (aTriangList); + for (; anIt.More(); anIt.Next()) + { + aB.MakeFace (aFace); + aB.UpdateFace (aFace,anIt.Value()); + aB.Add (aCmp,aFace); + } + aShape = aCmp; + } + } + else + { + // Read STL file to the triangulation. + Handle(Poly_Triangulation) aTriangulation = RWStl::ReadFile (aFilePath.ToCString(),aMergeAngle,aProgress->Start()); - TopoDS_Face aFace; - BRep_Builder aB; - aB.MakeFace (aFace); - aB.UpdateFace (aFace, aTriangulation); - aShape = aFace; + TopoDS_Face aFace; + BRep_Builder aB; + aB.MakeFace (aFace); + aB.UpdateFace (aFace,aTriangulation); + aShape = aFace; + } } else { @@ -2435,11 +2476,12 @@ void XSDRAWSTLVRML::InitCommands (Draw_Interpretor& theCommands) theCommands.Add ("writevrml", "shape file [version VRML#1.0/VRML#2.0 (1/2): 2 by default] [representation shaded/wireframe/both (0/1/2): 1 by default]",__FILE__,writevrml,g); theCommands.Add ("writestl", "shape file [ascii/binary (0/1) : 1 by default] [InParallel (0/1) : 0 by default]",__FILE__,writestl,g); theCommands.Add ("readstl", - "readstl shape file [-brep] [-mergeAngle Angle]" + "readstl shape file [-brep] [-mergeAngle Angle] [-multi]" "\n\t\t: Reads STL file and creates a new shape with specified name." "\n\t\t: When -brep is specified, creates a Compound of per-triangle Faces." "\n\t\t: Single triangulation-only Face is created otherwise (default)." - "\n\t\t: -mergeAngle specifies maximum angle in degrees between triangles to merge equal nodes; disabled by default.", + "\n\t\t: -mergeAngle specifies maximum angle in degrees between triangles to merge equal nodes; disabled by default." + "\n\t\t: -multi creates a face per solid in multi-domain files; ignored when -brep is set.", __FILE__, readstl, g); theCommands.Add ("loadvrml" , "shape file",__FILE__,loadvrml,g); theCommands.Add ("ReadObj", diff --git a/tests/bugs/stlvrml/bug31080 b/tests/bugs/stlvrml/bug31080 new file mode 100644 index 0000000000..2108c9a0c7 --- /dev/null +++ b/tests/bugs/stlvrml/bug31080 @@ -0,0 +1,44 @@ +puts "========" +puts "0031080: Data Exchange, STL reader - improve API for reading multi-domain STL files" +puts "========" +puts "" + +pload ALL + +# create two boxes with mesh +box b1 5 5 5 +box b2 5 5 5 +ttranslate b2 10 10 10 +incmesh b1 0.1 +incmesh b2 0.1 + +# write each box to Ascii STL +writestl b1 $imagedir/${casename}_1.stl 0 +writestl b2 $imagedir/${casename}_2.stl 0 + +set aTmpStl "${imagedir}/${casename}_cat.stl" +file delete $aTmpStl +set file_res [open $aTmpStl a+] + +# cat each stl files content to file_res +set file_stl [open $imagedir/${casename}_1.stl r] +set buffer [read $file_stl]; +puts $file_res $buffer +close $file_stl + +set file_stl [open $imagedir/${casename}_2.stl r] +set buffer [read $file_stl]; +puts $file_res $buffer +close $file_stl +close $file_res + +# load multi-domain STL +readstl result ${imagedir}/${casename}_cat.stl -multi + +vinit +vdisplay result -dispmode 1 +vfit + +checknbshapes result -face 2 -compound 1 +checktrinfo result -tri 24 -nod 16 +checkview -screenshot -3d -path ${imagedir}/${test_image}.png -- 2.39.5