0031080: Data Exchange, STL reader - improve API for reading multi-domain STL files
authorona <olga.nikonova@opencascade.com>
Fri, 1 Jul 2022 08:30:01 +0000 (11:30 +0300)
committersmoskvin <smoskvin@opencascade.com>
Fri, 15 Jul 2022 15:22:10 +0000 (18:22 +0300)
reading of multidomain stl files into separate Poly_Triangulation objects

src/RWStl/RWStl.cxx
src/RWStl/RWStl.hxx
src/RWStl/RWStl_Reader.cxx
src/RWStl/RWStl_Reader.hxx
src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx
tests/bugs/stlvrml/bug31080 [new file with mode: 0644]

index 86eaeb601e83a1468461097f9f7880352f59d6cc..49807eb7a2f4f3aefc211ef71ef149f7561bccb3 100644 (file)
@@ -99,11 +99,42 @@ namespace
       return aPoly;
     }
 
+  protected:
+    void Clear()
+    {
+      myNodes.Clear();
+      myTriangles.Clear();
+    }
+
   private:
     NCollection_Vector<gp_XYZ> myNodes;
     NCollection_Vector<Poly_Triangle> 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<Handle(Poly_Triangulation)>& ChangeTriangulationList()
+    {
+      return myTriangulationList;
+    }
+
+  private:
+    NCollection_Sequence<Handle(Poly_Triangulation)> 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<Handle(Poly_Triangulation)>& theTriangList,
+                     const Message_ProgressRange& theProgress)
+{
+  MultiDomainReader aReader;
+  aReader.SetMergeAngle (theMergeAngle);
+  aReader.Read (theFile, theProgress);
+  theTriangList.Clear();
+  theTriangList.Append (aReader.ChangeTriangulationList());
+}
+
 //=============================================================================
 //function : ReadFile
 //purpose  :
index d513ce1a691f1812d123f88323496843b90d7e9e..f329bba495a1013250742406c8c173e7ae1eb6bc 100644 (file)
@@ -20,6 +20,7 @@
 #include <Poly_Triangulation.hxx>
 #include <Standard_Macro.hxx>
 #include <Message_ProgressScope.hxx>
+#include <NCollection_Sequence.hxx>
 
 //! 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<Handle(Poly_Triangulation)>& 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,
index ad7ad321ede406bdca49425300ea10be4a029245..10801140fcdec22e51934e3d83db18bbf2df3eb7 100644 (file)
@@ -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");
index 0a6955b748a1ad6cc38475c50d902d27912a3f73..d09098773a6188a89c106b9ea7246efd7e6c50c2 100644 (file)
@@ -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.
index 7976a23ecb8aa0b9caf23dc1c0e11bc85ae95d03..f0c2c917e004ea3e3f1d8e938b3b821ba678010e 100644 (file)
@@ -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<Handle(Poly_Triangulation)> 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<Handle(Poly_Triangulation)>::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 (file)
index 0000000..2108c9a
--- /dev/null
@@ -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