0032086: Visualization - support deferred data loading
authorosa <osa@opencascade.com>
Fri, 26 Feb 2021 15:01:11 +0000 (18:01 +0300)
committerbugmaster <bugmaster@opencascade.com>
Sat, 27 Mar 2021 10:46:02 +0000 (13:46 +0300)
1) Extend Poly_Triangulation by mesh purpose, possibility to be cleared and late-load deferred data interfaces.
2) Update BRep_TFace to store list of triangulations istead of single one. And also active one. Update getter and setter of single triangulation and add new methods to interaction with whole triangulations list.
3) Update BRep_Tool to get single triangulation of face according to the input mesh purpose or whole triangulations list.
4) Update BRep_Builder to make face by not only single triangulation but whole triangulations list with specified active one.
5) Add new methods to BRepTools to interact with shape triangulations (Load/Unload/Activate/LoadAll/UnloadAllTriangulation(s))
6) Add new 'tlateload'command for shape to load/unload/activate triangulations.
7) Update 'trinfo' command by '-lods' options to print detailaed information about LODs of this shape
8) Support empty triangulations by selection. Use bounding box selection in this case.
9) Add new 'outdisplist' option to XDispaly command to print list of displayed objects to output variable but not to theDI
10) Add new '-noecho' option to vdisplay command to skip printing of displayed objects to theDI
11) Create new RWMesh_TriangulationSource as mesh data wrapper for delayed triangulation loading.
12) Create new RWMesh_TriangulationReader as base interface for reading primitive array from the buffer.
13) Cache nodes/triangles number defined in glTF file
14) Use RWMesh_TriangulationSource class as base of RWGltf_GltfLatePrimitiveArray one and RWMesh_TriangulationReader class as base of RWGltf_TriangulationReader one
15) Add possibilty to support of LODs by glTF reader. It is possible to skip data loading and load them later
16) Add new '-skiplateloading' (to skip triangulation loading), '-keeplate' (to keep information about deferred storage to load/unload triangulation later),
'-toprintdebuginfo' (to print additional debug information) options to ReadGltf command
17) Add new test of glTF late loading

46 files changed:
src/BRep/BRep_Builder.cxx
src/BRep/BRep_Builder.hxx
src/BRep/BRep_TFace.cxx
src/BRep/BRep_TFace.hxx
src/BRep/BRep_TFace.lxx [deleted file]
src/BRep/BRep_Tool.cxx
src/BRep/BRep_Tool.hxx
src/BRep/FILES
src/BRepTools/BRepTools.cxx
src/BRepTools/BRepTools.hxx
src/DrawResources/CheckCommands.tcl
src/DrawResources/TestCommands.tcl
src/MeshTest/MeshTest.cxx
src/Poly/FILES
src/Poly/Poly_MeshPurpose.hxx [new file with mode: 0644]
src/Poly/Poly_Triangulation.cxx
src/Poly/Poly_Triangulation.hxx
src/Prs3d/Prs3d.cxx
src/RWGltf/FILES
src/RWGltf/RWGltf_CafReader.cxx
src/RWGltf/RWGltf_CafReader.hxx
src/RWGltf/RWGltf_GltfJsonParser.cxx
src/RWGltf/RWGltf_GltfJsonParser.hxx
src/RWGltf/RWGltf_GltfLatePrimitiveArray.cxx
src/RWGltf/RWGltf_GltfLatePrimitiveArray.hxx
src/RWGltf/RWGltf_PrimitiveArrayReader.cxx [deleted file]
src/RWGltf/RWGltf_PrimitiveArrayReader.hxx [deleted file]
src/RWGltf/RWGltf_TriangulationReader.cxx
src/RWGltf/RWGltf_TriangulationReader.hxx
src/RWMesh/FILES
src/RWMesh/RWMesh_TriangulationReader.cxx [new file with mode: 0644]
src/RWMesh/RWMesh_TriangulationReader.hxx [new file with mode: 0644]
src/RWMesh/RWMesh_TriangulationSource.cxx [new file with mode: 0644]
src/RWMesh/RWMesh_TriangulationSource.hxx [new file with mode: 0644]
src/Select3D/Select3D_SensitiveTriangulation.cxx
src/Select3D/Select3D_SensitiveTriangulation.hxx
src/StdPrs/StdPrs_ShadedShape.cxx
src/ViewerTest/ViewerTest.cxx
src/XDEDRAW/XDEDRAW.cxx
src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx
tests/bugs/mesh/bug25612
tests/bugs/modalg_6/bug26897
tests/de_mesh/gltf_lateload/begin [new file with mode: 0644]
tests/de_mesh/gltf_lateload/boxwithoutindices [new file with mode: 0644]
tests/de_mesh/gltf_lateload/engine [new file with mode: 0644]
tests/de_mesh/grids.list

index 2e71609..17e869f 100644 (file)
@@ -469,19 +469,34 @@ void  BRep_Builder::MakeFace(TopoDS_Face& F,
 //function : MakeFace
 //purpose  : 
 //=======================================================================
-
-void  BRep_Builder::MakeFace(TopoDS_Face&                      F,
-                             const Handle(Poly_Triangulation)& T) const
+void  BRep_Builder::MakeFace(TopoDS_Face& theFace,
+                             const Handle(Poly_Triangulation)& theTriangulation) const
 {
-  Handle(BRep_TFace) TF = new BRep_TFace();
-  if(!F.IsNull() && F.Locked())
+  Handle(BRep_TFace) aTFace = new BRep_TFace();
+  if(!theFace.IsNull() && theFace.Locked())
   {
     throw TopoDS_LockedShape("BRep_Builder::MakeFace");
   }
-  TF->Triangulation(T);
-  MakeShape(F, TF);
+  aTFace->Triangulation (theTriangulation);
+  MakeShape (theFace, aTFace);
 }
 
+//=======================================================================
+//function : MakeFace
+//purpose  :
+//=======================================================================
+void BRep_Builder::MakeFace (TopoDS_Face& theFace,
+                             const Poly_ListOfTriangulation& theTriangulations,
+                             const Handle(Poly_Triangulation)& theActiveTriangulation) const
+{
+  Handle(BRep_TFace) aTFace = new BRep_TFace();
+  if(!theFace.IsNull() && theFace.Locked())
+  {
+    throw TopoDS_LockedShape ("BRep_Builder::MakeFace");
+  }
+  aTFace->Triangulations (theTriangulations, theActiveTriangulation);
+  MakeShape (theFace, aTFace);
+}
 
 //=======================================================================
 //function : MakeFace
@@ -531,20 +546,19 @@ void  BRep_Builder::UpdateFace(const TopoDS_Face& F,
 //function : UpdateFace
 //purpose  : 
 //=======================================================================
-
-void  BRep_Builder::UpdateFace(const TopoDS_Face& F,
-                               const Handle(Poly_Triangulation)& T) const
+void BRep_Builder::UpdateFace (const TopoDS_Face& theFace,
+                               const Handle(Poly_Triangulation)& theTriangulation,
+                               const Standard_Boolean theToReset) const
 {
-  const Handle(BRep_TFace)& TF = *((Handle(BRep_TFace)*) &F.TShape());
-  if(TF->Locked())
+  const Handle(BRep_TFace)& aTFace = *((Handle(BRep_TFace)*) &theFace.TShape());
+  if(aTFace->Locked())
   {
     throw TopoDS_LockedShape("BRep_Builder::UpdateFace");
   }
-  TF->Triangulation(T);
-  F.TShape()->Modified(Standard_True);
+  aTFace->Triangulation (theTriangulation, theToReset);
+  theFace.TShape()->Modified (Standard_True);
 }
 
-
 //=======================================================================
 //function : UpdateFace
 //purpose  : 
index 2deef68..37239a8 100644 (file)
@@ -28,7 +28,7 @@
 #include <GeomAbs_Shape.hxx>
 #include <Poly_Polygon3D.hxx>
 #include <Poly_PolygonOnTriangulation.hxx>
-#include <Poly_Triangulation.hxx>
+#include <Poly_ListOfTriangulation.hxx>
 
 class Standard_NullObject;
 class Standard_DomainError;
@@ -79,19 +79,26 @@ public:
   //! Makes a Face with a surface and a location.
   Standard_EXPORT void MakeFace (TopoDS_Face& F, const Handle(Geom_Surface)& S, const TopLoc_Location& L, const Standard_Real Tol) const;
   
-  //! Makes a Face with a triangulation. The triangulation
+  //! Makes a theFace with a single triangulation. The triangulation
   //! is in the same reference system than the TFace.
-  Standard_EXPORT void MakeFace (TopoDS_Face& F, const Handle(Poly_Triangulation)& T) const;
+  Standard_EXPORT void MakeFace (TopoDS_Face& theFace, const Handle(Poly_Triangulation)& theTriangulation) const;
+
+  //! Makes a Face with a list of triangulations and active one.
+  //! Use NULL active triangulation to set the first triangulation in list as active.
+  //! The triangulations is in the same reference system than the TFace.
+  Standard_EXPORT void MakeFace (TopoDS_Face& theFace, const Poly_ListOfTriangulation& theTriangulations, const Handle(Poly_Triangulation)& theActiveTriangulation = Handle(Poly_Triangulation)()) const;
   
   //! Updates the face F using the tolerance value Tol,
   //! surface S and location Location.
   Standard_EXPORT void UpdateFace (const TopoDS_Face& F, const Handle(Geom_Surface)& S, const TopLoc_Location& L, const Standard_Real Tol) const;
   
-  //! Changes a  face triangulation.
-  //!
-  //! A null Triangulation removes the triangulation.
-  Standard_EXPORT void UpdateFace (const TopoDS_Face& F, const Handle(Poly_Triangulation)& T) const;
-  
+  //! Changes a face triangulation.
+  //! A NULL theTriangulation removes face triangulations.
+  //! If theToReset is TRUE face triangulations will be reset to new list with only one input triangulation that will be active.
+  //! Else if theTriangulation is contained in internal triangulations list it will be made active,
+  //!      else the active triangulation will be replaced to theTriangulation one.
+  Standard_EXPORT void UpdateFace (const TopoDS_Face& theFace, const Handle(Poly_Triangulation)& theTriangulation, const Standard_Boolean theToReset = true) const;
+
   //! Updates the face Tolerance.
   Standard_EXPORT void UpdateFace (const TopoDS_Face& F, const Standard_Real Tol) const;
   
index 8e9c88e..c44d3b1 100644 (file)
@@ -51,6 +51,131 @@ Handle(TopoDS_TShape) BRep_TFace::EmptyCopy() const
   return TF;
 }
 
+//=======================================================================
+//function : Triangulation
+//purpose  :
+//=======================================================================
+const Handle(Poly_Triangulation)& BRep_TFace::Triangulation (const Poly_MeshPurpose thePurpose) const
+{
+  if (thePurpose == Poly_MeshPurpose_NONE)
+  {
+    return ActiveTriangulation();
+  }
+  for (Poly_ListOfTriangulation::Iterator anIter(myTriangulations); anIter.More(); anIter.Next())
+  {
+    const Handle(Poly_Triangulation)& aTriangulation = anIter.Value();
+    if ((aTriangulation->MeshPurpose() & thePurpose) != 0)
+    {
+      return aTriangulation;
+    }
+  }
+  if ((thePurpose & Poly_MeshPurpose_AnyFallback) != 0
+    && !myTriangulations.IsEmpty())
+  {
+    // if none matching other criteria was found return the first defined triangulation
+    return myTriangulations.First();
+  }
+  static const Handle(Poly_Triangulation) anEmptyTriangulation;
+  return anEmptyTriangulation;
+}
+
+//=======================================================================
+//function : Triangulation
+//purpose  :
+//=======================================================================
+void BRep_TFace::Triangulation (const Handle(Poly_Triangulation)& theTriangulation,
+                                const Standard_Boolean theToReset)
+{
+  if (theToReset || theTriangulation.IsNull())
+  {
+    if (!myActiveTriangulation.IsNull())
+    {
+      // Reset Active bit
+      myActiveTriangulation->SetMeshPurpose (myActiveTriangulation->MeshPurpose() & ~Poly_MeshPurpose_Active);
+      myActiveTriangulation.Nullify();
+    }
+    myTriangulations.Clear();
+    if (!theTriangulation.IsNull())
+    {
+      // Reset list of triangulations to new list with only one input triangulation that will be active
+      myTriangulations.Append (theTriangulation);
+      myActiveTriangulation = theTriangulation;
+      // Set Active bit
+      theTriangulation->SetMeshPurpose (theTriangulation->MeshPurpose() | Poly_MeshPurpose_Active);
+    }
+    return;
+  }
+  for (Poly_ListOfTriangulation::Iterator anIter(myTriangulations); anIter.More(); anIter.Next())
+  {
+    // Make input triangulation active if it is already contained in list of triangulations
+    if (anIter.Value() == theTriangulation)
+    {
+      if (!myActiveTriangulation.IsNull())
+      {
+        // Reset Active bit
+        myActiveTriangulation->SetMeshPurpose (myActiveTriangulation->MeshPurpose() & ~Poly_MeshPurpose_Active);
+      }
+      myActiveTriangulation = theTriangulation;
+      // Set Active bit
+      theTriangulation->SetMeshPurpose (theTriangulation->MeshPurpose() | Poly_MeshPurpose_Active);
+      return;
+    }
+  }
+  for (Poly_ListOfTriangulation::Iterator anIter(myTriangulations); anIter.More(); anIter.Next())
+  {
+    // Replace active triangulation to input one
+    if (anIter.Value() == myActiveTriangulation)
+    {
+      // Reset Active bit
+      myActiveTriangulation->SetMeshPurpose (myActiveTriangulation->MeshPurpose() & ~Poly_MeshPurpose_Active);
+      anIter.ChangeValue() = theTriangulation;
+      myActiveTriangulation = theTriangulation;
+      // Set Active bit
+      theTriangulation->SetMeshPurpose (theTriangulation->MeshPurpose() | Poly_MeshPurpose_Active);
+      return;
+    }
+  }
+}
+
+//=======================================================================
+//function : Triangulations
+//purpose  :
+//=======================================================================
+void BRep_TFace::Triangulations (const Poly_ListOfTriangulation& theTriangulations,
+                                 const Handle(Poly_Triangulation)& theActiveTriangulation)
+{
+  if (theTriangulations.IsEmpty())
+  {
+    myActiveTriangulation.Nullify();
+    myTriangulations.Clear();
+    return;
+  }
+  Standard_Boolean anActiveInList = false;
+  for (Poly_ListOfTriangulation::Iterator anIter(theTriangulations); anIter.More(); anIter.Next())
+  {
+    const Handle(Poly_Triangulation)& aTriangulation = anIter.Value();
+    Standard_ASSERT_RAISE (!aTriangulation.IsNull(), "Try to set list with NULL triangulation to the face");
+    if (aTriangulation == theActiveTriangulation)
+    {
+      anActiveInList = true;
+    }
+    // Reset Active bit
+    aTriangulation->SetMeshPurpose (aTriangulation->MeshPurpose() & ~Poly_MeshPurpose_Active);
+  }
+  Standard_ASSERT_RAISE (theActiveTriangulation.IsNull() || anActiveInList, "Active triangulation isn't part of triangulations list");
+  myTriangulations = theTriangulations;
+  if (theActiveTriangulation.IsNull())
+  {
+    // Save the first one as active
+    myActiveTriangulation = myTriangulations.First();
+  }
+  else
+  {
+    myActiveTriangulation = theActiveTriangulation;
+  }
+  myActiveTriangulation->SetMeshPurpose (myActiveTriangulation->MeshPurpose() | Poly_MeshPurpose_Active);
+}
+
 //=======================================================================
 //function : DumpJson
 //purpose  : 
@@ -61,10 +186,16 @@ void BRep_TFace::DumpJson (Standard_OStream& theOStream, Standard_Integer theDep
 
   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, TopoDS_TFace)
 
+  OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myActiveTriangulation.get())
   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, mySurface.get())
-  OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myTriangulation.get())
   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myLocation)
 
   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTolerance)
   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNaturalRestriction)
+
+  for (Poly_ListOfTriangulation::Iterator anIter(myTriangulations); anIter.More(); anIter.Next())
+  {
+    const Handle(Poly_Triangulation)& aTriangulation = anIter.Value();
+    OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, aTriangulation.get())
+  }
 }
index dd23f43..f1b589f 100644 (file)
 #include <Standard.hxx>
 #include <Standard_Type.hxx>
 
+#include <Poly_ListOfTriangulation.hxx>
 #include <TopLoc_Location.hxx>
 #include <Standard_Real.hxx>
 #include <Standard_Boolean.hxx>
 #include <TopoDS_TFace.hxx>
 class Geom_Surface;
-class Poly_Triangulation;
 class TopLoc_Location;
 class TopoDS_TShape;
 
-
 class BRep_TFace;
 DEFINE_STANDARD_HANDLE(BRep_TFace, TopoDS_TFace)
 
@@ -42,8 +41,8 @@ DEFINE_STANDARD_HANDLE(BRep_TFace, TopoDS_TFace)
 //! True the  boundary of the  face is known to be the
 //! parametric space (Umin, UMax, VMin, VMax).
 //!
-//! *  An    optional Triangulation.   If  there  is a
-//! triangulation the surface can be absent.
+//! * An optional list of triangulations. If there are any
+//! triangulations the surface can be absent.
 //!
 //! The  Location is  used   for the Surface.
 //!
@@ -60,64 +59,87 @@ class BRep_TFace : public TopoDS_TFace
 
 public:
 
-  
   //! Creates an empty TFace.
   Standard_EXPORT BRep_TFace();
-  
-    const Handle(Geom_Surface)& Surface() const;
-  
-    const Handle(Poly_Triangulation)& Triangulation() const;
-  
-    const TopLoc_Location& Location() const;
-  
-    Standard_Real Tolerance() const;
-  
-    void Surface (const Handle(Geom_Surface)& S);
-  
-    void Triangulation (const Handle(Poly_Triangulation)& T);
-  
-    void Location (const TopLoc_Location& L);
-  
-    void Tolerance (const Standard_Real T);
-  
-    Standard_Boolean NaturalRestriction() const;
-  
-    void NaturalRestriction (const Standard_Boolean N);
-  
-  //! Returns a copy  of the  TShape  with no sub-shapes.
-  //! The new Face has no triangulation.
-  Standard_EXPORT virtual Handle(TopoDS_TShape) EmptyCopy() const Standard_OVERRIDE;
 
-  //! Dumps the content of me into the stream
-  Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE;
+  //! Returns face surface.
+  const Handle(Geom_Surface)& Surface() const { return mySurface; }
 
+  //! Sets surface for this face.
+  void Surface (const Handle(Geom_Surface)& theSurface) { mySurface = theSurface;}
 
+  //! Returns the face location.
+  const TopLoc_Location& Location() const { return myLocation; }
 
+  //! Sets the location for this face.
+  void Location (const TopLoc_Location& theLocation) { myLocation = theLocation; }
 
-  DEFINE_STANDARD_RTTIEXT(BRep_TFace,TopoDS_TFace)
+  //! Returns the face tolerance.
+  Standard_Real Tolerance() const { return myTolerance; }
 
-protected:
+  //! Sets the tolerance for this face.
+  void Tolerance (const Standard_Real theTolerance) { myTolerance = theTolerance; }
 
+  //! Returns TRUE if the boundary of this face is known to be the parametric space (Umin, UMax, VMin, VMax).
+  Standard_Boolean NaturalRestriction() const { return myNaturalRestriction; }
 
+  //! Sets the flag that is TRUE if the boundary of this face is known to be the parametric space.
+  void NaturalRestriction (const Standard_Boolean theRestriction) { myNaturalRestriction = theRestriction; }
 
+  //! Returns the triangulation of this face according to the mesh purpose.
+  //! @param theMeshPurpose [in] a mesh purpose to find appropriate triangulation (NONE by default).
+  //! @return an active triangulation in case of NONE purpose,
+  //!         the first triangulation appropriate for the input purpose,
+  //!         just the first triangulation if none matching other criteria and input purpose is AnyFallback
+  //!         or null handle if there is no any suitable triangulation.
+  Standard_EXPORT const Handle(Poly_Triangulation)& Triangulation (const Poly_MeshPurpose thePurpose = Poly_MeshPurpose_NONE) const;
 
-private:
+  //! Sets input triangulation for this face.
+  //! @param theTriangulation [in] triangulation to be set
+  //! @param theToReset [in] flag to reset triangulations list to new list with only one input triangulation.
+  //! If theTriangulation is NULL internal list of triangulations will be cleared and active triangulation will be nullified.
+  //! If theToReset is TRUE internal list of triangulations will be reset
+  //! to new list with only one input triangulation that will be active.
+  //! Else if input triangulation is contained in internal triangulations list it will be made active,
+  //!      else the active triangulation will be replaced to input one.
+  Standard_EXPORT void Triangulation (const Handle(Poly_Triangulation)& theTriangulation, const Standard_Boolean theToReset = true);
 
+  //! Returns a copy  of the  TShape  with no sub-shapes.
+  //! The new Face has no triangulation.
+  Standard_EXPORT virtual Handle(TopoDS_TShape) EmptyCopy() const Standard_OVERRIDE;
 
-  Handle(Geom_Surface) mySurface;
-  Handle(Poly_Triangulation) myTriangulation;
-  TopLoc_Location myLocation;
-  Standard_Real myTolerance;
-  Standard_Boolean myNaturalRestriction;
+  //! Dumps the content of me into the stream
+  Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE;
 
+public:
 
-};
+  //! Returns the list of available face triangulations.
+  const Poly_ListOfTriangulation& Triangulations() const { return myTriangulations; }
 
+  //! Sets input list of triangulations and currently active triangulation for this face.
+  //! If list is empty internal list of triangulations will be cleared and active triangulation will be nullified.
+  //! Else this list will be saved and the input active triangulation be saved as active.
+  //! Use NULL active triangulation to set the first triangulation in list as active.
+  //! Note: the method throws exception if there is any NULL triangulation in input list or
+  //!       if this list doesn't contain input active triangulation.
+  Standard_EXPORT void Triangulations (const Poly_ListOfTriangulation& theTriangulations, const Handle(Poly_Triangulation)& theActiveTriangulation);
 
-#include <BRep_TFace.lxx>
+  //! Returns number of available face triangulations.
+  Standard_Integer NbTriangulations() const { return myTriangulations.Size(); }
 
+  //! Returns current active triangulation.
+  const Handle(Poly_Triangulation)& ActiveTriangulation() const { return myActiveTriangulation; }
 
+  DEFINE_STANDARD_RTTIEXT(BRep_TFace,TopoDS_TFace)
 
+private:
 
+  Poly_ListOfTriangulation myTriangulations;
+  Handle(Poly_Triangulation) myActiveTriangulation;
+  Handle(Geom_Surface) mySurface;
+  TopLoc_Location myLocation;
+  Standard_Real myTolerance;
+  Standard_Boolean myNaturalRestriction;
+};
 
 #endif // _BRep_TFace_HeaderFile
diff --git a/src/BRep/BRep_TFace.lxx b/src/BRep/BRep_TFace.lxx
deleted file mode 100644 (file)
index ed99814..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-// Created on: 1992-08-25
-// Created by: Modelistation
-// Copyright (c) 1992-1999 Matra Datavision
-// Copyright (c) 1999-2014 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.
-
-//=======================================================================
-//function : Surface
-//purpose  : 
-//=======================================================================
-
-inline const Handle(Geom_Surface)&  BRep_TFace::Surface()const 
-{
-  return mySurface;
-}
-
-
-//=======================================================================
-//function : Triangulation
-//purpose  : 
-//=======================================================================
-
- inline const Handle(Poly_Triangulation)&  BRep_TFace::Triangulation()const 
-{
-  return myTriangulation;
-}
-
-
-//=======================================================================
-//function : Location
-//purpose  : 
-//=======================================================================
-
- inline const TopLoc_Location&  BRep_TFace::Location()const 
-{
-  return myLocation;
-}
-
-
-//=======================================================================
-//function : Tolerance
-//purpose  : 
-//=======================================================================
-
- inline Standard_Real  BRep_TFace::Tolerance()const 
-{
-  return myTolerance;
-}
-
-
-//=======================================================================
-//function : Surface
-//purpose  : 
-//=======================================================================
-
-inline void  BRep_TFace::Surface(const Handle(Geom_Surface)& S)
-{
-  mySurface = S;
-}
-
-//=======================================================================
-//function : Triangulation
-//purpose  : 
-//=======================================================================
-
-inline void  BRep_TFace::Triangulation(const Handle(Poly_Triangulation)& T)
-{
-  myTriangulation = T;
-}
-
-
-//=======================================================================
-//function : Location
-//purpose  : 
-//=======================================================================
-
- inline void  BRep_TFace::Location(const TopLoc_Location& L)
-{
-  myLocation = L;
-}
-
-
-//=======================================================================
-//function : Tolerance
-//purpose  : 
-//=======================================================================
-
- inline void  BRep_TFace::Tolerance(const Standard_Real T)
-{
-  myTolerance = T;
-}
-
-
-
-
-//=======================================================================
-//function : NaturalRestriction
-//purpose  : 
-//=======================================================================
-
- inline Standard_Boolean  BRep_TFace::NaturalRestriction()const 
-{
-  return myNaturalRestriction;
-}
-
-
-//=======================================================================
-//function : NaturalRestriction
-//purpose  : 
-//=======================================================================
-
- inline void  BRep_TFace::NaturalRestriction(const Standard_Boolean N)
-{
-  myNaturalRestriction = N;
-}
-
-
index b3ebf62..7e2f0f4 100644 (file)
@@ -113,16 +113,27 @@ Handle(Geom_Surface) BRep_Tool::Surface(const TopoDS_Face& F)
 
 //=======================================================================
 //function : Triangulation
-//purpose  : Returns  the Triangulation of  the  face. It  is a
-//           null handle if there is no triangulation.
+//purpose  :
 //=======================================================================
+const Handle(Poly_Triangulation)& BRep_Tool::Triangulation (const TopoDS_Face& theFace,
+                                                            TopLoc_Location&   theLocation,
+                                                            const Poly_MeshPurpose theMeshPurpose)
+{
+  theLocation = theFace.Location();
+  const BRep_TFace* aTFace = static_cast<const BRep_TFace*>(theFace.TShape().get());
+  return aTFace->Triangulation (theMeshPurpose);
+}
 
-const Handle(Poly_Triangulation)& BRep_Tool::Triangulation(const TopoDS_Face& F,
-                                                           TopLoc_Location&   L)
+//=======================================================================
+//function : Triangulations
+//purpose  :
+//=======================================================================
+const Poly_ListOfTriangulation& BRep_Tool::Triangulations (const TopoDS_Face& theFace,
+                                                           TopLoc_Location&   theLocation)
 {
-  L = F.Location();
-  const BRep_TFace* TF = static_cast<const BRep_TFace*>(F.TShape().get());
-  return TF->Triangulation();
+  theLocation = theFace.Location();
+  const BRep_TFace* aTFace = static_cast<const BRep_TFace*>(theFace.TShape().get());
+  return aTFace->Triangulations();
 }
 
 //=======================================================================
index 4d3b4de..2b38ee7 100644 (file)
@@ -27,7 +27,7 @@
 #include <Geom2d_Curve.hxx>
 #include <gp_Pnt2d.hxx>
 #include <gp_Pnt.hxx>
-#include <Poly_Triangulation.hxx>
+#include <Poly_ListOfTriangulation.hxx>
 #include <Poly_Polygon3D.hxx>
 #include <Poly_Polygon2D.hxx>
 #include <Poly_PolygonOnTriangulation.hxx>
@@ -63,11 +63,24 @@ public:
   //! Returns the geometric  surface of the face. It can
   //! be a copy if there is a Location.
   Standard_EXPORT static Handle(Geom_Surface) Surface (const TopoDS_Face& F);
-  
-  //! Returns  the Triangulation of  the  face. It  is a
-  //! null handle if there is no triangulation.
-  Standard_EXPORT static const Handle(Poly_Triangulation)& Triangulation (const TopoDS_Face& F, TopLoc_Location& L);
-  
+
+  //! Returns the triangulation of the face according to the mesh purpose.
+  //! @param theFace [in] the input face to find triangulation.
+  //! @param theLocation [out] the face location.
+  //! @param theMeshPurpose [in] a mesh purpose to find appropriate triangulation (NONE by default).
+  //! @return an active triangulation in case of NONE purpose,
+  //!         the first triangulation appropriate for the input purpose,
+  //!         just the first triangulation if none matching other criteria and input purpose is AnyFallback
+  //!         or null handle if there is no any suitable triangulation.
+  Standard_EXPORT static const Handle(Poly_Triangulation)& Triangulation (const TopoDS_Face& theFace, TopLoc_Location& theLocation,
+                                                                          const Poly_MeshPurpose theMeshPurpose = Poly_MeshPurpose_NONE);
+
+  //! Returns all triangulations of the face.
+  //! @param theFace [in] the input face.
+  //! @param theLocation [out] the face location.
+  //! @return list of all available face triangulations.
+  Standard_EXPORT static const Poly_ListOfTriangulation& Triangulations (const TopoDS_Face& theFace, TopLoc_Location& theLocation);
+
   //! Returns the tolerance of the face.
   Standard_EXPORT static Standard_Real Tolerance (const TopoDS_Face& F);
   
index c180c20..ada2d5a 100644 (file)
@@ -47,7 +47,6 @@ BRep_TEdge.hxx
 BRep_TEdge.lxx
 BRep_TFace.cxx
 BRep_TFace.hxx
-BRep_TFace.lxx
 BRep_Tool.cxx
 BRep_Tool.hxx
 BRep_TVertex.cxx
index 4dd05b8..61e7a90 100644 (file)
@@ -36,6 +36,8 @@
 #include <Geom_Surface.hxx>
 #include <gp_Lin2d.hxx>
 #include <gp_Vec2d.hxx>
+#include <Message.hxx>
+#include <OSD_FileSystem.hxx>
 #include <OSD_OpenFile.hxx>
 #include <Poly_PolygonOnTriangulation.hxx>
 #include <Poly_Triangulation.hxx>
@@ -1020,6 +1022,230 @@ Standard_Boolean  BRepTools::Triangulation(const TopoDS_Shape& theShape,
   return Standard_True;
 }
 
+//=======================================================================
+//function : LoadTriangulation
+//purpose  : 
+//=======================================================================
+Standard_Boolean BRepTools::LoadTriangulation (const TopoDS_Shape& theShape,
+                                               const Standard_Integer theTriangulationIdx,
+                                               const Standard_Boolean theToSetAsActive,
+                                               const Handle(OSD_FileSystem)& theFileSystem)
+{
+  Standard_ASSERT_RAISE (theTriangulationIdx >= -1, "Invalid negative triangulation index!");
+
+  Standard_Boolean wasLoaded = false;
+  BRep_Builder aBuilder;
+  TopLoc_Location aDummyLoc;
+  const Handle(OSD_FileSystem)& aFileSystem = !theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem();
+  for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
+  {
+    const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
+    Handle(Poly_Triangulation) aTriangulation;
+    if (theTriangulationIdx == -1)
+    {
+      // load an active triangulation
+      aTriangulation = BRep_Tool::Triangulation (aFace, aDummyLoc);
+    }
+    else
+    {
+      const Poly_ListOfTriangulation& aTriangulations = BRep_Tool::Triangulations (aFace, aDummyLoc);
+      if (theTriangulationIdx >= aTriangulations.Size())
+      {
+        // triangulation index is out of range
+        continue;
+      }
+      Standard_Integer aTriangulationIdx = 0;
+      for (Poly_ListOfTriangulation::Iterator anIter(aTriangulations);
+           anIter.More(); anIter.Next(), aTriangulationIdx++)
+      {
+        if (aTriangulationIdx != theTriangulationIdx)
+        {
+          continue;
+        }
+        aTriangulation = anIter.Value();
+        break;
+      }
+    }
+    if (aTriangulation.IsNull() ||
+       !aTriangulation->HasDeferredData())
+    {
+      // NULL triangulation, already loaded triangulation or triangulation without deferred storage
+      // cannot be loaded
+      continue;
+    }
+    if (aTriangulation->LoadDeferredData (aFileSystem))
+    {
+      wasLoaded = true;
+      if (theToSetAsActive
+       && (theTriangulationIdx != -1)) // triangulation is already active
+      {
+        aBuilder.UpdateFace (aFace, aTriangulation, false);
+      }
+    }
+  }
+  return wasLoaded;
+}
+
+//=======================================================================
+//function : LoadAllTriangulation
+//purpose  : 
+//=======================================================================
+Standard_Boolean BRepTools::LoadAllTriangulations (const TopoDS_Shape& theShape,
+                                                   const Handle(OSD_FileSystem)& theFileSystem)
+{
+  Standard_Boolean wasLoaded = false;
+  TopLoc_Location aDummyLoc;
+  const Handle(OSD_FileSystem)& aFileSystem = !theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem();
+  for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
+  {
+    const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
+    for (Poly_ListOfTriangulation::Iterator anIter (BRep_Tool::Triangulations (aFace, aDummyLoc));
+         anIter.More(); anIter.Next())
+    {
+      const Handle(Poly_Triangulation)& aTriangulation = anIter.Value();
+      if (aTriangulation.IsNull() ||
+         !aTriangulation->HasDeferredData())
+      {
+        // NULL triangulation, already loaded triangulation or triangulation without deferred storage
+        // cannot be loaded
+        continue;
+      }
+      wasLoaded = aTriangulation->LoadDeferredData (aFileSystem);
+    }
+  }
+  return wasLoaded;
+}
+
+//=======================================================================
+//function : UnloadTriangulation
+//purpose  : 
+//=======================================================================
+Standard_Boolean BRepTools::UnloadTriangulation (const TopoDS_Shape& theShape,
+                                                 const Standard_Integer theTriangulationIdx)
+{
+  Standard_ASSERT_RAISE (theTriangulationIdx >= -1, "Invalid negative triangulation index!");
+
+  Standard_Boolean wasUnloaded = false;
+  TopLoc_Location aDummyLoc;
+  for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
+  {
+    const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
+    Handle(Poly_Triangulation) aTriangulation;
+    if (theTriangulationIdx == -1)
+    {
+      // unload an active triangulation
+      aTriangulation = BRep_Tool::Triangulation (aFace, aDummyLoc);
+    }
+    else
+    {
+      Standard_Integer aTriangulationIdx = 0;
+      const Poly_ListOfTriangulation& aTriangulations = BRep_Tool::Triangulations (aFace, aDummyLoc);
+      if (theTriangulationIdx >= aTriangulations.Size())
+      {
+        // triangulation index is out of range
+        continue;
+      }
+      for (Poly_ListOfTriangulation::Iterator anIter (aTriangulations);
+           anIter.More(); anIter.Next(), aTriangulationIdx++)
+      {
+        if (aTriangulationIdx != theTriangulationIdx)
+        {
+          continue;
+        }
+        aTriangulation = anIter.Value();
+        break;
+      }
+    }
+    if (aTriangulation.IsNull() ||
+       !aTriangulation->HasDeferredData())
+    {
+      // NULL triangulation or triangulation without deferred storage cannot be unloaded
+      continue;
+    }
+    wasUnloaded = aTriangulation->UnloadDeferredData();
+  }
+  return wasUnloaded;
+}
+
+//=======================================================================
+//function : UnloadAllTriangulations
+//purpose  : 
+//=======================================================================
+Standard_Boolean BRepTools::UnloadAllTriangulations (const TopoDS_Shape& theShape)
+{
+  Standard_Boolean wasUnloaded = false;
+  TopLoc_Location aDummyLoc;
+  for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
+  {
+    const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
+    Handle(Poly_Triangulation) aTriangulation;
+    for (Poly_ListOfTriangulation::Iterator anIter (BRep_Tool::Triangulations (aFace, aDummyLoc));
+         anIter.More(); anIter.Next())
+    {
+      aTriangulation = anIter.Value();
+      if (aTriangulation.IsNull() ||
+         !aTriangulation->HasDeferredData())
+      {
+        // NULL triangulation or triangulation without deferred storage cannot be unloaded
+        continue;
+      }
+      wasUnloaded = aTriangulation->UnloadDeferredData();
+    }
+  }
+  return wasUnloaded;
+}
+
+//=======================================================================
+//function : ActivateTriangulation
+//purpose  : 
+//=======================================================================
+Standard_Boolean BRepTools::ActivateTriangulation (const TopoDS_Shape& theShape,
+                                                   const Standard_Integer theTriangulationIdx,
+                                                   const Standard_Boolean theToActivateStrictly)
+{
+  Standard_ASSERT_RAISE (theTriangulationIdx > -1, "Invalid negative triangulation index!");
+
+  Standard_Boolean wasActivated = false;
+  BRep_Builder aBuilder;
+  TopLoc_Location aDummyLoc;
+  for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
+  {
+    const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
+    Standard_Integer aTriangulationIdx = theTriangulationIdx;
+    const Poly_ListOfTriangulation& aTriangulations = BRep_Tool::Triangulations (aFace, aDummyLoc);
+    const Standard_Integer aTriangulationsNb = aTriangulations.Size();
+    if (theTriangulationIdx >= aTriangulationsNb)
+    {
+      // triangulation index is out of range
+      if (theToActivateStrictly)
+      {
+        // skip activation
+        continue;
+      }
+      // use last available
+      aTriangulationIdx = aTriangulationsNb - 1;
+    }
+    Handle(Poly_Triangulation) anActiveTriangulation;
+    Standard_Integer aTriangulationIter = 0;
+    for (Poly_ListOfTriangulation::Iterator anIter (aTriangulations);
+         anIter.More(); anIter.Next(), aTriangulationIter++)
+    {
+      if (aTriangulationIter != aTriangulationIdx)
+      {
+        continue;
+      }
+      anActiveTriangulation = anIter.Value();
+      break;
+    }
+    if (anActiveTriangulation.IsNull())
+    {
+      continue;
+    }
+    aBuilder.UpdateFace (aFace, anActiveTriangulation, false);
+    wasActivated = true;
+  }
+  return wasActivated;
+}
 
 //=======================================================================
 //function : IsReallyClosed
index 99766fc..babe873 100644 (file)
@@ -54,6 +54,7 @@ class BRepTools_ReShape;
 class Geom_Curve;
 class Geom2d_Curve;
 class Geom_Surface;
+class OSD_FileSystem;
 
 
 //! The BRepTools package provides  utilities for BRep
@@ -165,7 +166,9 @@ public:
   //! Removes all the pcurves of the edges of <S> that
   //! refer to surfaces not belonging to any face of <S>
   Standard_EXPORT static void RemoveUnusedPCurves (const TopoDS_Shape& S);
-  
+
+public:
+
   //! Verifies that each Face from the shape has got a triangulation with a deflection smaller or equal to specified one
   //! and the Edges a discretization on this triangulation.
   //! @param theShape   [in] shape to verify
@@ -178,7 +181,60 @@ public:
   Standard_EXPORT static Standard_Boolean Triangulation (const TopoDS_Shape& theShape,
                                                          const Standard_Real theLinDefl,
                                                          const Standard_Boolean theToCheckFreeEdges = Standard_False);
-  
+
+  //! Loads triangulation data for each face of the shape
+  //! from some deferred storage using specified shared input file system
+  //! @param theShape            [in] shape to load triangulations
+  //! @param theTriangulationIdx [in] index defining what triangulation should be loaded. Starts from 0.
+  //!        -1 is used in specific case to load currently already active triangulation.
+  //!        If some face doesn't contain triangulation with this index, nothing will be loaded for it.
+  //!        Exception will be thrown in case of invalid negative index
+  //! @param theToSetAsActive    [in] flag to activate triangulation after its loading
+  //! @param theFileSystem       [in] shared file system
+  //! @return TRUE if at least one triangulation is loaded.
+  Standard_EXPORT static Standard_Boolean LoadTriangulation (const TopoDS_Shape& theShape,
+                                                             const Standard_Integer theTriangulationIdx = -1,
+                                                             const Standard_Boolean theToSetAsActive = Standard_False,
+                                                             const Handle(OSD_FileSystem)& theFileSystem = Handle(OSD_FileSystem)());
+
+  //! Releases triangulation data for each face of the shape if there is deferred storage to load it later
+  //! @param theShape            [in] shape to unload triangulations
+  //! @param theTriangulationIdx [in] index defining what triangulation should be unloaded. Starts from 0.
+  //!        -1 is used in specific case to unload currently already active triangulation.
+  //!        If some face doesn't contain triangulation with this index, nothing will be unloaded for it.
+  //!        Exception will be thrown in case of invalid negative index
+  //! @return TRUE if at least one triangulation is unloaded.
+  Standard_EXPORT static Standard_Boolean UnloadTriangulation (const TopoDS_Shape& theShape,
+                                                               const Standard_Integer theTriangulationIdx = -1);
+
+  //! Activates triangulation data for each face of the shape
+  //! from some deferred storage using specified shared input file system
+  //! @param theShape              [in] shape to activate triangulations
+  //! @param theTriangulationIdx   [in] index defining what triangulation should be activated. Starts from 0.
+  //!        Exception will be thrown in case of invalid negative index
+  //! @param theToActivateStrictly [in] flag to activate exactly triangulation with defined theTriangulationIdx index.
+  //!        In TRUE case if some face doesn't contain triangulation with this index, active triangulation
+  //!        will not be changed for it. Else the last available triangulation will be activated.
+  //! @return TRUE if at least one active triangulation was changed.
+  Standard_EXPORT static Standard_Boolean ActivateTriangulation (const TopoDS_Shape& theShape,
+                                                                 const Standard_Integer theTriangulationIdx,
+                                                                 const Standard_Boolean theToActivateStrictly = false);
+
+  //! Loads all available triangulations for each face of the shape
+  //! from some deferred storage using specified shared input file system
+  //! @param theShape      [in] shape to load triangulations
+  //! @param theFileSystem [in] shared file system
+  //! @return TRUE if at least one triangulation is loaded.
+  Standard_EXPORT static Standard_Boolean LoadAllTriangulations (const TopoDS_Shape& theShape,
+                                                                 const Handle(OSD_FileSystem)& theFileSystem = Handle(OSD_FileSystem)());
+
+  //! Releases all available triangulations for each face of the shape if there is deferred storage to load them later
+  //! @param theShape      [in] shape to unload triangulations
+  //! @return TRUE if at least one triangulation is unloaded.
+  Standard_EXPORT static Standard_Boolean UnloadAllTriangulations (const TopoDS_Shape& theShape);
+
+public:
+
   //! Returns  True if  the    distance between the  two
   //! vertices is lower than their tolerance.
   Standard_EXPORT static Standard_Boolean Compare (const TopoDS_Vertex& V1, const TopoDS_Vertex& V2);
index 6f367a3..e0b5c33 100644 (file)
@@ -934,6 +934,12 @@ help checktrinfo {
 
   Use: checktrinfo shapename [options...]
   Allowed options are:
+    -face [N]: compare current number of faces in "shapename" mesh with given reference data.
+               If reference value N is not given and current number of faces is equal to 0
+               procedure checktrinfo will print an error.
+    -empty[N]: compare current number of empty faces in "shapename" mesh with given reference data.
+               If reference value N is not given and current number of empty faces is greater that 0
+               procedure checktrinfo will print an error.
     -tri [N]:  compare current number of triangles in "shapename" mesh with given reference data.
                If reference value N is not given and current number of triangles is equal to 0
                procedure checktrinfo will print an error.
@@ -961,6 +967,8 @@ proc checktrinfo {shape args} {
         return
     }
 
+    set ref_nb_faces false
+    set ref_nb_empty_faces true
     set ref_nb_triangles false
     set ref_nb_nodes false
     set ref_deflection false
@@ -973,7 +981,9 @@ proc checktrinfo {shape args} {
     set max_defl -1
     set ref_info ""
 
-    set options {{"-tri" ref_nb_triangles ?}
+    set options {{"-face" ref_nb_faces ?}
+                 {"-empty" ref_nb_empty_faces ?} 
+                 {"-tri" ref_nb_triangles ?}
                  {"-nod" ref_nb_nodes ?}
                  {"-defl" ref_deflection ?}
                  {"-tol_abs_defl" tol_abs_defl 1}
@@ -987,20 +997,52 @@ proc checktrinfo {shape args} {
 
     _check_args ${args} ${options} "checktrinfo"
 
-    # get current number of triangles and nodes, value of max deflection
+    # get current number of faces, triangles and nodes, value of max deflection
     set tri_info [trinfo ${shape}]
-    set triinfo_pattern "(\[0-9\]+) +triangles.*\[^0-9]\(\[0-9\]+) +nodes.*deflection +(\[-0-9.+eE\]+)"
-    if {![regexp "${triinfo_pattern}" ${tri_info} dump cur_nb_triangles cur_nb_nodes cur_deflection]} {
+    set triinfo_pattern "(\[0-9\]+) +faces(.*\[^0-9]\(\[0-9\]+) +empty faces)?.*\[^0-9]\(\[0-9\]+) +triangles.*\[^0-9]\(\[0-9\]+) +nodes.*deflection +(\[-0-9.+eE\]+)"
+    if {![regexp "${triinfo_pattern}" ${tri_info} dump cur_nb_faces tmp cur_nb_empty_faces cur_nb_triangles cur_nb_nodes cur_deflection]} {
         puts "Error: command trinfo prints empty info"
     }
+    if { ${cur_nb_empty_faces} == "" } {
+      set cur_nb_empty_faces 0
+    }
 
     # get reference values from -ref option
     if { "${ref_info}" != ""} {
-        if {![regexp "${triinfo_pattern}" ${ref_info} dump ref_nb_triangles ref_nb_nodes ref_deflection]} {
+        if {![regexp "${triinfo_pattern}" ${ref_info} dump ref_nb_faces tmp ref_nb_empty_faces ref_nb_triangles ref_nb_nodes ref_deflection]} {
             puts "Error: reference information given by -ref option is wrong"
         }
     }
 
+    # check number of faces
+    if { [string is boolean ${ref_nb_faces}] } {
+        if { ${cur_nb_faces} <= 0 && ${ref_nb_faces} } {
+            puts "Error: Number of faces is equal to 0"
+        }
+    } else {
+        if {[regexp {!([-0-9.+eE]+)} $ref_nb_faces full ref_nb_faces_value]} {
+            if  {${ref_nb_faces_value} == ${cur_nb_faces} } {
+                puts "Error: Number of faces is equal to ${ref_nb_faces_value} but it should not"
+            }
+        } else {
+            checkreal "Number of faces" ${cur_nb_faces} ${ref_nb_faces} ${tol_abs_tri} ${tol_rel_tri}
+        }
+    }
+    # check number of empty faces
+    if { [string is boolean ${ref_nb_empty_faces}] } {
+        if { ${cur_nb_empty_faces} > 0 && !${ref_nb_empty_faces} } {
+            puts "Error: Number of empty faces is greater that 0"
+        }
+    } else {
+        if {[regexp {!([-0-9.+eE]+)} $ref_nb_empty_faces full ref_nb_empty_faces_value]} {
+            if  {${ref_nb_empty_faces_value} == ${cur_nb_empty_faces} } {
+                puts "Error: Number of empty faces is equal to ${ref_nb_empty_faces_value} but it should not"
+            }
+        } else {
+            checkreal "Number of empty faces" ${cur_nb_empty_faces} ${ref_nb_empty_faces} ${tol_abs_tri} ${tol_rel_tri}
+        }
+    }
+
     # check number of triangles
     if { [string is boolean ${ref_nb_triangles}] } {
         if { ${cur_nb_triangles} <= 0 && ${ref_nb_triangles} } {
index 48dd1ee..1a28ba2 100644 (file)
@@ -1118,7 +1118,7 @@ proc testfile {filelist} {
         # warn if shape contains triangulation
         pload MODELING
         if { "$format" != "STL" &&
-             [regexp {contains\s+([0-9]+)\s+triangles} [uplevel trinfo a] res nbtriangles] &&
+             [regexp {([0-9]+)\s+triangles} [uplevel trinfo a] res nbtriangles] &&
              $nbtriangles != 0 } {
             puts "  Warning: shape contains triangulation ($nbtriangles triangles),"
             puts "           consider removing them unless they are needed for the test!"
index b562ba2..230d5c0 100644 (file)
@@ -52,6 +52,8 @@
 #include <BRepMesh_MeshAlgoFactory.hxx>
 #include <BRepMesh_DelabellaMeshAlgoFactory.hxx>
 
+#include <algorithm>
+
 //epa Memory leaks test
 //OAN: for triepoints
 #ifdef _WIN32
@@ -428,33 +430,329 @@ static Standard_Integer MemLeakTest(Draw_Interpretor&, Standard_Integer /*nbarg*
   return 0;
 }
 
+//=======================================================================
+//function : TrLateLoad
+//purpose  :
+//=======================================================================
+static Standard_Integer TrLateLoad (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec)
+{
+  if (theNbArgs < 3)
+  {
+    theDI << "Syntax error: not enough arguments\n";
+    return 1;
+  }
+  TopoDS_Shape aShape = DBRep::Get (theArgVec[1]);
+  if (aShape.IsNull())
+  {
+    theDI << "Syntax error: '" << theArgVec[1] << "' is not a shape\n";
+    return 1;
+  }
+  for (Standard_Integer anArgIter = 2; anArgIter < theNbArgs; ++anArgIter)
+  {
+    TCollection_AsciiString anArgCase(theArgVec[anArgIter]);
+    anArgCase.LowerCase();
+    if (anArgCase == "-load")
+    {
+      if (anArgIter + 1 < theNbArgs)
+      {
+        TCollection_AsciiString aLoadArg(theArgVec[anArgIter + 1]);
+        aLoadArg.LowerCase();
+        if (aLoadArg == "all"
+         || aLoadArg == "*")
+        {
+          // Load all triangulations
+          anArgIter++;
+          if (BRepTools::LoadAllTriangulations (aShape))
+          {
+            theDI << "All triangulations of shape " << theArgVec[1] << " were loaded\n";
+          }
+          continue;
+        }
+        if (aLoadArg.IsIntegerValue())
+        {
+          // Load defined triangulation
+          anArgIter++;
+          Standard_Integer anIndexToLoad = aLoadArg.IntegerValue();
+          if (anIndexToLoad < -1)
+          {
+            Message::SendWarning ("Invalid negative triangulation index to be loaded");
+            continue;
+          }
+          if (BRepTools::LoadTriangulation (aShape, anIndexToLoad))
+          {
+            theDI << "The " << anIndexToLoad << " triangulation of shape " << theArgVec[1] << " was loaded\n";
+          }
+          continue;
+        }
+      }
+      // Load active triangulation
+      if (BRepTools::LoadTriangulation (aShape))
+      {
+        theDI << "The active triangulation of shape " << theArgVec[1] << " was loaded\n";
+      }
+      continue;
+    }
+    else if (anArgCase == "-unload")
+    {
+      if (anArgIter + 1 < theNbArgs)
+      {
+        TCollection_AsciiString anUnloadArg(theArgVec[anArgIter + 1]);
+        anUnloadArg.LowerCase();
+        if (anUnloadArg == "all"
+         || anUnloadArg == "*")
+        {
+          // Unload all triangulations
+          anArgIter++;
+          if (BRepTools::UnloadAllTriangulations (aShape))
+          {
+            theDI << "All triangulations of shape " << theArgVec[1] << " were unloaded\n";
+          }
+          continue;
+        }
+        if (anUnloadArg.IsIntegerValue())
+        {
+          // Unload defined triangulation
+          anArgIter++;
+          Standard_Integer anIndexToUnload = anUnloadArg.IntegerValue();
+          if (anIndexToUnload < -1)
+          {
+            Message::SendWarning ("Invalid negative triangulation index to be unloaded");
+            continue;
+          }
+          if (BRepTools::UnloadTriangulation (aShape, anIndexToUnload))
+          {
+            theDI << "The " << anIndexToUnload << " triangulation of shape " << theArgVec[1] << " was unloaded\n";
+          }
+          continue;
+        }
+      }
+      // Unload active triangulation
+      if (BRepTools::UnloadTriangulation (aShape))
+      {
+        theDI << "The active triangulation of shape " << theArgVec[1] << " was unloaded\n";
+      }
+      continue;
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && anArgCase == "-activate"
+          && TCollection_AsciiString(theArgVec[anArgIter + 1]).IsIntegerValue())
+    {
+      Standard_Integer anIndexToActivate = TCollection_AsciiString(theArgVec[++anArgIter]).IntegerValue();
+      if (anIndexToActivate < 0)
+      {
+        Message::SendWarning ("Invalid negative triangulation index to be activated");
+        continue;
+      }
+      if (BRepTools::ActivateTriangulation (aShape, anIndexToActivate, false))
+      {
+        theDI << "The " << anIndexToActivate << " triangulation of shape " << theArgVec[1] << " was activated\n";
+      }
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && (anArgCase == "-activatestrict" || anArgCase == "-activateexact")
+          && TCollection_AsciiString(theArgVec[anArgIter + 1]).IsIntegerValue())
+    {
+      Standard_Integer anIndexToActivate = TCollection_AsciiString(theArgVec[++anArgIter]).IntegerValue();
+      if (anIndexToActivate < 0)
+      {
+        Message::SendWarning ("Invalid negative triangulation index to be activated");
+        continue;
+      }
+      if (BRepTools::ActivateTriangulation (aShape, anIndexToActivate, true))
+      {
+        theDI << "The " << anIndexToActivate << " triangulation of shape " << theArgVec[1] << " was activated\n";
+      }
+    }
+    else if (anArgCase == "-loadsingle")
+    {
+      Standard_Integer anIndexToSingleLoad = -1;
+      if (anArgIter + 1 < theNbArgs
+       && TCollection_AsciiString(theArgVec[anArgIter + 1]).IsIntegerValue())
+      {
+        anIndexToSingleLoad = TCollection_AsciiString(theArgVec[++anArgIter]).IntegerValue();
+      }
+      if (anIndexToSingleLoad < -1)
+      {
+        Message::SendWarning ("Invalid negative triangulation index to be single loaded");
+        continue;
+      }
+      // Unload all triangulations
+      if (BRepTools::UnloadAllTriangulations (aShape))
+      {
+        theDI << "All triangulations of shape " << theArgVec[1] << " were unloaded\n";
+      }
+      // Activate required triangulation
+      if (anIndexToSingleLoad > -1
+       && BRepTools::ActivateTriangulation (aShape, anIndexToSingleLoad))
+      {
+        theDI << "The " << anIndexToSingleLoad << " triangulation of shape " << theArgVec[1] << " was activated\n";
+      }
+      // Load active triangulation
+      if (BRepTools::LoadTriangulation (aShape))
+      {
+        theDI << "The " << anIndexToSingleLoad << " triangulation of shape " << theArgVec[1] << " was loaded\n";
+      }
+
+      continue;
+    }
+    else if (anArgCase == "-loadsingleexact" ||
+             anArgCase == "-loadsinglestrict")
+    {
+      Standard_Integer anIndexToSingleLoad = -1;
+      if (anArgIter + 1 < theNbArgs
+       && TCollection_AsciiString(theArgVec[anArgIter + 1]).IsIntegerValue())
+      {
+        anIndexToSingleLoad = TCollection_AsciiString(theArgVec[++anArgIter]).IntegerValue();
+      }
+      if (anIndexToSingleLoad <= -1)
+      {
+        Message::SendWarning ("Invalid negative triangulation index to be single loaded");
+        continue;
+      }
+      // Unload all triangulations
+      if (BRepTools::UnloadAllTriangulations (aShape))
+      {
+        theDI << "All triangulations of shape " << theArgVec[1] << " were unloaded\n";
+      }
+      // Load required triangulation
+      if (BRepTools::LoadTriangulation (aShape, anIndexToSingleLoad, true))
+      {
+        theDI << "The " << anIndexToSingleLoad << " triangulation of shape " << theArgVec[1] << " was loaded and activated\n";
+      }
+      continue;
+    }
+    else
+    {
+      theDI << "Syntax error: incorrect arguments";
+      return 1;
+    }
+  }
+  return 0;
+}
+
 //=======================================================================
 //function : trianglesinfo
 //purpose  : 
 //=======================================================================
-static Standard_Integer trianglesinfo(Draw_Interpretor& di, Standard_Integer n, const char** a)
+static Standard_Integer trianglesinfo (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec)
 {
-  if (n != 2) return 1;
-  TopoDS_Shape S = DBRep::Get(a[1]);
-  if (S.IsNull()) return 1;
-  TopExp_Explorer ex;
-  Handle(Poly_Triangulation) T;
-  TopLoc_Location L;
+  if (theNbArgs < 2)
+  {
+    Message::SendFail ("Syntax error: not enough arguments");
+    return 1;
+  }
+  TopoDS_Shape aShape = DBRep::Get (theArgVec[1]);
+  if (aShape.IsNull())
+  {
+    theDI << theArgVec[1] << " is not a shape\n";
+    return 1;
+  }
 
-  Standard_Real MaxDeflection = 0.0;
-  Standard_Integer nbtriangles = 0, nbnodes = 0, nbrepresentations = 0;
-  for (ex.Init(S, TopAbs_FACE); ex.More(); ex.Next()) {
-    TopoDS_Face F = TopoDS::Face(ex.Current());
-    T = BRep_Tool::Triangulation(F, L);
-    if (!T.IsNull()) {
-      nbtriangles += T->NbTriangles();
-      nbnodes += T->NbNodes();
-      if (T->Deflection() > MaxDeflection)
-        MaxDeflection = T->Deflection();
+  struct TriangulationStat
+  {
+    TriangulationStat()
+    : NbFaces (0),
+      NbEmptyFaces (0),
+      NbTriangles(0),
+      NbDeferredFaces (0),
+      NbUnloadedFaces (0),
+      NbUnloadedTriangles (0) {}
+
+    NCollection_IndexedDataMap<Handle(Standard_Type), Standard_Integer> TypeMap;
+    Standard_Integer NbFaces;
+    Standard_Integer NbEmptyFaces;
+    Standard_Integer NbTriangles;
+    Standard_Integer NbDeferredFaces;
+    Standard_Integer NbUnloadedFaces;
+    Standard_Integer NbUnloadedTriangles;
+  };
+
+  Standard_Boolean toPrintLODs = false;
+  if (theNbArgs > 2)
+  {
+    TCollection_AsciiString anArgCase(theArgVec[2]);
+    anArgCase.LowerCase();
+    if (anArgCase == "-lods")
+    {
+      toPrintLODs = true;
+    }
+  }
+
+  TopExp_Explorer anExp;
+  Handle(Poly_Triangulation) aTriangulation;
+  TopLoc_Location aLoc;
+  Standard_Real aMaxDeflection = 0.0;
+  Standard_Integer aNbFaces = 0, aNbEmptyFaces = 0, aNbTriangles = 0, aNbNodes = 0, aNbRepresentations = 0;
+  NCollection_IndexedDataMap<Standard_Integer, TriangulationStat> aLODsStat;
+  NCollection_Vector<Standard_Integer> aNbLODs;
+  for (anExp.Init (aShape, TopAbs_FACE); anExp.More(); anExp.Next())
+  {
+    TopoDS_Face aFace = TopoDS::Face (anExp.Current());
+    aNbFaces++;
+    aTriangulation = BRep_Tool::Triangulation (aFace, aLoc);
+    if (!aTriangulation.IsNull())
+    {
+      aNbTriangles += aTriangulation->NbTriangles();
+      aNbNodes += aTriangulation->NbNodes();
+      if (aTriangulation->Deflection() > aMaxDeflection)
+      {
+        aMaxDeflection = aTriangulation->Deflection();
+      }
+    }
+    else
+    {
+      aNbEmptyFaces++;
+    }
+    if (toPrintLODs)
+    {
+      // Collect LODs information
+      const Poly_ListOfTriangulation& aLODs = BRep_Tool::Triangulations (aFace, aLoc);
+      if (aLODs.Size() != 0)
+      {
+        aNbLODs.Append (aLODs.Size());
+      }
+      Standard_Integer aTriangIndex = 0;
+      for (Poly_ListOfTriangulation::Iterator anIter(aLODs); anIter.More(); anIter.Next(), ++aTriangIndex)
+      {
+        TriangulationStat* aStats = aLODsStat.ChangeSeek (aTriangIndex);
+        if (aStats == NULL)
+        {
+          Standard_Integer aNewIndex = aLODsStat.Add (aTriangIndex, TriangulationStat());
+          aStats = &aLODsStat.ChangeFromIndex (aNewIndex);
+        }
+        aStats->NbFaces++;
+        const Handle(Poly_Triangulation)& aLOD = anIter.Value();
+        if (aLOD.IsNull())
+        {
+          aStats->NbEmptyFaces++;
+          continue;
+        }
+        Standard_Integer* aDynTypeCounter = aStats->TypeMap.ChangeSeek (aLOD->DynamicType());
+        if (aDynTypeCounter == NULL)
+        {
+          Standard_Integer aNewIndex = aStats->TypeMap.Add (aLOD->DynamicType(), 0);
+          aDynTypeCounter = &aStats->TypeMap.ChangeFromIndex (aNewIndex);
+        }
+        (*aDynTypeCounter)++;
+        aStats->NbTriangles += aLOD->NbTriangles();
+        if (aLOD->HasDeferredData())
+        {
+          aStats->NbDeferredFaces++;
+          if (!aLOD->HasGeometry())
+          {
+            aStats->NbUnloadedFaces++;
+            aStats->NbUnloadedTriangles += aLOD->NbDeferredTriangles();
+          }
+        }
+        else if (!aLOD->HasGeometry())
+        {
+          aStats->NbEmptyFaces++;
+        }
+      }
     }
   }
   TopTools_IndexedMapOfShape anEdges;
-  TopExp::MapShapes(S, TopAbs_EDGE, anEdges);
+  TopExp::MapShapes (aShape, TopAbs_EDGE, anEdges);
   for (int i = 1; i<=anEdges.Extent(); ++i)
   {
     const TopoDS_Edge& anEdge = TopoDS::Edge(anEdges(i));
@@ -467,19 +765,105 @@ static Standard_Integer trianglesinfo(Draw_Interpretor& di, Standard_Integer n,
       aCR = anIterCR.Value();
       if (aCR->IsPolygonOnTriangulation())
       {
-        nbrepresentations++;
+        aNbRepresentations++;
       }
       anIterCR.Next();
     }
   }
 
-  di<<"\n";
-  di << "This shape contains " << nbtriangles << " triangles.\n";
-  di << "                    " << nbnodes << " nodes.\n";
-  di << "                    " << nbrepresentations << " polygons on triangulation .\n";;
-  di << "Maximal deflection " << MaxDeflection << "\n";
-  
-  di<<"\n";
+  theDI <<"\n";
+  theDI << "This shape contains " << aNbFaces << " faces.\n";
+  if (aNbEmptyFaces > 0)
+  {
+    theDI << "                    " << aNbEmptyFaces << " empty faces.\n";
+  }
+  theDI << "                    " << aNbTriangles << " triangles.\n";
+  theDI << "                    " << aNbNodes << " nodes.\n";
+  theDI << "                    " << aNbRepresentations << " polygons on triangulation.\n";
+  theDI << "Maximal deflection " << aMaxDeflection << "\n";
+
+  if (aNbLODs.Size() > 0)
+  {
+    // Find all different numbers of triangulation LODs and their average value per face
+    if (aNbLODs.Size() > 1)
+    {
+      std::sort (aNbLODs.begin(), aNbLODs.end());
+    }
+    NCollection_IndexedMap<Standard_Integer> aLODsRange;
+    for (NCollection_Vector<Standard_Integer>::Iterator aNbIter(aNbLODs); aNbIter.More(); aNbIter.Next())
+    {
+      if (!aLODsRange.Contains (aNbIter.Value()))
+      {
+        aLODsRange.Add (aNbIter.Value());
+      }
+    }
+    TCollection_AsciiString aLODsRangeStr;
+    Standard_Integer anIndex = 0;
+    for (NCollection_IndexedMap<Standard_Integer>::Iterator aRangeIter(aLODsRange); aRangeIter.More(); aRangeIter.Next(), anIndex++)
+    {
+      aLODsRangeStr += TCollection_AsciiString(aRangeIter.Value());
+      if (anIndex < aLODsRange.Size() - 1)
+      {
+        aLODsRangeStr += " ";
+      }
+    }
+    theDI << TCollection_AsciiString("Number of triangulation LODs [") + aLODsRangeStr + "]\n";
+    if (aLODsRange.Size() > 1)
+    {
+      // Find average number of triangulation LODs per face
+      Standard_Integer aMedian = aNbLODs.Value (aNbLODs.Lower() + aNbLODs.Size() / 2);
+      if ((aNbLODs.Size() % 2) == 0)
+      {
+        aMedian += aNbLODs.Value (aNbLODs.Lower() + aNbLODs.Size() / 2 - 1);
+        aMedian /= 2;
+      }
+      theDI << TCollection_AsciiString("                             [average per face: ") + aMedian + "]\n";
+    }
+  }
+  if (!aLODsStat.IsEmpty())
+  {
+    TCollection_AsciiString aLODsStatStr;
+    for (NCollection_IndexedDataMap<Standard_Integer, TriangulationStat>::Iterator anIter(aLODsStat);
+         anIter.More(); anIter.Next())
+    {
+      const TriangulationStat& aLodStat = anIter.Value();
+      aLODsStatStr += TCollection_AsciiString("LOD #") + anIter.Key() + ". ";
+      //aLODsStatStr += TCollection_AsciiString("NbFaces: ") + aLodStat.NbFaces;
+      if (aLodStat.NbEmptyFaces > 0 || aLodStat.NbFaces < aNbFaces)
+      {
+        const Standard_Integer aNbEmpty = aLodStat.NbEmptyFaces + (aNbFaces - aLodStat.NbFaces);
+        aLODsStatStr += TCollection_AsciiString("NbEmpty: ") + aNbEmpty + ", ";
+      }
+      aLODsStatStr += TCollection_AsciiString("NbTris: ") + aLodStat.NbTriangles;
+      if (aLodStat.NbDeferredFaces > 0)
+      {
+        aLODsStatStr += TCollection_AsciiString(", NbDeferred: ") + aLodStat.NbDeferredFaces;
+        if (aLodStat.NbUnloadedFaces > 0)
+        {
+          aLODsStatStr += TCollection_AsciiString(", NbUnloaded: ") + aLodStat.NbUnloadedFaces + ", NbUnloadedTris: " + aLodStat.NbUnloadedTriangles;
+        }
+      }
+      aLODsStatStr += ".\n";
+
+      // Add types
+      aLODsStatStr += TCollection_AsciiString("        Types: ");
+      Standard_Integer aCounter = 0;
+      for (NCollection_IndexedDataMap<Handle(Standard_Type), Standard_Integer>::Iterator aTypeIter(aLodStat.TypeMap);
+           aTypeIter.More(); aTypeIter.Next(), aCounter++)
+      {
+        aLODsStatStr += TCollection_AsciiString(aTypeIter.Key()->Name()) + " (" + aTypeIter.Value() + ")";
+        if (aCounter < aLodStat.TypeMap.Size() - 1)
+        {
+          aLODsStatStr += TCollection_AsciiString(", ");
+        }
+      }
+      aLODsStatStr += ".\n";
+    }
+
+    theDI << aLODsStatStr;
+  }
+  theDI << "\n";
+
 #ifdef OCCT_DEBUG_MESH_CHRONO
   Standard_Real tot, addp, unif, contr, inter;
   Standard_Real edges, mailledges, etuinter, lastcontrol, stock;
@@ -494,40 +878,40 @@ static Standard_Integer trianglesinfo(Draw_Interpretor& di, Standard_Integer n,
   chPointValid.Show(pointvalid); chIsos.Show(isos); chPointsOnIsos.Show(pointsisos);
 
   if (tot > 0.00001) {
-    di <<"temps total de maillage:     "<<tot        <<" seconds\n";
-    di <<"dont: \n";
-    di <<"discretisation des edges:    "<<edges      <<" seconds---> "<< 100*edges/tot      <<" %\n";
-    di <<"maillage des edges:          "<<mailledges <<" seconds---> "<< 100*mailledges/tot <<" %\n";
-    di <<"controle et points internes: "<<etuinter   <<" seconds---> "<< 100*etuinter/tot   <<" %\n";
-    di <<"derniers controles:          "<<lastcontrol<<" seconds---> "<< 100*lastcontrol/tot<<" %\n";
-    di <<"stockage dans la S.D.        "<<stock      <<" seconds---> "<< 100*stock/tot      <<" %\n";
-    di << "\n";
-    di <<"et plus precisement: \n";
-    di <<"Add 11ere partie :           "<<add11     <<" seconds---> "<<100*add11/tot      <<" %\n";
-    di <<"Add 12ere partie :           "<<add12     <<" seconds---> "<<100*add12/tot      <<" %\n";
-    di <<"Add 2eme partie :            "<<add2      <<" seconds---> "<<100*add2/tot       <<" %\n";
-    di <<"Update :                     "<<upda      <<" seconds---> "<<100*upda/tot       <<" %\n";
-    di <<"AddPoint :                   "<<addp      <<" seconds---> "<<100*addp/tot       <<" %\n";
-    di <<"UniformDeflection            "<<unif      <<" seconds---> "<<100*unif/tot       <<" %\n";
-    di <<"Controle :                   "<<contr     <<" seconds---> "<<100*contr/tot      <<" %\n";
-    di <<"Points Internes:             "<<inter     <<" seconds---> "<<100*inter/tot      <<" %\n";
-    di <<"calcul des isos et du, dv:   "<<isos      <<" seconds---> "<<100*isos/tot       <<" %\n";
-    di <<"calcul des points sur isos:  "<<pointsisos<<" seconds---> "<<100*pointsisos/tot <<" %\n";
-    di <<"IsPointValid:                "<<pointvalid<<" seconds---> "<<100*pointvalid/tot <<" %\n";
-    di << "\n";
-
-
-    di <<"nombre d'appels de controle apres points internes          : "<< NbControls << "\n";
-    di <<"nombre de points sur restrictions                          : "<< D0Edges    << "\n";
-    di <<"nombre de points calcules par UniformDeflection            : "<< D0Unif     << "\n";
-    di <<"nombre de points calcules dans InternalVertices            : "<< D0Internal << "\n";
-    di <<"nombre de points calcules dans Control                     : "<< D0Control  << "\n";
+    theDI <<"temps total de maillage:     "<<tot        <<" seconds\n";
+    theDI <<"dont: \n";
+    theDI <<"discretisation des edges:    "<<edges      <<" seconds---> "<< 100*edges/tot      <<" %\n";
+    theDI <<"maillage des edges:          "<<mailledges <<" seconds---> "<< 100*mailledges/tot <<" %\n";
+    theDI <<"controle et points internes: "<<etuinter   <<" seconds---> "<< 100*etuinter/tot   <<" %\n";
+    theDI <<"derniers controles:          "<<lastcontrol<<" seconds---> "<< 100*lastcontrol/tot<<" %\n";
+    theDI <<"stockage dans la S.D.        "<<stock      <<" seconds---> "<< 100*stock/tot      <<" %\n";
+    theDI << "\n";
+    theDI <<"et plus precisement: \n";
+    theDI <<"Add 11ere partie :           "<<add11     <<" seconds---> "<<100*add11/tot      <<" %\n";
+    theDI <<"Add 12ere partie :           "<<add12     <<" seconds---> "<<100*add12/tot      <<" %\n";
+    theDI <<"Add 2eme partie :            "<<add2      <<" seconds---> "<<100*add2/tot       <<" %\n";
+    theDI <<"Update :                     "<<upda      <<" seconds---> "<<100*upda/tot       <<" %\n";
+    theDI <<"AddPoint :                   "<<addp      <<" seconds---> "<<100*addp/tot       <<" %\n";
+    theDI <<"UniformDeflection            "<<unif      <<" seconds---> "<<100*unif/tot       <<" %\n";
+    theDI <<"Controle :                   "<<contr     <<" seconds---> "<<100*contr/tot      <<" %\n";
+    theDI <<"Points Internes:             "<<inter     <<" seconds---> "<<100*inter/tot      <<" %\n";
+    theDI <<"calcul des isos et du, dv:   "<<isos      <<" seconds---> "<<100*isos/tot       <<" %\n";
+    theDI <<"calcul des points sur isos:  "<<pointsisos<<" seconds---> "<<100*pointsisos/tot <<" %\n";
+    theDI <<"IsPointValid:                "<<pointvalid<<" seconds---> "<<100*pointvalid/tot <<" %\n";
+    theDI << "\n";
+
+
+    theDI <<"nombre d'appels de controle apres points internes          : "<< NbControls << "\n";
+    theDI <<"nombre de points sur restrictions                          : "<< D0Edges    << "\n";
+    theDI <<"nombre de points calcules par UniformDeflection            : "<< D0Unif     << "\n";
+    theDI <<"nombre de points calcules dans InternalVertices            : "<< D0Internal << "\n";
+    theDI <<"nombre de points calcules dans Control                     : "<< D0Control  << "\n";
     if (nbnodes-D0Edges != 0) { 
       Standard_Real ratio = (Standard_Real)(D0Internal+D0Control)/ (Standard_Real)(nbnodes-D0Edges);
-      di <<"---> Ratio: (D0Internal+D0Control) / (nbNodes-nbOnEdges)   : "<< ratio      << "\n";
+      theDI <<"---> Ratio: (D0Internal+D0Control) / (nbNodes-nbOnEdges)   : "<< ratio      << "\n";
     }
 
-    di << "\n";
+    theDI << "\n";
 
     chTotal.Reset(); chAddPoint.Reset(); chUnif.Reset(); 
     chControl.Reset(); chInternal.Reset();
@@ -1003,10 +1387,31 @@ void  MeshTest::Commands(Draw_Interpretor& theCommands)
   theCommands.Add("MemLeakTest","MemLeakTest",__FILE__, MemLeakTest, g);
 
   theCommands.Add("tri2d", "tri2d facename",__FILE__, tri2d, g);
-  theCommands.Add("trinfo","trinfo name, print triangles information on objects",__FILE__,trianglesinfo,g);
+  theCommands.Add("trinfo",
+                  "trinfo shapeName [-lods], print triangles information on objects"
+                  "\n\t\t: -lods Print detailed LOD information",
+                  __FILE__,trianglesinfo,g);
   theCommands.Add("veriftriangles","veriftriangles name, verif triangles",__FILE__,veriftriangles,g);
   theCommands.Add("wavefront","wavefront name",__FILE__, wavefront, g);
   theCommands.Add("triepoints", "triepoints shape1 [shape2 ...]",__FILE__, triedgepoints, g);
-
+  theCommands.Add("trlateload",
+                  "trlateload shapeName"
+                  "\n\t\t:   [-load {-1|Index|ALL}=-1] [-unload {-1|Index|ALL}=-1]"
+                  "\n\t\t:   [-activate Index] [-activateExact Index]"
+                  "\n\t\t:   [-loadSingle {-1|Index}=-1] [-loadSingleExact {Index}=-1]"
+                  "\n\t\t: Interaction with deferred triangulations."
+                  "\n\t\t:   '-load'            - load triangulation (-1 - currently active one, Index - with defined index,"
+                  "\n\t\t:                      ALL - all available ones)"
+                  "\n\t\t:   '-unload'          - unload triangulation (-1 - currently active one, Index - with defined index,"
+                  "\n\t\t:                      ALL - all available ones)"
+                  "\n\t\t:   '-activate'        - activate triangulation with defined index. If it doesn't exist -"
+                  "\n\t\t:                      activate the last available triangulation."
+                  "\n\t\t:   '-activateExact'   - activate exactly triangulation with defined index or do nothing."
+                  "\n\t\t:   '-loadSingle'      - make loaded and active ONLY specified triangulation (-1 - currently active one,"
+                  "\n\t\t:                      Index - with defined index or last available if it doesn't exist)."
+                  "\n\t\t:                      All other triangulations will be unloaded."
+                  "\n\t\t:   '-loadSingleExact' - make loaded and active ONLY exactly specified triangulation. All other triangulations"
+                  "\n\t\t:                      will be unloaded. If triangulation with such Index doesn't exist do nothing",
+                  __FILE__, TrLateLoad, g);
   theCommands.Add("correctnormals", "correctnormals shape",__FILE__, correctnormals, g);
 }
index 28292e4..32383f2 100755 (executable)
@@ -21,6 +21,7 @@ Poly_HArray1OfTriangle.hxx
 Poly_ListOfTriangulation.hxx
 Poly_MakeLoops.cxx
 Poly_MakeLoops.hxx
+Poly_MeshPurpose.hxx
 Poly_Polygon2D.cxx
 Poly_Polygon2D.hxx
 Poly_Polygon3D.cxx
diff --git a/src/Poly/Poly_MeshPurpose.hxx b/src/Poly/Poly_MeshPurpose.hxx
new file mode 100644 (file)
index 0000000..fcc8e11
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (c) 2021 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Poly_MeshPurpose_HeaderFile
+#define _Poly_MeshPurpose_HeaderFile
+
+//! Purpose of triangulation using.
+typedef unsigned int Poly_MeshPurpose;
+enum
+{
+  // main flags
+  Poly_MeshPurpose_NONE               = 0,      //!< no special use (default)
+  Poly_MeshPurpose_Calculation        = 0x0001, //!< mesh for algorithms
+  Poly_MeshPurpose_Presentation       = 0x0002, //!< mesh for presentation (LODs usage)
+  // special purpose bits (should not be set externally)
+  Poly_MeshPurpose_Active             = 0x0004, //!< mesh marked as currently active in a list
+  Poly_MeshPurpose_Loaded             = 0x0008, //!< mesh has currently loaded data
+  Poly_MeshPurpose_AnyFallback        = 0x0010, //!< a special flag for BRep_Tools::Triangulation() to return any other defined mesh,
+                                                //   if none matching other criteria was found user-defined flags should have higher values
+  Poly_MeshPurpose_USER               = 0x0020  //!< application-defined flags
+};
+
+#endif // _Poly_MeshPurpose_HeaderFile
index 647238b..95f369e 100644 (file)
@@ -17,6 +17,7 @@
 #include <Poly_Triangulation.hxx>
 
 #include <gp_Pnt.hxx>
+#include <OSD_FileSystem.hxx>
 #include <Poly_Triangle.hxx>
 #include <Standard_Dump.hxx>
 #include <Standard_Type.hxx>
@@ -29,7 +30,8 @@ IMPLEMENT_STANDARD_RTTIEXT (Poly_Triangulation, Standard_Transient)
 //=======================================================================
 Poly_Triangulation::Poly_Triangulation()
 : myCachedMinMax (NULL),
-  myDeflection   (0)
+  myDeflection   (0),
+  myPurpose      (Poly_MeshPurpose_NONE)
 {
   //
 }
@@ -45,7 +47,8 @@ Poly_Triangulation::Poly_Triangulation (const Standard_Integer theNbNodes,
 : myCachedMinMax (NULL),
   myDeflection(0),
   myNodes     (theNbNodes),
-  myTriangles (1, theNbTriangles)
+  myTriangles (1, theNbTriangles),
+  myPurpose   (Poly_MeshPurpose_NONE)
 {
   if (theHasUVNodes)
   {
@@ -66,7 +69,8 @@ Poly_Triangulation::Poly_Triangulation (const TColgp_Array1OfPnt&    theNodes,
 : myCachedMinMax (NULL),
   myDeflection   (0),
   myNodes        (theNodes.Length()),
-  myTriangles    (1, theTriangles.Length())
+  myTriangles    (1, theTriangles.Length()),
+  myPurpose      (Poly_MeshPurpose_NONE)
 {
   const Poly_ArrayOfNodes aNodeWrapper (theNodes.First(), theNodes.Length());
   myNodes = aNodeWrapper;
@@ -85,7 +89,8 @@ Poly_Triangulation::Poly_Triangulation (const TColgp_Array1OfPnt&    theNodes,
   myDeflection   (0),
   myNodes        (theNodes.Length()),
   myTriangles    (1, theTriangles.Length()),
-  myUVNodes      (theNodes.Length())
+  myUVNodes      (theNodes.Length()),
+  myPurpose      (Poly_MeshPurpose_NONE)
 {
   const Poly_ArrayOfNodes aNodeWrapper (theNodes.First(), theNodes.Length());
   myNodes = aNodeWrapper;
@@ -124,11 +129,33 @@ Poly_Triangulation::Poly_Triangulation (const Handle(Poly_Triangulation)& theTri
   myNodes     (theTriangulation->myNodes),
   myTriangles (theTriangulation->myTriangles),
   myUVNodes   (theTriangulation->myUVNodes),
-  myNormals   (theTriangulation->myNormals)
+  myNormals   (theTriangulation->myNormals),
+  myPurpose   (theTriangulation->myPurpose)
 {
   SetCachedMinMax (theTriangulation->CachedMinMax());
 }
 
+//=======================================================================
+//function : Clear
+//purpose  : 
+//=======================================================================
+void Poly_Triangulation::Clear()
+{
+  if (!myNodes.IsEmpty())
+  {
+    Poly_ArrayOfNodes anEmptyNodes;
+    anEmptyNodes.SetDoublePrecision (myNodes.IsDoublePrecision());
+    myNodes.Move (anEmptyNodes);
+  }
+  if (!myTriangles.IsEmpty())
+  {
+    Poly_Array1OfTriangle anEmptyTriangles;
+    myTriangles.Move(anEmptyTriangles);
+  }
+  RemoveUVNodes();
+  RemoveNormals();
+}
+
 //=======================================================================
 //function : RemoveUVNodes
 //purpose  :
@@ -354,6 +381,8 @@ void Poly_Triangulation::DumpJson (Standard_OStream& theOStream, Standard_Intege
   if (!myNormals.IsEmpty())
     OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNormals.Size())
   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTriangles.Size())
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPurpose)
+
 }
 
 // =======================================================================
@@ -483,3 +512,55 @@ void Poly_Triangulation::ComputeNormals()
     aNorm3f = aMod == 0.0f ? gp_Vec3f (0.0f, 0.0f, 1.0f) : (aNorm3f / aMod);
   }
 }
+
+//=======================================================================
+//function : LoadDeferredData
+//purpose  :
+//=======================================================================
+Standard_Boolean Poly_Triangulation::LoadDeferredData (const Handle(OSD_FileSystem)& theFileSystem)
+{
+  if (!HasDeferredData())
+  {
+    return false;
+  }
+  if (!loadDeferredData (theFileSystem, this))
+  {
+    return false;
+  }
+  SetMeshPurpose (myPurpose | Poly_MeshPurpose_Loaded);
+  return true;
+}
+
+//=======================================================================
+//function : DetachedLoadDeferredData
+//purpose  :
+//=======================================================================
+Handle(Poly_Triangulation) Poly_Triangulation::DetachedLoadDeferredData (const Handle(OSD_FileSystem)& theFileSystem) const
+{
+  if (!HasDeferredData())
+  {
+    return Handle(Poly_Triangulation)();
+  }
+  Handle(Poly_Triangulation) aResult = createNewEntity();
+  if (!loadDeferredData(theFileSystem, aResult))
+  {
+    return Handle(Poly_Triangulation)();
+  }
+  aResult->SetMeshPurpose(aResult->MeshPurpose() | Poly_MeshPurpose_Loaded);
+  return aResult;
+}
+
+//=======================================================================
+//function : UnloadDeferredData
+//purpose  :
+//=======================================================================
+Standard_Boolean Poly_Triangulation::UnloadDeferredData()
+{
+  if (HasDeferredData())
+  {
+    Clear();
+    SetMeshPurpose (myPurpose & ~Poly_MeshPurpose_Loaded);
+    return true;
+  }
+  return false;
+}
index 48b4ad0..ae97694 100644 (file)
 #include <Poly_HArray1OfTriangle.hxx>
 #include <Poly_ArrayOfNodes.hxx>
 #include <Poly_ArrayOfUVNodes.hxx>
+#include <Poly_MeshPurpose.hxx>
 #include <TColgp_HArray1OfPnt.hxx>
 #include <TColgp_HArray1OfPnt2d.hxx>
 #include <TShort_HArray1OfShortReal.hxx>
 
+class OSD_FileSystem;
 class Poly_Triangulation;
 DEFINE_STANDARD_HANDLE(Poly_Triangulation, Standard_Transient)
 
@@ -105,6 +107,9 @@ public:
   //! See more on deflection in Polygon2D
   void Deflection (const Standard_Real theDeflection) { myDeflection = theDeflection; }
 
+  //! Clears internal arrays of nodes and all attributes.
+  Standard_EXPORT virtual void Clear();
+
   //! Returns TRUE if triangulation has some geometry.
   virtual Standard_Boolean HasGeometry() const { return !myNodes.IsEmpty() && !myTriangles.IsEmpty(); }
 
@@ -180,6 +185,12 @@ public:
                                    float(theNormal.Z())));
   }
 
+  //! Returns mesh purpose bits.
+  Poly_MeshPurpose MeshPurpose() const { return myPurpose; }
+
+  //! Sets mesh purpose bits.
+  void SetMeshPurpose (const Poly_MeshPurpose thePurpose) { myPurpose = thePurpose; }
+
   //! Returns cached min - max range of triangulation data,
   //! which is VOID by default (e.g, no cached information).
   Standard_EXPORT const Bnd_Box& CachedMinMax() const;
@@ -246,7 +257,7 @@ public:
   //! If an array for normals is not allocated yet, do it now.
   Standard_EXPORT void AddNormals();
 
-  //! Deallocates the Normals array.
+  //! Deallocates the normals array.
   Standard_EXPORT void RemoveNormals();
 
   //! Compute smooth normals by averaging triangle normals.
@@ -304,6 +315,50 @@ public:
   Standard_DEPRECATED("Deprecated method, SetTriangle() should be used instead")
   Poly_Triangle& ChangeTriangle (const Standard_Integer theIndex) { return myTriangles.ChangeValue (theIndex); }
 
+public: //! @name late-load deferred data interface
+
+  //! Returns number of deferred nodes that can be loaded using LoadDeferredData().
+  //! Note: this is estimated values, which might be different from actually loaded values.
+  //! Always check triangulation size of actually loaded data in code to avoid out-of-range issues.
+  virtual Standard_Integer NbDeferredNodes() const { return 0; }
+
+  //! Returns number of deferred triangles that can be loaded using LoadDeferredData().
+  //! Note: this is estimated values, which might be different from actually loaded values
+  //! Always check triangulation size of actually loaded data in code to avoid out-of-range issues.
+  virtual Standard_Integer NbDeferredTriangles() const { return 0; }
+
+  //! Returns TRUE if there is some triangulation data that can be loaded using LoadDeferredData().
+  virtual Standard_Boolean HasDeferredData() const { return NbDeferredTriangles() > 0; }
+
+  //! Loads triangulation data into itself
+  //! from some deferred storage using specified shared input file system.
+  Standard_EXPORT virtual Standard_Boolean LoadDeferredData (const Handle(OSD_FileSystem)& theFileSystem = Handle(OSD_FileSystem)());
+
+  //! Loads triangulation data into new Poly_Triangulation object
+  //! from some deferred storage using specified shared input file system.
+  Standard_EXPORT virtual Handle(Poly_Triangulation) DetachedLoadDeferredData
+    (const Handle(OSD_FileSystem)& theFileSystem = Handle(OSD_FileSystem)()) const;
+
+  //! Releases triangulation data if it has connected deferred storage.
+  Standard_EXPORT virtual Standard_Boolean UnloadDeferredData();
+
+protected:
+
+  //! Creates new triangulation object (can be inheritor of Poly_Triangulation).
+  virtual Handle(Poly_Triangulation) createNewEntity() const
+  {
+    return new Poly_Triangulation();
+  }
+
+  //! Load triangulation data from deferred storage using specified shared input file system.
+  virtual Standard_Boolean loadDeferredData (const Handle(OSD_FileSystem)& theFileSystem,
+                                             const Handle(Poly_Triangulation)& theDestTriangulation) const
+  {
+    (void )theFileSystem;
+    (void )theDestTriangulation;
+    return false;
+  }
+
 protected:
 
   //! Clears cached min - max range saved previously.
@@ -321,6 +376,7 @@ protected:
   Poly_Array1OfTriangle        myTriangles;
   Poly_ArrayOfUVNodes          myUVNodes;
   NCollection_Array1<gp_Vec3f> myNormals;
+  Poly_MeshPurpose             myPurpose;
 
 };
 
index 3e9b17f..d282190 100644 (file)
@@ -31,7 +31,7 @@ void Prs3d::AddFreeEdges (TColgp_SequenceOfPnt& theSegments,
                           const Handle(Poly_Triangulation)& thePolyTri,
                           const gp_Trsf& theLocation)
 {
-  if (thePolyTri.IsNull())
+  if (thePolyTri.IsNull() || !thePolyTri->HasGeometry())
   {
     return;
   }
index 42fc956..e9d204c 100644 (file)
@@ -23,8 +23,6 @@ RWGltf_GltfJsonParser.cxx
 RWGltf_GltfJsonParser.hxx
 RWGltf_GltfOStreamWriter.hxx
 RWGltf_GltfSceneNodeMap.hxx
-RWGltf_PrimitiveArrayReader.cxx
-RWGltf_PrimitiveArrayReader.hxx
 RWGltf_TriangulationReader.cxx
 RWGltf_TriangulationReader.hxx
 RWGltf_WriterTrsfFormat.hxx
index 87c443d..05bef91 100644 (file)
@@ -38,7 +38,6 @@ public:
   struct GltfReaderTLS
   {
     Handle(OSD_FileSystem) FileSystem;
-    Handle(RWGltf_PrimitiveArrayReader) Reader;
   };
 
   //! Main constructor.
@@ -62,12 +61,6 @@ public:
                    int theFaceIndex) const
   {
     GltfReaderTLS& aTlsData = myTlsData.ChangeValue (theThreadIndex);
-    if (aTlsData.Reader.IsNull())
-    {
-      aTlsData.Reader = myCafReader->createMeshReaderContext();
-      aTlsData.Reader->SetErrorPrefix (myErrPrefix);
-      aTlsData.Reader->SetCoordinateSystemConverter (myCafReader->myCoordSysConverter);
-    }
     if (aTlsData.FileSystem.IsNull())
     {
       aTlsData.FileSystem = new OSD_CachedFileSystem();
@@ -76,9 +69,16 @@ public:
     TopLoc_Location aDummyLoc;
     TopoDS_Face& aFace = myFaceList->ChangeValue (theFaceIndex);
     Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (aFace, aDummyLoc));
-    Handle(Poly_Triangulation) aPolyData = aTlsData.Reader->Load (aLateData, aTlsData.FileSystem);
-    BRep_Builder aBuilder;
-    aBuilder.UpdateFace (aFace, aPolyData);
+    if (myCafReader->ToKeepLateData())
+    {
+      aLateData->LoadDeferredData (aTlsData.FileSystem);
+    }
+    else
+    {
+      Handle(Poly_Triangulation) aPolyData = aLateData->DetachedLoadDeferredData (aTlsData.FileSystem);
+      BRep_Builder aBuilder;
+      aBuilder.UpdateFace (aFace, aPolyData); // replace all "proxy"-triangulations of face by loaded active one.
+    }
 
     if (myThreadPool.HasThreads())
     {
@@ -110,7 +110,10 @@ RWGltf_CafReader::RWGltf_CafReader()
 : myToParallel (false),
   myToSkipEmptyNodes (true),
   myUseMeshNameAsFallback (true),
-  myIsDoublePrecision (false)
+  myIsDoublePrecision (false),
+  myToSkipLateDataLoading (false),
+  myToKeepLateData (true),
+  myToPrintDebugMessages (false)
 {
   myCoordSysConverter.SetInputLengthUnit (1.0); // glTF defines model in meters
   myCoordSysConverter.SetInputCoordinateSystem (RWMesh_CoordinateSystem_glTF);
@@ -282,10 +285,13 @@ Standard_Boolean RWGltf_CafReader::performMesh (const TCollection_AsciiString& t
 // Function : createMeshReaderContext
 // Purpose  :
 //================================================================
-Handle(RWGltf_PrimitiveArrayReader) RWGltf_CafReader::createMeshReaderContext()
+Handle(RWMesh_TriangulationReader) RWGltf_CafReader::createMeshReaderContext() const
 {
   Handle(RWGltf_TriangulationReader) aReader = new RWGltf_TriangulationReader();
   aReader->SetDoublePrecision (myIsDoublePrecision);
+  aReader->SetCoordinateSystemConverter (myCoordSysConverter);
+  aReader->SetToSkipDegenerates (false);
+  aReader->SetToPrintDebugMessages (myToPrintDebugMessages);
   return aReader;
 }
 
@@ -297,6 +303,16 @@ Standard_Boolean RWGltf_CafReader::readLateData (NCollection_Vector<TopoDS_Face>
                                                  const TCollection_AsciiString& theFile,
                                                  const Message_ProgressRange& theProgress)
 {
+  Handle(RWGltf_TriangulationReader) aReader = Handle(RWGltf_TriangulationReader)::DownCast(createMeshReaderContext());
+  aReader->SetFileName (theFile);
+  updateLateDataReader (theFaces, aReader);
+  if (myToSkipLateDataLoading)
+  {
+    return Standard_True;
+  }
+
+  aReader->StartStatistic();
+
   const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
   const int aNbThreads = myToParallel ? Min (theFaces.Size(), aThreadPool->NbDefaultThreadsToLaunch()) : 1;
   OSD_ThreadPool::Launcher aLauncher (*aThreadPool, aNbThreads);
@@ -304,5 +320,31 @@ Standard_Boolean RWGltf_CafReader::readLateData (NCollection_Vector<TopoDS_Face>
   CafReader_GltfReaderFunctor aFunctor (this, theFaces, theProgress, aLauncher,
                                         TCollection_AsciiString ("File '") + theFile + "' defines invalid glTF!\n");
   aLauncher.Perform (theFaces.Lower(), theFaces.Upper() + 1, aFunctor);
+
+  aReader->PrintStatistic();
+  aReader->StopStatistic();
+
   return Standard_True;
 }
+
+//================================================================
+// Function : updateLateDataReader
+// Purpose  :
+//================================================================
+void RWGltf_CafReader::updateLateDataReader (NCollection_Vector<TopoDS_Face>& theFaces,
+                                             const Handle(RWMesh_TriangulationReader)& theReader) const
+{
+  TopLoc_Location aDummyLoc;
+  for (NCollection_Vector<TopoDS_Face>::Iterator aFaceIter(theFaces); aFaceIter.More(); aFaceIter.Next())
+  {
+    const TopoDS_Face& aFace = aFaceIter.Value();
+    for (Poly_ListOfTriangulation::Iterator anIter(BRep_Tool::Triangulations (aFace, aDummyLoc)); anIter.More(); anIter.Next())
+    {
+      Handle(RWGltf_GltfLatePrimitiveArray) aData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(anIter.Value());
+      if (!aData.IsNull())
+      {
+        aData->SetReader (theReader);
+      }
+    }
+  }
+}
index fce1c26..b99db7c 100644 (file)
@@ -20,7 +20,7 @@
 #include <RWMesh_CafReader.hxx>
 #include <TopoDS_Face.hxx>
 
-class RWGltf_PrimitiveArrayReader;
+class RWMesh_TriangulationReader;
 
 //! The glTF (GL Transmission Format) mesh reader into XDE document.
 class RWGltf_CafReader : public RWMesh_CafReader
@@ -55,6 +55,26 @@ public:
   //! Set flag to fill in triangulation using double or single precision.
   void SetDoublePrecision (bool theIsDouble) { myIsDoublePrecision = theIsDouble; }
 
+  //! Returns TRUE if data loading should be skipped and can be performed later; FALSE by default.
+  bool ToSkipLateDataLoading() { return myToSkipLateDataLoading; }
+
+  //! Sets flag to skip data loading.
+  void SetToSkipLateDataLoading (bool theToSkip) { myToSkipLateDataLoading = theToSkip; }
+
+  //! Returns TRUE if data should be loaded into itself without its transfering to new structure.
+  //! It allows to keep information about deferred storage to load/unload this data later.
+  //! TRUE by default.
+  bool ToKeepLateData() { return myToKeepLateData; }
+
+  //! Sets flag to keep information about deferred storage to load/unload data later.
+  void SetToKeepLateData (bool theToKeep) { myToKeepLateData = theToKeep; }
+
+  //! Returns TRUE if additional debug information should be print; FALSE by default.
+  bool ToPrintDebugMessages() const { return myToPrintDebugMessages; }
+
+  //! Sets flag to print debug information.
+  void SetToPrintDebugMessages (const Standard_Boolean theToPrint) { myToPrintDebugMessages = theToPrint; }
+
 protected:
 
   //! Read the mesh from specified file.
@@ -65,12 +85,17 @@ protected:
   //! Create primitive array reader context.
   //! Can be overridden by sub-class to read triangulation into application-specific data structures instead of Poly_Triangulation.
   //! Default implementation creates RWGltf_TriangulationReader.
-  Standard_EXPORT virtual Handle(RWGltf_PrimitiveArrayReader) createMeshReaderContext();
+  Standard_EXPORT virtual Handle(RWMesh_TriangulationReader) createMeshReaderContext() const;
 
   //! Read late data from RWGltf_GltfLatePrimitiveArray stored as Poly_Triangulation within faces.
   Standard_EXPORT virtual Standard_Boolean readLateData (NCollection_Vector<TopoDS_Face>& theFaces,
                                                          const TCollection_AsciiString& theFile,
                                                          const Message_ProgressRange& theProgress);
+
+  //! Set reader for each late data.
+  Standard_EXPORT void updateLateDataReader (NCollection_Vector<TopoDS_Face>& theFaces,
+                                             const Handle(RWMesh_TriangulationReader)& theReader) const;
+
 protected:
 
   class CafReader_GltfReaderFunctor;
@@ -81,6 +106,9 @@ protected:
   Standard_Boolean myToSkipEmptyNodes;      //!< ignore nodes without Geometry; TRUE by default
   Standard_Boolean myUseMeshNameAsFallback; //!< flag to use Mesh name in case if Node name is empty, TRUE by default
   Standard_Boolean myIsDoublePrecision;     //!< flag to fill in triangulation using single or double precision
+  Standard_Boolean myToSkipLateDataLoading; //!< flag to skip triangulation loading
+  Standard_Boolean myToKeepLateData;        //!< flag to keep information about deferred storage to load/unload triangulation later
+  Standard_Boolean myToPrintDebugMessages;  //!< flag to print additional debug information
 
 };
 
index 2606087..895718d 100644 (file)
@@ -1503,6 +1503,10 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (const Handle(RWGltf_GltfLatePrim
       return false;
     }
   }
+  else
+  {
+    theMeshData->SetNbDeferredTriangles (theMeshData->NbDeferredNodes() / 3);
+  }
 
   return true;
 }
@@ -1594,6 +1598,8 @@ bool RWGltf_GltfJsonParser::gltfParseAccessor (const Handle(RWGltf_GltfLatePrimi
   // Read Min/Max values for POSITION type. It is used for bounding boxes
   if (theType == RWGltf_GltfArrayType_Position)
   {
+    theMeshData->SetNbDeferredNodes ((Standard_Integer )aStruct.Count);
+
     const RWGltf_JsonValue* aMin = findObjectMember (theAccessor, "min");
     const RWGltf_JsonValue* aMax = findObjectMember (theAccessor, "max");
     if (aMin != NULL && aMax != NULL)
@@ -1644,6 +1650,10 @@ bool RWGltf_GltfJsonParser::gltfParseAccessor (const Handle(RWGltf_GltfLatePrimi
       }
     }
   }
+  else if (theType == RWGltf_GltfArrayType_Indices)
+  {
+    theMeshData->SetNbDeferredTriangles ((Standard_Integer )(aStruct.Count / 3));
+  }
 
   const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
   if (aBufferView == NULL
index 57ea9dc..8ba7ab5 100644 (file)
@@ -20,6 +20,8 @@
 #include <Message_ProgressScope.hxx>
 #include <NCollection_DataMap.hxx>
 #include <NCollection_IndexedMap.hxx>
+#include <RWGltf_GltfAccessor.hxx>
+#include <RWGltf_GltfPrimArrayData.hxx>
 #include <RWGltf_GltfLatePrimitiveArray.hxx>
 #include <RWGltf_GltfBufferView.hxx>
 #include <RWGltf_GltfRootElement.hxx>
index a76fa77..8ffadd4 100644 (file)
 
 #include <RWGltf_GltfLatePrimitiveArray.hxx>
 
+#include <RWGltf_GltfPrimArrayData.hxx>
 #include <RWGltf_MaterialMetallicRoughness.hxx>
 #include <RWGltf_MaterialCommon.hxx>
 
-#include <Message.hxx>
-#include <Message_Messenger.hxx>
-#include <OSD_OpenFile.hxx>
-#include <Standard_ArrayStreamBuffer.hxx>
-
-#include <fstream>
-
-IMPLEMENT_STANDARD_RTTIEXT(RWGltf_GltfLatePrimitiveArray, Poly_Triangulation)
+IMPLEMENT_STANDARD_RTTIEXT(RWGltf_GltfLatePrimitiveArray, RWMesh_TriangulationSource)
 
 // =======================================================================
 // function : RWGltf_GltfLatePrimitiveArray
@@ -32,8 +26,7 @@ IMPLEMENT_STANDARD_RTTIEXT(RWGltf_GltfLatePrimitiveArray, Poly_Triangulation)
 // =======================================================================
 RWGltf_GltfLatePrimitiveArray::RWGltf_GltfLatePrimitiveArray (const TCollection_AsciiString& theId,
                                                               const TCollection_AsciiString& theName)
-: Poly_Triangulation(),
-  myId (theId),
+: myId (theId),
   myName (theName),
   myPrimMode (RWGltf_GltfPrimitiveMode_UNKNOWN)
 {
index ecc5032..a06586f 100644 (file)
 #ifndef _RWGltf_GltfLatePrimitiveArray_HeaderFile
 #define _RWGltf_GltfLatePrimitiveArray_HeaderFile
 
+#include <RWMesh_TriangulationSource.hxx>
+
 #include <NCollection_Sequence.hxx>
-#include <Poly_Triangulation.hxx>
-#include <RWGltf_GltfPrimArrayData.hxx>
+#include <RWGltf_GltfArrayType.hxx>
 #include <RWGltf_GltfPrimitiveMode.hxx>
 #include <Quantity_ColorRGBA.hxx>
 
+class RWGltf_GltfPrimArrayData;
 class RWGltf_MaterialMetallicRoughness;
 class RWGltf_MaterialCommon;
 
 //! Mesh data wrapper for delayed primitive array loading from glTF file.
-//! Class inherits Poly_Triangulation so that it can be put temporarily into TopoDS_Face within assembly structure,
-//! to be replaced with proper Poly_Triangulation loaded later on.
-class RWGltf_GltfLatePrimitiveArray : public Poly_Triangulation
+class RWGltf_GltfLatePrimitiveArray : public RWMesh_TriangulationSource
 {
-  DEFINE_STANDARD_RTTIEXT(RWGltf_GltfLatePrimitiveArray, Poly_Triangulation)
+  DEFINE_STANDARD_RTTIEXT(RWGltf_GltfLatePrimitiveArray, RWMesh_TriangulationSource)
 public:
 
   //! Constructor.
@@ -78,6 +78,13 @@ public:
   //! Add primitive array data element.
   Standard_EXPORT RWGltf_GltfPrimArrayData& AddPrimArrayData (RWGltf_GltfArrayType theType);
 
+  //! Returns TRUE if there is deferred storege and some triangulation data
+  //! that can be loaded using LoadDeferredData().
+  virtual Standard_Boolean HasDeferredData() const Standard_OVERRIDE
+  {
+    return !myData.IsEmpty() && RWMesh_TriangulationSource::HasDeferredData();
+  }
+
 protected:
 
   NCollection_Sequence<RWGltf_GltfPrimArrayData> myData;
diff --git a/src/RWGltf/RWGltf_PrimitiveArrayReader.cxx b/src/RWGltf/RWGltf_PrimitiveArrayReader.cxx
deleted file mode 100644 (file)
index bb3c06f..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-// Author: Kirill Gavrilov
-// Copyright (c) 2019 OPEN CASCADE SAS
-//
-// This file is part of Open CASCADE Technology software library.
-//
-// This library is free software; you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License version 2.1 as published
-// by the Free Software Foundation, with special exception defined in the file
-// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
-// distribution for complete text of the license and disclaimer of any warranty.
-//
-// Alternatively, this file may be used under the terms of Open CASCADE
-// commercial license or contractual agreement.
-
-#include <RWGltf_PrimitiveArrayReader.hxx>
-
-#include <RWGltf_GltfLatePrimitiveArray.hxx>
-
-#include <BRep_Builder.hxx>
-#include <Message.hxx>
-#include <Message_Messenger.hxx>
-#include <OSD_CachedFileSystem.hxx>
-#include <Standard_ArrayStreamBuffer.hxx>
-#include <TopoDS.hxx>
-#include <TopoDS_Iterator.hxx>
-
-IMPLEMENT_STANDARD_RTTIEXT(RWGltf_PrimitiveArrayReader, Standard_Transient)
-
-// =======================================================================
-// function : reportError
-// purpose  :
-// =======================================================================
-void RWGltf_PrimitiveArrayReader::reportError (const TCollection_AsciiString& theText)
-{
-  Message::SendFail (myErrorPrefix + theText);
-}
-
-// =======================================================================
-// function : load
-// purpose  :
-// =======================================================================
-bool RWGltf_PrimitiveArrayReader::load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh,
-                                        const Handle(OSD_FileSystem)& theFileSystem)
-{
-  reset();
-  if (theMesh.IsNull()
-   || theMesh->PrimitiveMode() == RWGltf_GltfPrimitiveMode_UNKNOWN)
-  {
-    return false;
-  }
-
-  for (NCollection_Sequence<RWGltf_GltfPrimArrayData>::Iterator aDataIter (theMesh->Data()); aDataIter.More(); aDataIter.Next())
-  {
-    const RWGltf_GltfPrimArrayData& aData = aDataIter.Value();
-    if (!aData.StreamData.IsNull())
-    {
-      Standard_ArrayStreamBuffer aStreamBuffer ((const char* )aData.StreamData->Data(), aData.StreamData->Size());
-      std::istream aStream (&aStreamBuffer);
-      aStream.seekg ((std::streamoff )aData.StreamOffset, std::ios_base::beg);
-      if (!readBuffer (aStream, theMesh->Id(), aData.Accessor, aData.Type, theMesh->PrimitiveMode()))
-      {
-        return false;
-      }
-      continue;
-    }
-    else if (aData.StreamUri.IsEmpty())
-    {
-      reportError (TCollection_AsciiString ("Buffer '") + theMesh->Id() + "' does not define uri.");
-      return false;
-    }
-
-    opencascade::std::shared_ptr<std::istream> aSharedStream = theFileSystem->OpenIStream (aData.StreamUri, std::ios::in | std::ios::binary, aData.StreamOffset);
-    if (aSharedStream.get() == NULL)
-    {
-      reportError (TCollection_AsciiString ("Buffer '") + theMesh->Id() + "refers to invalid file '" + aData.StreamUri + "'.");
-      return false;
-    }
-    if (!readBuffer (*aSharedStream.get(), theMesh->Id(), aData.Accessor, aData.Type, theMesh->PrimitiveMode()))
-    {
-      return false;
-    }
-  }
-  return true;
-}
diff --git a/src/RWGltf/RWGltf_PrimitiveArrayReader.hxx b/src/RWGltf/RWGltf_PrimitiveArrayReader.hxx
deleted file mode 100644 (file)
index 8ce47df..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-// Author: Kirill Gavrilov
-// Copyright (c) 2019 OPEN CASCADE SAS
-//
-// This file is part of Open CASCADE Technology software library.
-//
-// This library is free software; you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License version 2.1 as published
-// by the Free Software Foundation, with special exception defined in the file
-// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
-// distribution for complete text of the license and disclaimer of any warranty.
-//
-// Alternatively, this file may be used under the terms of Open CASCADE
-// commercial license or contractual agreement.
-
-#ifndef _RWGltf_PrimitiveArrayReader_HeaderFile
-#define _RWGltf_PrimitiveArrayReader_HeaderFile
-
-#include <Poly_Triangulation.hxx>
-#include <RWMesh_CoordinateSystemConverter.hxx>
-#include <RWGltf_GltfAccessor.hxx>
-#include <RWGltf_GltfArrayType.hxx>
-#include <RWGltf_GltfPrimitiveMode.hxx>
-#include <TCollection_AsciiString.hxx>
-
-class RWGltf_GltfLatePrimitiveArray;
-class OSD_FileSystem;
-
-//! Interface for reading primitive array from glTF buffer.
-class RWGltf_PrimitiveArrayReader : public Standard_Transient
-{
-  DEFINE_STANDARD_RTTIEXT(RWGltf_PrimitiveArrayReader, Standard_Transient)
-public:
-
-  //! Constructor.
-  RWGltf_PrimitiveArrayReader() {}
-
-  //! Return prefix for reporting issues.
-  const TCollection_AsciiString& ErrorPrefix() const { return myErrorPrefix; }
-
-  //! Set prefix for reporting issues.
-  void SetErrorPrefix (const TCollection_AsciiString& theErrPrefix) { myErrorPrefix = theErrPrefix; }
-
-  //! Return transformation from glTF to OCCT coordinate system.
-  const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCoordSysConverter; }
-
-  //! Set transformation from glTF to OCCT coordinate system.
-  void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCoordSysConverter = theConverter; }
-
-  //! Load primitive array.
-  Handle(Poly_Triangulation) Load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh,
-                                   const Handle(OSD_FileSystem)& theFileSystem)
-  {
-    if (load (theMesh, theFileSystem))
-    {
-      return result();
-    }
-    return Handle(Poly_Triangulation)();
-  }
-
-protected:
-
-  //! Reset cache before loading primitive array.
-  Standard_EXPORT virtual void reset() = 0;
-
-  //! Load primitive array.
-  Standard_EXPORT virtual bool load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh,
-                                     const Handle(OSD_FileSystem)& theFileSystem);
-
-  //! Return result primitive array.
-  Standard_EXPORT virtual Handle(Poly_Triangulation) result() = 0;
-
-  //! Read primitive array data.
-  //! @param theStream   input stream to read from
-  //! @param theName     entity name for logging errors
-  //! @param theAccessor buffer accessor
-  //! @param theType     array type
-  //! @param theMode     primitive mode
-  //! @return FALSE on error
-  Standard_EXPORT virtual bool readBuffer (std::istream& theStream,
-                                           const TCollection_AsciiString& theName,
-                                           const RWGltf_GltfAccessor& theAccessor,
-                                           RWGltf_GltfArrayType theType,
-                                           RWGltf_GltfPrimitiveMode theMode) = 0;
-
-  //! Report error.
-  Standard_EXPORT virtual void reportError (const TCollection_AsciiString& theText);
-
-protected:
-
-  TCollection_AsciiString          myErrorPrefix;
-  RWMesh_CoordinateSystemConverter myCoordSysConverter;
-
-};
-
-#endif // _RWGltf_PrimitiveArrayReader_HeaderFile
index 25c7534..169b76a 100644 (file)
 
 #include <RWGltf_TriangulationReader.hxx>
 
+#include <Message.hxx>
+#include <OSD_FileSystem.hxx>
 #include <RWGltf_GltfLatePrimitiveArray.hxx>
-#include <RWMesh_CoordinateSystemConverter.hxx>
+#include <RWGltf_GltfPrimArrayData.hxx>
+#include <Standard_ArrayStreamBuffer.hxx>
 #include <Standard_ReadBuffer.hxx>
 
-#include <BRep_Builder.hxx>
-#include <Graphic3d_Vec.hxx>
-#include <Message.hxx>
-#include <Message_Messenger.hxx>
-#include <TopoDS.hxx>
-#include <TopoDS_Iterator.hxx>
-
 namespace
 {
   static const Standard_Integer   THE_LOWER_TRI_INDEX  = 1;
@@ -32,91 +28,128 @@ namespace
   static const Standard_ShortReal THE_NORMAL_PREC2 = 0.001f;
 }
 
-IMPLEMENT_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWGltf_PrimitiveArrayReader)
+IMPLEMENT_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWMesh_TriangulationReader)
 
 // =======================================================================
 // function : RWGltf_TriangulationReader
 // purpose  :
 // =======================================================================
 RWGltf_TriangulationReader::RWGltf_TriangulationReader()
-: myIsDoublePrecision (false)
 {
   //
 }
 
 // =======================================================================
-// function : reset
+// function : reportError
 // purpose  :
 // =======================================================================
-void RWGltf_TriangulationReader::reset()
+void RWGltf_TriangulationReader::reportError (const TCollection_AsciiString& theText) const
 {
-  myTriangulation = new Poly_Triangulation();
-  myTriangulation->SetDoublePrecision (myIsDoublePrecision);
+  Message::SendFail (TCollection_AsciiString("File '") + myFileName + "' defines invalid glTF!\n" + theText);
 }
 
 // =======================================================================
-// function : result
+// function : load
 // purpose  :
 // =======================================================================
-Handle(Poly_Triangulation) RWGltf_TriangulationReader::result()
+bool RWGltf_TriangulationReader::load (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+                                       const Handle(Poly_Triangulation)& theDestMesh,
+                                       const Handle(OSD_FileSystem)& theFileSystem) const
 {
-  if (myTriangulation->NbNodes() < 1)
+  const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh);
+  if (aSourceGltfMesh.IsNull()
+   || aSourceGltfMesh->PrimitiveMode() == RWGltf_GltfPrimitiveMode_UNKNOWN)
   {
-    return Handle(Poly_Triangulation)();
+    return false;
   }
 
-  if (myTriangulation->NbTriangles() < 1)
+  for (NCollection_Sequence<RWGltf_GltfPrimArrayData>::Iterator aDataIter (aSourceGltfMesh->Data()); aDataIter.More(); aDataIter.Next())
   {
-    // reconstruct indexes
-    const Standard_Integer aNbTris = myTriangulation->NbNodes() / 3;
-    if (!setNbTriangles (aNbTris))
+    const RWGltf_GltfPrimArrayData& aData = aDataIter.Value();
+    if (!aData.StreamData.IsNull())
     {
-      return Handle(Poly_Triangulation)();
+      Standard_ArrayStreamBuffer aStreamBuffer ((const char* )aData.StreamData->Data(), aData.StreamData->Size());
+      std::istream aStream (&aStreamBuffer);
+      aStream.seekg ((std::streamoff )aData.StreamOffset, std::ios_base::beg);
+      if (!readBuffer (aSourceGltfMesh, theDestMesh, aStream, aData.Accessor, aData.Type))
+      {
+        return false;
+      }
+      continue;
+    }
+    else if (aData.StreamUri.IsEmpty())
+    {
+      reportError (TCollection_AsciiString ("Buffer '") + aSourceGltfMesh->Id() + "' does not define uri.");
+      return false;
     }
 
-    for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
+    const Handle(OSD_FileSystem)& aFileSystem = !theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem();
+    opencascade::std::shared_ptr<std::istream> aSharedStream = aFileSystem->OpenIStream (aData.StreamUri, std::ios::in | std::ios::binary, aData.StreamOffset);
+    if (aSharedStream.get() == NULL)
+    {
+      reportError (TCollection_AsciiString ("Buffer '") + aSourceGltfMesh->Id() + "refers to invalid file '" + aData.StreamUri + "'.");
+      return false;
+    }
+    if (!readBuffer (aSourceGltfMesh, theDestMesh, *aSharedStream.get(), aData.Accessor, aData.Type))
     {
-      setTriangle (THE_LOWER_TRI_INDEX + aTriIter,
-                   Poly_Triangle (THE_LOWER_NODE_INDEX + aTriIter * 3 + 0,
-                                  THE_LOWER_NODE_INDEX + aTriIter * 3 + 1,
-                                  THE_LOWER_NODE_INDEX + aTriIter * 3 + 2));
+      return false;
     }
   }
-
-  return myTriangulation;
+  return true;
 }
 
 // =======================================================================
-// function : load
+// function : finalizeLoading
 // purpose  :
 // =======================================================================
-bool RWGltf_TriangulationReader::load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh,
-                                       const Handle(OSD_FileSystem)& theFileSystem)
+bool RWGltf_TriangulationReader::finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+                                                  const Handle(Poly_Triangulation)& theDestMesh) const
 {
-  if (!RWGltf_PrimitiveArrayReader::load (theMesh, theFileSystem))
+  if (theDestMesh->NbNodes() < 1)
   {
     return false;
   }
-  if (!theMesh->CachedMinMax().IsVoid())
+  if (theDestMesh->NbTriangles() < 1)
   {
-    myTriangulation->SetCachedMinMax (theMesh->CachedMinMax());
+    const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh);
+    if (!aSourceGltfMesh.IsNull() && aSourceGltfMesh->PrimitiveMode() == RWGltf_GltfPrimitiveMode_Triangles)
+    {
+      // reconstruct indexes
+      const Standard_Integer aNbTris = theDestMesh->NbNodes() / 3;
+      if (!setNbTriangles (theDestMesh, aNbTris))
+      {
+        return false;
+      }
+      for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
+      {
+        if (!setTriangle (theDestMesh, THE_LOWER_TRI_INDEX + aTriIter,
+                          Poly_Triangle (THE_LOWER_NODE_INDEX + aTriIter * 3 + 0,
+                                         THE_LOWER_NODE_INDEX + aTriIter * 3 + 1,
+                                         THE_LOWER_NODE_INDEX + aTriIter * 3 + 2)))
+        {
+          return false;
+        }
+      }
+    }
   }
-  return true;
+  return RWMesh_TriangulationReader::finalizeLoading (theSourceMesh, theDestMesh);
 }
 
 // =======================================================================
 // function : readBuffer
 // purpose  :
 // =======================================================================
-bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
-                                             const TCollection_AsciiString& theName,
+bool RWGltf_TriangulationReader::readBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceMesh,
+                                             const Handle(Poly_Triangulation)& theDestMesh,
+                                             std::istream& theStream,
                                              const RWGltf_GltfAccessor& theAccessor,
-                                             RWGltf_GltfArrayType theType,
-                                             RWGltf_GltfPrimitiveMode theMode)
+                                             RWGltf_GltfArrayType theType) const
+
 {
-  if (theMode != RWGltf_GltfPrimitiveMode_Triangles)
+  const TCollection_AsciiString& aName = theSourceMesh->Id();
+  if (theSourceMesh->PrimitiveMode() != RWGltf_GltfPrimitiveMode_Triangles)
   {
-    Message::SendWarning (TCollection_AsciiString("Buffer '") + theName + "' skipped unsupported primitive array");
+    Message::SendWarning (TCollection_AsciiString("Buffer '") + aName + "' skipped unsupported primitive array");
     return true;
   }
 
@@ -134,12 +167,12 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
       {
         if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
         {
-          reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
+          reportError (TCollection_AsciiString ("Buffer '") + aName + "' defines too big array.");
           return false;
         }
 
         const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3);
-        if (!setNbTriangles (aNbTris))
+        if (!setNbTriangles (theDestMesh, aNbTris))
         {
           return false;
         }
@@ -147,6 +180,7 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
                              ? theAccessor.ByteStride
                              : sizeof(uint16_t);
         Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
+        Standard_Integer aLastTriIndex = 0;
         for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
         {
           if (const uint16_t* anIndex0 = aBuffer.ReadChunk<uint16_t> (theStream))
@@ -163,13 +197,37 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
           }
           else
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
             return false;
           }
 
-          if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
+          const Standard_Integer wasSet = setTriangle (theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3);
+          if (!wasSet)
+          {
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' refers to invalid indices.");
+          }
+          if (wasSet > 0)
+          {
+            aLastTriIndex++;
+          }
+        }
+        const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex;
+        if (aNbDegenerate > 0)
+        {
+          if (aNbDegenerate == aNbTris)
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
+            Message::SendWarning (TCollection_AsciiString("Buffer '") + aName + "' has been skipped (all elements are degenerative in)");
+            return false;
+          }
+          theSourceMesh->ChangeDegeneratedTriNb() += aNbDegenerate;
+          if ((myLoadingStatistic == NULL) && myToPrintDebugMessages)
+          {
+            Message::SendTrace (TCollection_AsciiString() + aNbDegenerate
+                                + " degenerate triangles have been skipped while reading glTF triangulation '" + aName + "'");
+          }
+          if (!setNbTriangles (theDestMesh, aLastTriIndex, true))
+          {
+            return false;
           }
         }
       }
@@ -177,12 +235,12 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
       {
         if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
         {
-          reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
+          reportError (TCollection_AsciiString ("Buffer '") + aName + "' defines too big array.");
           return false;
         }
 
         const int aNbTris = (Standard_Integer )(theAccessor.Count / 3);
-        if (!setNbTriangles (aNbTris))
+        if (!setNbTriangles (theDestMesh, aNbTris))
         {
           return false;
         }
@@ -190,6 +248,7 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
                              ? theAccessor.ByteStride
                              : sizeof(uint32_t);
         Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
+        Standard_Integer aLastTriIndex = 0;
         for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
         {
           if (const uint32_t* anIndex0 = aBuffer.ReadChunk<uint32_t> (theStream))
@@ -206,13 +265,37 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
           }
           else
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
             return false;
           }
 
-          if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
+          const Standard_Integer wasSet = setTriangle (theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3);
+          if (!wasSet)
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' refers to invalid indices.");
+          }
+          if (wasSet > 0)
+          {
+            aLastTriIndex++;
+          }
+        }
+        const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex;
+        if (aNbDegenerate > 0)
+        {
+          if (aNbDegenerate == aNbTris)
+          {
+            Message::SendWarning (TCollection_AsciiString("Buffer '") + aName + "' has been skipped (all elements are degenerative in)");
+            return false;
+          }
+          theSourceMesh->ChangeDegeneratedTriNb() += aNbDegenerate;
+          if (myLoadingStatistic == NULL && myToPrintDebugMessages)
+          {
+            Message::SendTrace (TCollection_AsciiString() + aNbDegenerate
+                                + " degenerate triangles have been skipped while reading glTF triangulation '" + aName + "'");
+          }
+          if (!setNbTriangles (theDestMesh, aLastTriIndex, true))
+          {
+            return false;
           }
         }
       }
@@ -220,12 +303,12 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
       {
         if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
         {
-          reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
+          reportError (TCollection_AsciiString ("Buffer '") + aName + "' defines too big array.");
           return false;
         }
 
         const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3);
-        if (!setNbTriangles (aNbTris))
+        if (!setNbTriangles (theDestMesh, aNbTris))
         {
           return false;
         }
@@ -233,6 +316,7 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
                              ? theAccessor.ByteStride
                              : sizeof(uint8_t);
         Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
+        Standard_Integer aLastTriIndex = 0;
         for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
         {
           if (const uint8_t* anIndex0 = aBuffer.ReadChunk<uint8_t> (theStream))
@@ -249,13 +333,37 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
           }
           else
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
             return false;
           }
 
-          if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
+          const Standard_Integer wasSet = setTriangle (theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3);
+          if (!wasSet)
+          {
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' refers to invalid indices.");
+          }
+          if (wasSet > 0)
+          {
+            aLastTriIndex++;
+          }
+        }
+        const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex;
+        if (aNbDegenerate > 0)
+        {
+          if (aNbDegenerate == aNbTris)
+          {
+            Message::SendWarning (TCollection_AsciiString("Buffer '") + aName + "' has been skipped (all elements are degenerative in)");
+            return false;
+          }
+          theSourceMesh->ChangeDegeneratedTriNb() += aNbDegenerate;
+          if (myLoadingStatistic == NULL && myToPrintDebugMessages)
+          {
+            Message::SendTrace (TCollection_AsciiString() + aNbDegenerate
+                                + " degenerate triangles have been skipped while reading glTF triangulation '" + aName + "'");
+          }
+          if (!setNbTriangles (theDestMesh, aLastTriIndex, true))
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
+            return false;
           }
         }
       }
@@ -275,7 +383,7 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
       }
       else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
       {
-        reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
+        reportError (TCollection_AsciiString ("Buffer '") + aName + "' defines too big array.");
         return false;
       }
 
@@ -283,7 +391,7 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
                            ? theAccessor.ByteStride
                            : sizeof(Graphic3d_Vec3);
       const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
-      if (!setNbPositionNodes (aNbNodes))
+      if (!setNbPositionNodes (theDestMesh, aNbNodes))
       {
         return false;
       }
@@ -296,13 +404,13 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
           const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
           if (aVec3 == NULL)
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
             return false;
           }
 
           gp_Pnt anXYZ (aVec3->x(), aVec3->y(), aVec3->z());
           myCoordSysConverter.TransformPosition (anXYZ.ChangeCoord());
-          setNodePosition (THE_LOWER_NODE_INDEX + aVertIter, anXYZ);
+          setNodePosition (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, anXYZ);
         }
       }
       else
@@ -312,10 +420,10 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
           const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
           if (aVec3 == NULL)
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
             return false;
           }
-          setNodePosition (THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt (aVec3->x(), aVec3->y(), aVec3->z()));
+          setNodePosition (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt (aVec3->x(), aVec3->y(), aVec3->z()));
         }
       }
       break;
@@ -329,7 +437,7 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
       }
       else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
       {
-        reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
+        reportError (TCollection_AsciiString ("Buffer '") + aName + "' defines too big array.");
         return false;
       }
 
@@ -337,7 +445,7 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
                            ? theAccessor.ByteStride
                            : sizeof(Graphic3d_Vec3);
       const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
-      if (!setNbNormalNodes (aNbNodes))
+      if (!setNbNormalNodes (theDestMesh, aNbNodes))
       {
         return false;
       }
@@ -349,17 +457,17 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
           Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
           if (aVec3 == NULL)
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
             return false;
           }
           if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
           {
             myCoordSysConverter.TransformNormal (*aVec3);
-            setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (aVec3->x(), aVec3->y(), aVec3->z()));
+            setNodeNormal (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, *aVec3);
           }
           else
           {
-            setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (0.0, 0.0, 1.0));
+            setNodeNormal (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Vec3f(0.0, 0.0, 1.0));
           }
         }
       }
@@ -370,16 +478,16 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
           const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
           if (aVec3 == NULL)
           {
-            reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
+            reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
             return false;
           }
           if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
           {
-            setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (aVec3->x(), aVec3->y(), aVec3->z()));
+            setNodeNormal (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, *aVec3);
           }
           else
           {
-            setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (0.0, 0.0, 1.0));
+            setNodeNormal (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Vec3f(0.0, 0.0, 1.0));
           }
         }
       }
@@ -394,7 +502,7 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
       }
       else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
       {
-        reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
+        reportError (TCollection_AsciiString ("Buffer '") + aName + "' defines too big array.");
         return false;
       }
 
@@ -402,7 +510,7 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
                            ? theAccessor.ByteStride
                            : sizeof(Graphic3d_Vec2);
       const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
-      if (!setNbUVNodes (aNbNodes))
+      if (!setNbUVNodes (theDestMesh, aNbNodes))
       {
         return false;
       }
@@ -413,13 +521,13 @@ bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
         Graphic3d_Vec2* aVec2 = aBuffer.ReadChunk<Graphic3d_Vec2> (theStream);
         if (aVec2 == NULL)
         {
-          reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
+          reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
           return false;
         }
 
         // Y should be flipped (relative to image layout used by OCCT)
         aVec2->y() = 1.0f - aVec2->y();
-        setNodeUV (THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt2d (aVec2->x(), aVec2->y()));
+        setNodeUV (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt2d (aVec2->x(), aVec2->y()));
       }
       break;
     }
index 3237710..ee10f68 100644 (file)
 #ifndef _RWGltf_TriangulationReader_HeaderFile
 #define _RWGltf_TriangulationReader_HeaderFile
 
-#include <RWGltf_PrimitiveArrayReader.hxx>
+#include <RWMesh_TriangulationReader.hxx>
+#include <RWGltf_GltfAccessor.hxx>
+#include <RWGltf_GltfArrayType.hxx>
+#include <RWGltf_GltfPrimitiveMode.hxx>
 
-//! RWGltf_PrimitiveArrayReader implementation creating Poly_Triangulation.
-class RWGltf_TriangulationReader : public RWGltf_PrimitiveArrayReader
+class RWGltf_GltfLatePrimitiveArray;
+
+//! RWMesh_TriangulationReader implementation creating Poly_Triangulation.
+class RWGltf_TriangulationReader : public RWMesh_TriangulationReader
 {
-  DEFINE_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWGltf_PrimitiveArrayReader)
+  DEFINE_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWMesh_TriangulationReader)
 public:
 
   //! Empty constructor.
   Standard_EXPORT RWGltf_TriangulationReader();
 
-  //! Return flag to fill in triangulation using double or single precision; FALSE by default.
-  bool IsDoublePrecision() const { return myIsDoublePrecision; }
-
-  //! Set flag to fill in triangulation using double or single precision.
-  void SetDoublePrecision (bool theIsDouble) { myIsDoublePrecision = theIsDouble; }
-
 protected:
 
-  //! Load primitive array.
-  Standard_EXPORT virtual bool load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh,
-                                     const Handle(OSD_FileSystem)& theFileSystem) Standard_OVERRIDE;
+  //! Reports error.
+  Standard_EXPORT virtual void reportError (const TCollection_AsciiString& theText) const;
 
-  //! Create Poly_Triangulation from collected data
-  Standard_EXPORT virtual Handle(Poly_Triangulation) result() Standard_OVERRIDE;
+  //! Loads primitive array.
+  Standard_EXPORT virtual bool load (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+                                     const Handle(Poly_Triangulation)& theDestMesh,
+                                     const Handle(OSD_FileSystem)& theFileSystem) const Standard_OVERRIDE;
 
-  //! Reset cache before loading primitive array.
-  Standard_EXPORT virtual void reset() Standard_OVERRIDE;
+  //! Performs additional actions to finalize data loading.
+  Standard_EXPORT virtual bool finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+                                                const Handle(Poly_Triangulation)& theDestMesh) const Standard_OVERRIDE;
 
-  //! Fill triangulation data and ignore non-triangulation primitives.
-  //! @param theStream   input stream to read from
-  //! @param theName     entity name for logging errors
-  //! @param theAccessor buffer accessor
-  //! @param theType     array type
-  //! @param theMode     primitive mode
+  //! Fills triangulation data and ignore non-triangulation primitives.
+  //! @param theSourceMesh source triangulation
+  //! @param theDestMesh   triangulation to be modified
+  //! @param theStream     input stream to read from
+  //! @param theAccessor   buffer accessor
+  //! @param theType       array type
   //! @return FALSE on error
-  Standard_EXPORT virtual bool readBuffer (std::istream& theStream,
-                                           const TCollection_AsciiString& theName,
+  Standard_EXPORT virtual bool readBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceMesh,
+                                           const Handle(Poly_Triangulation)& theDestMesh,
+                                           std::istream& theStream,
                                            const RWGltf_GltfAccessor& theAccessor,
-                                           RWGltf_GltfArrayType theType,
-                                           RWGltf_GltfPrimitiveMode theMode) Standard_OVERRIDE;
-
-protected: //! @name interface for filling triangulation data
-
-  //! Resize array of position nodes to specified size.
-  virtual bool setNbPositionNodes (Standard_Integer theNbNodes)
-  {
-    if (theNbNodes <= 0)
-    {
-      return false;
-    }
-    myTriangulation->ResizeNodes (theNbNodes, false);
-    return true;
-  }
-
-  //! Set node position.
-  //! @param theIndex node index starting from 1
-  //! @param thePnt   node position
-  virtual void setNodePosition (Standard_Integer theIndex,
-                                const gp_Pnt& thePnt)
-  {
-    myTriangulation->SetNode (theIndex, thePnt);
-  }
-
-  //! Resize array of UV nodes to specified size.
-  virtual bool setNbUVNodes (Standard_Integer theNbNodes)
-  {
-    if (theNbNodes <= 0
-     || myTriangulation->NbNodes() != theNbNodes)
-    {
-      return false;
-    }
-    myTriangulation->AddUVNodes();
-    return true;
-  }
-
-  //! Set node UV texture coordinates.
-  //! @param theIndex node index starting from 1
-  //! @param theUV    node UV coordinates
-  virtual void setNodeUV (Standard_Integer theIndex,
-                          const gp_Pnt2d& theUV)
-  {
-    myTriangulation->SetUVNode (theIndex, theUV);
-  }
-
-  //! Resize array of nodes normals to specified size.
-  virtual bool setNbNormalNodes (Standard_Integer theNbNodes)
-  {
-    if (theNbNodes <= 0
-     || myTriangulation->NbNodes() != theNbNodes)
-    {
-      return false;
-    }
-    myTriangulation->AddNormals();
-    return true;
-  }
-
-  //! Set node normal.
-  //! @param theIndex  node index starting from 1
-  //! @param theNormal node normal
-  virtual void setNodeNormal (Standard_Integer theIndex,
-                              const gp_Dir& theNormal)
-  {
-    myTriangulation->SetNormal (theIndex, theNormal);
-  }
-
-  //! Resize array of triangles to specified size.
-  virtual bool setNbTriangles (Standard_Integer theNbTris)
-  {
-    if (theNbTris >= 1)
-    {
-      myTriangulation->ResizeTriangles (theNbTris, false);
-      return true;
-    }
-    return false;
-  }
-
-  //! Add triangle element.
-  //! @param theIndex    triangle index starting from 1
-  //! @param theTriangle triangle nodes starting from 1
-  //! @return FALSE if node indexes are out of range
-  virtual bool setTriangle (Standard_Integer theIndex,
-                            const Poly_Triangle& theTriangle)
-  {
-    if (theTriangle.Value (1) < 1 || theTriangle.Value (1) > myTriangulation->NbNodes()
-     || theTriangle.Value (2) < 1 || theTriangle.Value (2) > myTriangulation->NbNodes()
-     || theTriangle.Value (3) < 1 || theTriangle.Value (3) > myTriangulation->NbNodes())
-    {
-      return false;
-    }
-    myTriangulation->SetTriangle (theIndex, theTriangle);
-    return true;
-  }
+                                           RWGltf_GltfArrayType theType) const;
 
 protected:
 
   Handle(Poly_Triangulation) myTriangulation;
-  Standard_Boolean myIsDoublePrecision;
 
 };
 
index 1533fa8..6cf9889 100644 (file)
@@ -8,3 +8,7 @@ RWMesh_FaceIterator.hxx
 RWMesh_MaterialMap.cxx
 RWMesh_MaterialMap.hxx
 RWMesh_NodeAttributes.hxx
+RWMesh_TriangulationReader.cxx
+RWMesh_TriangulationReader.hxx
+RWMesh_TriangulationSource.cxx
+RWMesh_TriangulationSource.hxx
diff --git a/src/RWMesh/RWMesh_TriangulationReader.cxx b/src/RWMesh/RWMesh_TriangulationReader.cxx
new file mode 100644 (file)
index 0000000..bc001ff
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright (c) 2021 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <RWMesh_TriangulationReader.hxx>
+
+#include <Message.hxx>
+#include <RWMesh_TriangulationSource.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(RWMesh_TriangulationReader, Standard_Transient)
+
+namespace
+{
+  //! Forms string with loading statistic.
+  static TCollection_AsciiString loadingStatistic (const TCollection_AsciiString& thePrefix,
+                                                   const Standard_Integer theExpectedNodesNb,
+                                                   const Standard_Integer theLoadedNodesNb,
+                                                   const Standard_Integer theExpectedTrianglesNb,
+                                                   const Standard_Integer theDegeneratedTrianglesNb,
+                                                   const Standard_Integer theLoadedTrianglesNb)
+  {
+    TCollection_AsciiString aNodesInfo;
+    if (theExpectedNodesNb != theLoadedNodesNb)
+    {
+      aNodesInfo = TCollection_AsciiString("Nodes: ") + theExpectedNodesNb + " expected / ";
+      aNodesInfo += TCollection_AsciiString(theLoadedNodesNb) + " loaded.";
+    }
+    TCollection_AsciiString aTrianglesInfo;
+    if (theExpectedTrianglesNb != theLoadedTrianglesNb)
+    {
+      if (!aNodesInfo.IsEmpty())
+      {
+        aNodesInfo += " ";
+      }
+      aTrianglesInfo = TCollection_AsciiString("Triangles: ") + theExpectedTrianglesNb + " expected / ";
+      if (theDegeneratedTrianglesNb != 0)
+      {
+        aTrianglesInfo += TCollection_AsciiString(theDegeneratedTrianglesNb) + " skipped degenerated / ";
+      }
+      aTrianglesInfo += TCollection_AsciiString(theLoadedTrianglesNb) + " loaded.";
+    }
+    if (aNodesInfo.IsEmpty() && aTrianglesInfo.IsEmpty())
+    {
+      return TCollection_AsciiString();
+    }
+    return thePrefix + ("Disconformity of the expected number of nodes/triangles for deferred mesh to the loaded amount. ")
+           + aNodesInfo + aTrianglesInfo;
+  }
+}
+
+// =======================================================================
+// function : PrintStatistic
+// purpose  :
+// =======================================================================
+void RWMesh_TriangulationReader::LoadingStatistic::PrintStatistic (const TCollection_AsciiString& thePrefix) const
+{
+  TCollection_AsciiString aStatisticInfo = loadingStatistic (thePrefix, ExpectedNodesNb, LoadedNodesNb,
+                                                             ExpectedTrianglesNb, DegeneratedTrianglesNb, LoadedTrianglesNb);
+  if (!aStatisticInfo.IsEmpty())
+  {
+    Message::SendWarning (aStatisticInfo);
+  }
+}
+
+// =======================================================================
+// function : Constructor
+// purpose  :
+// =======================================================================
+RWMesh_TriangulationReader::RWMesh_TriangulationReader()
+: myLoadingStatistic(NULL),
+  myIsDoublePrecision(false),
+  myToSkipDegenerateTris(false),
+  myToPrintDebugMessages(false)
+{
+}
+
+// =======================================================================
+// function : Destructor
+// purpose  :
+// =======================================================================
+RWMesh_TriangulationReader::~RWMesh_TriangulationReader()
+{
+  delete myLoadingStatistic;
+}
+
+// =======================================================================
+// function : Load
+// purpose  :
+// =======================================================================
+bool RWMesh_TriangulationReader::Load (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+                                       const Handle(Poly_Triangulation)& theDestMesh,
+                                       const Handle(OSD_FileSystem)& theFileSystem) const
+{
+  Standard_ASSERT_RETURN (!theDestMesh.IsNull(), "The destination mesh should be initialized before loading data to it", false);
+  theDestMesh->Clear();
+  theDestMesh->SetDoublePrecision (myIsDoublePrecision);
+
+  if (!load (theSourceMesh, theDestMesh, theFileSystem))
+  {
+    theDestMesh->Clear();
+    return false;
+  }
+  if (!finalizeLoading (theSourceMesh, theDestMesh))
+  {
+    theDestMesh->Clear();
+    return false;
+  }
+  return true;
+}
+
+// =======================================================================
+// function : finalizeLoading
+// purpose  :
+// =======================================================================
+bool RWMesh_TriangulationReader::finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+                                                  const Handle(Poly_Triangulation)& theDestMesh) const
+{
+  if (!theSourceMesh->CachedMinMax().IsVoid())
+  {
+    theDestMesh->SetCachedMinMax (theSourceMesh->CachedMinMax());
+  }
+  if (myLoadingStatistic)
+  {
+    Standard_Mutex::Sentry aLock(myMutex);
+    myLoadingStatistic->ExpectedNodesNb += theSourceMesh->NbDeferredNodes();
+    myLoadingStatistic->ExpectedTrianglesNb += theSourceMesh->NbDeferredTriangles();
+    myLoadingStatistic->DegeneratedTrianglesNb += theSourceMesh->DegeneratedTriNb();
+    myLoadingStatistic->LoadedNodesNb += theDestMesh->NbNodes();
+    myLoadingStatistic->LoadedTrianglesNb += theDestMesh->NbTriangles();
+  }
+  else if (myToPrintDebugMessages)
+  {
+    TCollection_AsciiString aStatisticInfo = loadingStatistic (TCollection_AsciiString("[Mesh reader. File '") + myFileName + "']. ",
+                                                               theSourceMesh->NbDeferredNodes(), theDestMesh->NbNodes(),
+                                                               theSourceMesh->NbDeferredTriangles(), theSourceMesh->DegeneratedTriNb(),
+                                                               theDestMesh->NbTriangles());
+    Message::SendTrace (aStatisticInfo);
+  }
+  return true;
+}
diff --git a/src/RWMesh/RWMesh_TriangulationReader.hxx b/src/RWMesh/RWMesh_TriangulationReader.hxx
new file mode 100644 (file)
index 0000000..e980d04
--- /dev/null
@@ -0,0 +1,283 @@
+// Copyright (c) 2021 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _RWMesh_TriangulationReader_HeaderFile
+#define _RWMesh_TriangulationReader_HeaderFile
+
+#include <Poly_Triangulation.hxx>
+#include <RWMesh_CoordinateSystemConverter.hxx>
+#include <Standard_Mutex.hxx>
+
+class OSD_FileSystem;
+class RWMesh_TriangulationSource;
+
+//! Interface for reading primitive array from the buffer.
+class RWMesh_TriangulationReader : public Standard_Transient
+{
+  DEFINE_STANDARD_RTTIEXT(RWMesh_TriangulationReader, Standard_Transient)
+public:
+
+  struct LoadingStatistic
+  {
+    LoadingStatistic()
+    : ExpectedNodesNb(0),
+      LoadedNodesNb(0),
+      ExpectedTrianglesNb(0),
+      DegeneratedTrianglesNb(0),
+      LoadedTrianglesNb(0) {}
+
+    void Reset()
+    {
+      ExpectedNodesNb = 0;
+      LoadedNodesNb = 0;
+      ExpectedTrianglesNb = 0;
+      DegeneratedTrianglesNb = 0;
+      LoadedTrianglesNb = 0;
+    }
+
+    Standard_EXPORT void PrintStatistic (const TCollection_AsciiString& thePrefix = "") const;
+
+    Standard_Integer ExpectedNodesNb;
+    Standard_Integer LoadedNodesNb;
+    Standard_Integer ExpectedTrianglesNb;
+    Standard_Integer DegeneratedTrianglesNb;
+    Standard_Integer LoadedTrianglesNb;
+  };
+
+  //! Constructor.
+  Standard_EXPORT RWMesh_TriangulationReader();
+
+  //! Destructor.
+  Standard_EXPORT virtual ~RWMesh_TriangulationReader();
+
+  //! Returns file name for reporting issues.
+  const TCollection_AsciiString& FileName() const { return myFileName; }
+
+  //! Sets file name for reporting issues.
+  void SetFileName(const TCollection_AsciiString& theFileName) { myFileName = theFileName; }
+
+  //! Returns coordinate system converter using for correct data loading.
+  const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCoordSysConverter; }
+
+  //! Sets coordinate system converter.
+  void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCoordSysConverter = theConverter; }
+
+  //! Returns flag to fill in triangulation using double or single precision; FALSE by default.
+  bool IsDoublePrecision() const { return myIsDoublePrecision; }
+
+  //! Sets flag to fill in triangulation using double or single precision.
+  void SetDoublePrecision (bool theIsDouble) { myIsDoublePrecision = theIsDouble; }
+
+  //! Returns TRUE if degenerated triangles should be skipped during mesh loading (only indexes will be checked).
+  Standard_Boolean ToSkipDegenerates() const { return myToSkipDegenerateTris; }
+
+  //! Sets flag to skip degenerated triangles during mesh loading (only indexes will be checked).
+  void SetToSkipDegenerates (const Standard_Boolean theToSkip) { myToSkipDegenerateTris = theToSkip; }
+
+  //! Returns TRUE if additional debug information should be print.
+  Standard_Boolean ToPrintDebugMessages() const { return myToPrintDebugMessages; }
+
+  //! Sets flag to print debug information.
+  void SetToPrintDebugMessages (const Standard_Boolean theToPrint) { myToPrintDebugMessages = theToPrint; }
+
+  //! Starts and reset internal object that accumulates nodes/triangles statistic during data reading.
+  void StartStatistic()
+  {
+    if (myLoadingStatistic)
+    {
+      myLoadingStatistic->Reset();
+    }
+    else
+    {
+      myLoadingStatistic = new LoadingStatistic();
+    }
+  }
+
+  //! Stops and nullify internal object that accumulates nodes/triangles statistic during data reading.
+  void StopStatistic()
+  {
+    if (myLoadingStatistic)
+    {
+      delete myLoadingStatistic;
+      myLoadingStatistic = NULL;
+    }
+  }
+
+  //! Prints loading statistic.
+  //! This method should be used between StartStatistic() and StopStatistic() calls
+  //! for correct results.
+  void PrintStatistic() const
+  {
+    if (myLoadingStatistic)
+    {
+      myLoadingStatistic->PrintStatistic (TCollection_AsciiString("[Mesh reader. File '") + myFileName + "']. ");
+    }
+  }
+
+  //! Loads primitive array.
+  Standard_EXPORT bool Load (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+                             const Handle(Poly_Triangulation)& theDestMesh,
+                             const Handle(OSD_FileSystem)& theFileSystem) const;
+
+protected:
+
+  //! Loads primitive array.
+  Standard_EXPORT virtual bool load (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+                                     const Handle(Poly_Triangulation)& theDestMesh,
+                                     const Handle(OSD_FileSystem)& theFileSystem) const = 0;
+
+  //! Performs additional actions to finalize data loading.
+  Standard_EXPORT virtual bool finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
+                                                const Handle(Poly_Triangulation)& theDestMesh) const;
+
+protected: //! @name interface for filling triangulation data
+
+  //! Resizes array of position nodes to specified size.
+  //! @param theMesh [in] triangulation to be modified
+  //! @param theNbNodes [in] nodes number
+  //! @param theToCopyData [in] copy old nodes into new array
+  //! @return TRUE in case of success operation
+  virtual bool setNbPositionNodes (const Handle(Poly_Triangulation)& theMesh,
+                                   Standard_Integer theNbNodes,
+                                   Standard_Boolean theToCopyData = false) const
+  {
+    if (theNbNodes <= 0)
+    {
+      return false;
+    }
+    theMesh->ResizeNodes (theNbNodes, theToCopyData);
+    return true;
+  }
+
+  //! Sets node position.
+  //! @param theMesh [in] triangulation to be modified
+  //! @param theIndex [in] node index starting from 1
+  //! @param thePnt [in] node position
+  virtual void setNodePosition (const Handle(Poly_Triangulation)& theMesh,
+                                Standard_Integer theIndex,
+                                const gp_Pnt& thePnt) const
+  {
+    theMesh->SetNode (theIndex, thePnt);
+  }
+
+  //! Resizes array of UV nodes to specified size.
+  //! @param theMesh [in] triangulation to be modified
+  //! @param theNbNodes [in] nodes number
+  //! @return TRUE in case of success operation
+  virtual bool setNbUVNodes (const Handle(Poly_Triangulation)& theMesh,
+                             Standard_Integer theNbNodes) const
+  {
+    if (theNbNodes <= 0
+     || theMesh->NbNodes() != theNbNodes)
+    {
+      return false;
+    }
+    theMesh->AddUVNodes();
+    return true;
+  }
+
+  //! Sets node UV texture coordinates.
+  //! @param theMesh [in] triangulation to be modified
+  //! @param theIndex [in] node index starting from 1
+  //! @param theUV [in] node UV coordinates
+  virtual void setNodeUV (const Handle(Poly_Triangulation)& theMesh,
+                          Standard_Integer theIndex,
+                          const gp_Pnt2d& theUV) const
+  {
+    theMesh->SetUVNode (theIndex, theUV);
+  }
+
+  //! Resizes array of nodes normals to specified size.
+  //! @param theMesh [in] triangulation to be modified
+  //! @param theNbNodes [in] nodes number
+  //! @return TRUE in case of success operation
+  virtual bool setNbNormalNodes (const Handle(Poly_Triangulation)& theMesh,
+                                 Standard_Integer theNbNodes) const
+  {
+    if (theNbNodes <= 0
+     || theMesh->NbNodes() != theNbNodes)
+    {
+      return false;
+    }
+    theMesh->AddNormals();
+    return true;
+  }
+
+  //! Sets node normal.
+  //! @param theMesh [in] triangulation to be modified
+  //! @param theIndex  node index starting from 1
+  //! @param theNormal node normal vector
+  virtual void setNodeNormal (const Handle(Poly_Triangulation)& theMesh,
+                              Standard_Integer theIndex,
+                              const gp_Vec3f& theNormal) const
+  {
+    theMesh->SetNormal (theIndex, theNormal);
+  }
+
+  //! Resizes array of triangles to specified size.
+  //! @param theMesh [in] triangulation to be modified
+  //! @param theNbTris [in] elements number
+  //! @param theToCopyData [in] copy old triangles into new array
+  //! @return TRUE in case of success operation
+  virtual bool setNbTriangles (const Handle(Poly_Triangulation)& theMesh,
+                               Standard_Integer theNbTris,
+                               Standard_Boolean theToCopyData = false) const
+  {
+    if (theNbTris >= 1)
+    {
+      theMesh->ResizeTriangles (theNbTris, theToCopyData);
+      return true;
+    }
+    return false;
+  }
+
+  //! Adds triangle element.
+  //! @param theMesh [in] triangulation to be modified
+  //! @param theIndex    triangle index starting from 1
+  //! @param theTriangle triangle nodes starting from 1
+  //! @return 0 if node indexes are out of range,
+  //!        -1 if triangle is degenerated and should be skipped,
+  //!         1 in case of success operation.
+  virtual Standard_Integer setTriangle (const Handle(Poly_Triangulation)& theMesh,
+                                        Standard_Integer theIndex,
+                                        const Poly_Triangle& theTriangle) const
+  {
+    if (theTriangle.Value (1) < 1 || theTriangle.Value (1) > theMesh->NbNodes()
+     || theTriangle.Value (2) < 1 || theTriangle.Value (2) > theMesh->NbNodes()
+     || theTriangle.Value (3) < 1 || theTriangle.Value (3) > theMesh->NbNodes())
+    {
+      return 0;
+    }
+    if (myToSkipDegenerateTris
+        && (theTriangle.Value (1) == theTriangle.Value (2)
+         || theTriangle.Value (1) == theTriangle.Value (3)
+         || theTriangle.Value (2) == theTriangle.Value (3)))
+    {
+      return -1;
+    }
+    theMesh->SetTriangle (theIndex, theTriangle);
+    return 1;
+  }
+
+protected:
+
+  RWMesh_CoordinateSystemConverter myCoordSysConverter;    //!< coordinate system converter
+  TCollection_AsciiString          myFileName;             //!< file name to use during message printing
+  mutable Standard_Mutex           myMutex;                //!< internal mutex to collect nodes/triangles statistic
+  mutable LoadingStatistic*        myLoadingStatistic;     //!< statistic of loaded triangulation
+  Standard_Boolean                 myIsDoublePrecision;    //!< flag to fill in triangulation using single or double precision
+  Standard_Boolean                 myToSkipDegenerateTris; //!< flag to skip degenerate triangles during loading, FALSE by default
+  Standard_Boolean                 myToPrintDebugMessages; //!< flag to print additional debug information
+};
+
+#endif // _RWMesh_TriangulationReader_HeaderFile
diff --git a/src/RWMesh/RWMesh_TriangulationSource.cxx b/src/RWMesh/RWMesh_TriangulationSource.cxx
new file mode 100644 (file)
index 0000000..39beb67
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (c) 2021 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <RWMesh_TriangulationSource.hxx>
+
+#include <RWMesh_TriangulationReader.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(RWMesh_TriangulationSource, Poly_Triangulation)
+
+// =======================================================================
+// function : RWMesh_TriangulationSource
+// purpose  :
+// =======================================================================
+RWMesh_TriangulationSource::RWMesh_TriangulationSource()
+: myNbDefNodes(0),
+  myNbDefTriangles(0),
+  myStatisticOfDegeneratedTriNb(0)
+{
+}
+
+// =======================================================================
+// function : ~RWMesh_TriangulationSource
+// purpose  :
+// =======================================================================
+RWMesh_TriangulationSource::~RWMesh_TriangulationSource()
+{
+  //
+}
+
+// =======================================================================
+// function : loadDeferredData
+// purpose  :
+// =======================================================================
+Standard_Boolean RWMesh_TriangulationSource::loadDeferredData (const Handle(OSD_FileSystem)& theFileSystem,
+                                                               const Handle(Poly_Triangulation)& theDestTriangulation) const
+{
+  myStatisticOfDegeneratedTriNb = 0;
+  if (myReader.IsNull())
+  {
+    return false;
+  }
+  if (myReader->Load (this, theDestTriangulation, theFileSystem))
+  {
+    return true;
+  }
+  return false;
+}
diff --git a/src/RWMesh/RWMesh_TriangulationSource.hxx b/src/RWMesh/RWMesh_TriangulationSource.hxx
new file mode 100644 (file)
index 0000000..cab9293
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright (c) 2021 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _RWMesh_TriangulationSource_HeaderFile
+#define _RWMesh_TriangulationSource_HeaderFile
+
+#include <Poly_Triangulation.hxx>
+
+class RWMesh_TriangulationReader;
+
+//! Mesh data wrapper for delayed triangulation loading.
+//! Class inherits Poly_Triangulation so that it can be put temporarily into TopoDS_Face within assembly structure.
+class RWMesh_TriangulationSource : public Poly_Triangulation
+{
+  DEFINE_STANDARD_RTTIEXT(RWMesh_TriangulationSource, Poly_Triangulation)
+public:
+
+  //! Constructor.
+  Standard_EXPORT RWMesh_TriangulationSource();
+
+  //! Destructor.
+  Standard_EXPORT virtual ~RWMesh_TriangulationSource();
+
+  //! Returns reader allowing to read data from the buffer.
+  const Handle(RWMesh_TriangulationReader)& Reader() const { return myReader; }
+
+  //! Sets reader allowing to read data from the buffer.
+  void SetReader (const Handle(RWMesh_TriangulationReader)& theReader) { myReader = theReader; }
+
+  //! Returns number of degenerated triangles collected during data reading.
+  //! Used for debug statistic purpose.
+  Standard_Integer DegeneratedTriNb() const { return myStatisticOfDegeneratedTriNb; }
+
+  //! Gets access to number of degenerated triangles to collect them during data reading.
+  Standard_Integer& ChangeDegeneratedTriNb() { return myStatisticOfDegeneratedTriNb; }
+
+public: //! @name late-load deferred data interface
+
+  //! Returns number of nodes for deferred loading.
+  //! Note: this is estimated values defined in object header, which might be different from actually loaded values
+  //! (due to broken header or extra mesh processing).
+  //! Always check triangulation size of actually loaded data in code to avoid out-of-range issues.
+  virtual Standard_Integer NbDeferredNodes() const Standard_OVERRIDE { return myNbDefNodes; }
+
+  //! Sets number of nodes for deferred loading.
+  void SetNbDeferredNodes (const Standard_Integer theNbNodes) { myNbDefNodes = theNbNodes; }
+
+  //! Returns number of triangles for deferred loading.
+  //! Note: this is estimated values defined in object header, which might be different from actually loaded values
+  //! (due to broken header or extra mesh processing).
+  //! Always check triangulation size of actually loaded data in code to avoid out-of-range issues.
+  virtual Standard_Integer NbDeferredTriangles() const Standard_OVERRIDE { return myNbDefTriangles; }
+
+  //! Sets number of triangles for deferred loading.
+  void SetNbDeferredTriangles (const Standard_Integer theNbTris) { myNbDefTriangles = theNbTris; }
+
+protected:
+
+  //! Loads triangulation data from deferred storage using specified shared input file system.
+  Standard_EXPORT virtual Standard_Boolean loadDeferredData (const Handle(OSD_FileSystem)& theFileSystem,
+                                                             const Handle(Poly_Triangulation)& theDestTriangulation) const Standard_OVERRIDE;
+
+protected:
+
+  Handle(RWMesh_TriangulationReader) myReader;
+  Standard_Integer                   myNbDefNodes;
+  Standard_Integer                   myNbDefTriangles;
+  mutable Standard_Integer           myStatisticOfDegeneratedTriNb;
+
+};
+
+#endif // _RWMesh_TriangulationSource_HeaderFile
index 412992a..7e2ddfb 100644 (file)
@@ -59,80 +59,88 @@ Select3D_SensitiveTriangulation::Select3D_SensitiveTriangulation (const Handle(S
                                                                   const Standard_Boolean theIsInterior)
 : Select3D_SensitiveSet (theOwnerId),
   myTriangul (theTrg),
-  myInitLocation (theInitLoc)
+  myInitLocation (theInitLoc),
+  myPrimitivesNb (0)
 {
   myInvInitLocation = myInitLocation.Transformation().Inverted();
   mySensType = theIsInterior ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
-  Standard_Integer aNbTriangles (myTriangul->NbTriangles());
+  Standard_Integer aNbTriangles = 0;
   gp_XYZ aCenter (0.0, 0.0, 0.0);
-
-  myPrimitivesNb = theIsInterior ? aNbTriangles : NbOfFreeEdges (theTrg);
-  myBVHPrimIndexes = new TColStd_HArray1OfInteger(0, myPrimitivesNb - 1);
-  TColStd_Array1OfInteger& aBVHPrimIdxs = myBVHPrimIndexes->ChangeArray1();
-
-  if (!theIsInterior)
+  if (!theTrg->HasGeometry())
+  {
+    if (myTriangul->HasCachedMinMax())
+    {
+      aCenter = 0.5 * (myTriangul->CachedMinMax().CornerMin().XYZ()
+                     + myTriangul->CachedMinMax().CornerMax().XYZ());
+    }
+  }
+  else
   {
-    Standard_Integer anEdgeIdx = 1;
-    myFreeEdges = new TColStd_HArray1OfInteger (1, 2 * myPrimitivesNb);
-    TColStd_Array1OfInteger& aFreeEdges = myFreeEdges->ChangeArray1();
-    Poly_Connect aPoly (myTriangul);
-    Standard_Integer aTriangle[3];
-    Standard_Integer aTrNodeIdx[3];
-    for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= aNbTriangles; aTriangleIdx++)
+    aNbTriangles = myTriangul->NbTriangles();
+    myPrimitivesNb = theIsInterior ? aNbTriangles : NbOfFreeEdges (theTrg);
+    myBVHPrimIndexes = new TColStd_HArray1OfInteger(0, myPrimitivesNb - 1);
+    TColStd_Array1OfInteger& aBVHPrimIdxs = myBVHPrimIndexes->ChangeArray1();
+
+    if (!theIsInterior)
     {
-      aPoly.Triangles (aTriangleIdx, aTriangle[0], aTriangle[1], aTriangle[2]);
-      myTriangul->Triangle (aTriangleIdx).Get (aTrNodeIdx[0], aTrNodeIdx[1], aTrNodeIdx[2]);
-      const gp_Pnt aTriNodes[3] = { myTriangul->Node (aTrNodeIdx[0]), myTriangul->Node (aTrNodeIdx[1]), myTriangul->Node (aTrNodeIdx[2]) };
-      aCenter += (aTriNodes[0].XYZ() + aTriNodes[1].XYZ()+ aTriNodes[2].XYZ()) / 3.0;
-      for (Standard_Integer aVertIdx = 0; aVertIdx < 3; aVertIdx++)
+      Standard_Integer anEdgeIdx = 1;
+      myFreeEdges = new TColStd_HArray1OfInteger (1, 2 * myPrimitivesNb);
+      TColStd_Array1OfInteger& aFreeEdges = myFreeEdges->ChangeArray1();
+      Poly_Connect aPoly (myTriangul);
+      Standard_Integer aTriangle[3];
+      Standard_Integer aTrNodeIdx[3];
+      for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= aNbTriangles; aTriangleIdx++)
       {
-        Standard_Integer aNextVert = (aVertIdx + 1) % 3;
-        if (aTriangle[aVertIdx] == 0)
+        aPoly.Triangles (aTriangleIdx, aTriangle[0], aTriangle[1], aTriangle[2]);
+        myTriangul->Triangle (aTriangleIdx).Get (aTrNodeIdx[0], aTrNodeIdx[1], aTrNodeIdx[2]);
+        const gp_Pnt aTriNodes[3] = { myTriangul->Node (aTrNodeIdx[0]), myTriangul->Node (aTrNodeIdx[1]), myTriangul->Node (aTrNodeIdx[2]) };
+        aCenter += (aTriNodes[0].XYZ() + aTriNodes[1].XYZ()+ aTriNodes[2].XYZ()) / 3.0;
+        for (Standard_Integer aVertIdx = 0; aVertIdx < 3; aVertIdx++)
         {
-          aFreeEdges (anEdgeIdx)  = aTrNodeIdx[aVertIdx];
-          aFreeEdges (anEdgeIdx+1) = aTrNodeIdx[aNextVert];
-          anEdgeIdx += 2;
+          Standard_Integer aNextVert = (aVertIdx + 1) % 3;
+          if (aTriangle[aVertIdx] == 0)
+          {
+            aFreeEdges (anEdgeIdx)  = aTrNodeIdx[aVertIdx];
+            aFreeEdges (anEdgeIdx+1) = aTrNodeIdx[aNextVert];
+            anEdgeIdx += 2;
+          }
         }
       }
     }
-  }
-  else
-  {
-    Standard_Integer aTrNodeIdx[3];
-    for (Standard_Integer aTrIdx = 1; aTrIdx <= aNbTriangles; aTrIdx++)
+    else
     {
-      myTriangul->Triangle (aTrIdx).Get (aTrNodeIdx[0], aTrNodeIdx[1], aTrNodeIdx[2]);
-      const gp_Pnt aTriNodes[3] = { myTriangul->Node (aTrNodeIdx[0]), myTriangul->Node (aTrNodeIdx[1]), myTriangul->Node (aTrNodeIdx[2]) };
-      aCenter += (aTriNodes[0].XYZ() + aTriNodes[1].XYZ()+ aTriNodes[2].XYZ()) / 3.0;
+      Standard_Integer aTrNodeIdx[3];
+      for (Standard_Integer aTrIdx = 1; aTrIdx <= aNbTriangles; aTrIdx++)
+      {
+        myTriangul->Triangle (aTrIdx).Get (aTrNodeIdx[0], aTrNodeIdx[1], aTrNodeIdx[2]);
+        const gp_Pnt aTriNodes[3] = { myTriangul->Node (aTrNodeIdx[0]), myTriangul->Node (aTrNodeIdx[1]), myTriangul->Node (aTrNodeIdx[2]) };
+        aCenter += (aTriNodes[0].XYZ() + aTriNodes[1].XYZ()+ aTriNodes[2].XYZ()) / 3.0;
+      }
     }
-  }
-  if (aNbTriangles != 0)
-    aCenter /= aNbTriangles;
-  myCDG3D = gp_Pnt (aCenter);
 
-  myBndBox.Clear();
-  for (Standard_Integer aNodeIdx = 1; aNodeIdx <= myTriangul->NbNodes(); ++aNodeIdx)
-  {
-    const gp_Pnt aNode = myTriangul->Node (aNodeIdx);
-    myBndBox.Add (SelectMgr_Vec3 (aNode.X(), aNode.Y(), aNode.Z()));
-  }
-
-  if (theIsInterior)
-  {
-    for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= aNbTriangles; ++aTriangleIdx)
+    if (theIsInterior)
     {
-      aBVHPrimIdxs (aTriangleIdx - 1) = aTriangleIdx - 1;
+      for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= aNbTriangles; ++aTriangleIdx)
+      {
+        aBVHPrimIdxs(aTriangleIdx - 1) = aTriangleIdx - 1;
+      }
     }
-  }
-  else
-  {
-    Standard_Integer aStartIdx = myFreeEdges->Lower();
-    Standard_Integer anEndIdx = myFreeEdges->Upper();
-    for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
+    else
     {
-      aBVHPrimIdxs ((aFreeEdgesIdx - aStartIdx) / 2) = (aFreeEdgesIdx - aStartIdx) / 2;
+      Standard_Integer aStartIdx = myFreeEdges->Lower();
+      Standard_Integer anEndIdx = myFreeEdges->Upper();
+      for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
+      {
+        aBVHPrimIdxs((aFreeEdgesIdx - aStartIdx) / 2) = (aFreeEdgesIdx - aStartIdx) / 2;
+      }
     }
   }
+  if (aNbTriangles != 0)
+  {
+    aCenter /= aNbTriangles;
+  }
+  myCDG3D = gp_Pnt (aCenter);
+  computeBoundingBox();
 }
 
 //=======================================================================
@@ -149,26 +157,30 @@ Select3D_SensitiveTriangulation::Select3D_SensitiveTriangulation (const Handle(S
   myTriangul (theTrg),
   myInitLocation (theInitLoc),
   myCDG3D (theCOG),
-  myFreeEdges (theFreeEdges)
+  myFreeEdges (theFreeEdges),
+  myPrimitivesNb (0)
 {
   myInvInitLocation = myInitLocation.Transformation().Inverted();
   mySensType = theIsInterior ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
-  myPrimitivesNb = theIsInterior ? theTrg->NbTriangles() : theFreeEdges->Length() / 2;
-  myBVHPrimIndexes = new TColStd_HArray1OfInteger(0, myPrimitivesNb - 1);
-  if (theIsInterior)
+  if (theTrg->HasGeometry())
   {
-    for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= myPrimitivesNb; ++aTriangleIdx)
+    myPrimitivesNb = theIsInterior ? theTrg->NbTriangles() : theFreeEdges->Length() / 2;
+    myBVHPrimIndexes = new TColStd_HArray1OfInteger(0, myPrimitivesNb - 1);
+    if (theIsInterior)
     {
-      myBVHPrimIndexes->SetValue (aTriangleIdx - 1, aTriangleIdx - 1);
+      for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= myPrimitivesNb; ++aTriangleIdx)
+      {
+        myBVHPrimIndexes->SetValue (aTriangleIdx - 1, aTriangleIdx - 1);
+      }
     }
-  }
-  else
-  {
-    Standard_Integer aStartIdx = myFreeEdges->Lower();
-    Standard_Integer anEndIdx = myFreeEdges->Upper();
-    for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
+    else
     {
-      myBVHPrimIndexes->SetValue ((aFreeEdgesIdx - aStartIdx) / 2, (aFreeEdgesIdx - aStartIdx) / 2);
+      Standard_Integer aStartIdx = myFreeEdges->Lower();
+      Standard_Integer anEndIdx = myFreeEdges->Upper();
+      for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
+      {
+        myBVHPrimIndexes->SetValue ((aFreeEdgesIdx - aStartIdx) / 2, (aFreeEdgesIdx - aStartIdx) / 2);
+      }
     }
   }
 }
@@ -226,6 +238,37 @@ Select3D_BndBox3d Select3D_SensitiveTriangulation::Box (const Standard_Integer t
   return Select3D_BndBox3d (aMinPnt, aMaxPnt);
 }
 
+// =======================================================================
+// function : Matches
+// purpose  :
+// =======================================================================
+Standard_Boolean Select3D_SensitiveTriangulation::Matches (SelectBasics_SelectingVolumeManager& theMgr,
+                                                           SelectBasics_PickResult& thePickResult)
+{
+  if (myTriangul->HasGeometry())
+  {
+    return Select3D_SensitiveSet::Matches (theMgr, thePickResult);
+  }
+
+  Select3D_BndBox3d aBndBox = BoundingBox();
+  if (!aBndBox.IsValid())
+  {
+    return false;
+  }
+
+  if (!theMgr.IsOverlapAllowed()) // check for inclusion
+  {
+    bool isInside = true;
+    return theMgr.Overlaps (aBndBox.CornerMin(), aBndBox.CornerMax(), &isInside) && isInside;
+  }
+  if (!theMgr.Overlaps (aBndBox.CornerMin(), aBndBox.CornerMax(), thePickResult)) // check for overlap
+  {
+    return false;
+  }
+  thePickResult.SetDistToGeomCenter (theMgr.DistToGeometryCenter (myCDG3D));
+  return true;
+}
+
 //=======================================================================
 // function : Center
 // purpose  : Returns geometry center of triangle/edge with index theIdx
@@ -430,22 +473,41 @@ Select3D_BndBox3d Select3D_SensitiveTriangulation::applyTransformation()
 //=======================================================================
 Select3D_BndBox3d Select3D_SensitiveTriangulation::BoundingBox()
 {
-  if (myBndBox.IsValid())
-    return applyTransformation();
-
-  const Standard_Integer aLower = 1;
-  const Standard_Integer anUpper = myTriangul->NbNodes();
-  Select3D_BndBox3d aBndBox;
-  for (Standard_Integer aNodeIdx = aLower; aNodeIdx <= anUpper; ++aNodeIdx)
+  if (!myBndBox.IsValid())
   {
-    const gp_Pnt aNode = myTriangul->Node (aNodeIdx);
-    const SelectMgr_Vec3 aNodeTransf = SelectMgr_Vec3 (aNode.X(), aNode.Y(), aNode.Z());
-    aBndBox.Add (aNodeTransf);
+    computeBoundingBox();
   }
+  return applyTransformation();
+}
 
-  myBndBox = aBndBox;
+// =======================================================================
+// function : computeBoundingBox
+// purpose  :
+// =======================================================================
+void Select3D_SensitiveTriangulation::computeBoundingBox()
+{
+  myBndBox.Clear();
 
-  return applyTransformation();
+  if (myTriangul->HasCachedMinMax())
+  {
+    // Use cached MeshData_Data bounding box if it exists
+    Bnd_Box aCachedBox = myTriangul->CachedMinMax();
+    myBndBox.Add (SelectMgr_Vec3 (aCachedBox.CornerMin().X(),
+                                  aCachedBox.CornerMin().Y(),
+                                  aCachedBox.CornerMin().Z()));
+    myBndBox.Add (SelectMgr_Vec3 (aCachedBox.CornerMax().X(),
+                                  aCachedBox.CornerMax().Y(),
+                                  aCachedBox.CornerMax().Z()));
+    return;
+  }
+  else if (myTriangul->HasGeometry())
+  {
+    for (Standard_Integer aNodeIdx = 1; aNodeIdx <= myTriangul->NbNodes(); ++aNodeIdx)
+    {
+      const gp_Pnt aNode = myTriangul->Node (aNodeIdx);
+      myBndBox.Add (SelectMgr_Vec3 (aNode.X(), aNode.Y(), aNode.Z()));
+    }
+  }
 }
 
 //=======================================================================
index 550a333..dbc8871 100644 (file)
@@ -119,8 +119,15 @@ public:
   //! Dumps the content of me into the stream
   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE;
 
+  //! Checks whether one or more entities of the set overlap current selecting volume.
+  Standard_EXPORT virtual Standard_Boolean Matches (SelectBasics_SelectingVolumeManager& theMgr,
+                                                    SelectBasics_PickResult& thePickResult) Standard_OVERRIDE;
+
 protected:
 
+  //! Compute bounding box.
+  void computeBoundingBox();
+
   //! Inner function for transformation application to bounding
   //! box of the triangulation
   Select3D_BndBox3d applyTransformation();
index 6a56b81..dde6a79 100644 (file)
@@ -179,7 +179,7 @@ namespace
     {
       const TopoDS_Face& aFace = TopoDS::Face(aFaceIt.Current());
       aT = BRep_Tool::Triangulation (aFace, aLoc);
-      if (aT.IsNull())
+      if (aT.IsNull() || !aT->HasGeometry())
       {
         continue;
       }
index 1b5d539..4393c5c 100644 (file)
@@ -4840,6 +4840,7 @@ static int VDisplay2 (Draw_Interpretor& theDI,
   Standard_Integer   anObjDispMode  = -2;
   Standard_Integer   anObjHighMode  = -2;
   Standard_Boolean   toSetTrsfPers  = Standard_False;
+  Standard_Boolean   toEcho         = Standard_True;
   Handle(Graphic3d_TransformPers) aTrsfPers;
   TColStd_SequenceOfAsciiString aNamesOfDisplayIO;
   AIS_DisplayStatus aDispStatus = AIS_DS_None;
@@ -5046,6 +5047,10 @@ static int VDisplay2 (Draw_Interpretor& theDI,
     {
       aDispStatus = AIS_DS_Erased;
     }
+    else if (aNameCase == "-noecho")
+    {
+      toEcho = false;
+    }
     else
     {
       aNamesOfDisplayIO.Append (aName);
@@ -5175,7 +5180,10 @@ static int VDisplay2 (Draw_Interpretor& theDI,
     }
     else
     {
-      theDI << "Display " << aName << "\n";
+      if (toEcho)
+      {
+        theDI << "Display " << aName << "\n";
+      }
 
       // update the Shape in the AIS_Shape
       TopoDS_Shape      aNewShape = DBRep::GetExisting (aName);
@@ -6540,6 +6548,7 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands)
       "\n\t\t:          [-dispMode mode] [-highMode mode]"
       "\n\t\t:          [-layer index] [-top|-topmost|-overlay|-underlay]"
       "\n\t\t:          [-redisplay] [-erased]"
+      "\n\t\t:          [-noecho]"
       "\n\t\t:          name1 [name2] ... [name n]"
       "\n\t\t: Displays named objects."
       "\n\t\t: Option -local enables displaying of objects in local"
@@ -6567,7 +6576,8 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands)
       "\n\t\t:               (DY looks up)"
       "\n\t\t:  -dispmode    Sets display mode for objects."
       "\n\t\t:  -highmode    Sets hilight mode for objects."
-      "\n\t\t:  -redisplay   Recomputes presentation of objects.",
+      "\n\t\t:  -redisplay   Recomputes presentation of objects."
+      "\n\t\t:  -noecho      Avoid printing of command results.",
       __FILE__, VDisplay2, group);
 
   theCommands.Add ("vnbdisplayed",
index cf7f492..0d3b111 100644 (file)
@@ -609,10 +609,10 @@ private:
     myToExplore  (Standard_False) {}
 
   //! Display single label.
-  Standard_Integer displayLabel (Draw_Interpretor& theDI,
-                                 const TDF_Label& theLabel,
+  Standard_Integer displayLabel (const TDF_Label& theLabel,
                                  const TCollection_AsciiString& theNamePrefix,
-                                 const TopLoc_Location& theLoc)
+                                 const TopLoc_Location& theLoc,
+                                 TCollection_AsciiString& theOutDispList)
   {
     TCollection_AsciiString aName;
     if (myToGetNames)
@@ -661,7 +661,7 @@ private:
         const TopLoc_Location aLoc = theLoc * XCAFDoc_ShapeTool::GetLocation (theLabel);
         for (TDF_ChildIterator aChildIter (aRefLabel); aChildIter.More(); aChildIter.Next())
         {
-          if (displayLabel (theDI, aChildIter.Value(), aName, aLoc) == 1)
+          if (displayLabel (aChildIter.Value(), aName, aLoc, theOutDispList) == 1)
           {
             return 1;
           }
@@ -703,7 +703,7 @@ private:
     }
 
     ViewerTest::Display (aName, aPrs, false);
-    theDI << aName << " ";
+    theOutDispList += aName + " ";
     return 0;
   }
 
@@ -787,6 +787,12 @@ private:
           myToExplore = !myToExplore;
         }
       }
+      else if (anArgCase == "-outdisplist"
+            && anArgIter + 1 < theNbArgs)
+      {
+        myOutDispListVar = theArgVec[++anArgIter];
+        myOutDispList.Clear();
+      }
       else
       {
         if (myDoc.IsNull()
@@ -848,11 +854,19 @@ private:
     for (TDF_LabelSequence::Iterator aLabIter (myLabels); aLabIter.More(); aLabIter.Next())
     {
       const TDF_Label& aLabel = aLabIter.Value();
-      if (displayLabel (theDI, aLabel, myToPrefixDocName ? myDocName + ":" : "", TopLoc_Location()) == 1)
+      if (displayLabel (aLabel, myToPrefixDocName ? myDocName + ":" : "", TopLoc_Location(), myOutDispList) == 1)
       {
         return 1;
       }
     }
+    if (myOutDispListVar.IsEmpty())
+    {
+      theDI << myOutDispList;
+    }
+    else
+    {
+      Draw::Set (myOutDispListVar.ToCString(), myOutDispList.ToCString());
+    }
     return 0;
   }
 
@@ -861,6 +875,8 @@ private:
                            myNameMap;         //!< names map to handle collisions
   Handle(TDocStd_Document) myDoc;             //!< document
   TCollection_AsciiString  myDocName;         //!< document name
+  TCollection_AsciiString  myOutDispListVar;  //!< tcl variable to print the result objects
+  TCollection_AsciiString  myOutDispList;     //!< string with list of all displayed object names
   TDF_LabelSequence        myLabels;          //!< labels to display
   Standard_Integer         myDispMode;        //!< shape display mode
   Standard_Integer         myHiMode;          //!< shape highlight mode
@@ -1466,7 +1482,9 @@ void XDEDRAW::Init(Draw_Interpretor& di)
           "\n\t\t:  -highMode    Presentation highlight mode."
           "\n\t\t:  -docPrefix   Prepend document name to object names; TRUE by default."
           "\n\t\t:  -names       Use object names instead of label tag; TRUE by default."
-          "\n\t\t:  -explore     Explode labels to leaves; FALSE by default.",
+          "\n\t\t:  -explore     Explode labels to leaves; FALSE by default."
+          "\n\t\t:  -outDispList Set the TCL variable to the list of displayed object names."
+          "\n\t\t:               (instead of printing them to draw interpreter)",
           __FILE__, XDEDRAW_XDisplayTool::XDisplay, g);
 
   di.Add ("XWdump","Doc filename.{gif|xwd|bmp} \t: Dump contents of viewer window to XWD, GIF or BMP file",
index 66370c2..9a33cb7 100644 (file)
@@ -103,6 +103,9 @@ static Standard_Integer ReadGltf (Draw_Interpretor& theDI,
   Standard_Boolean toListExternalFiles = Standard_False;
   Standard_Boolean isParallel = Standard_False;
   Standard_Boolean isDoublePrec = Standard_False;
+  Standard_Boolean toSkipLateDataLoading = Standard_False;
+  Standard_Boolean toKeepLateData = Standard_True;
+  Standard_Boolean toPrintDebugInfo = Standard_False;
   Standard_Boolean isNoDoc = (TCollection_AsciiString(theArgVec[0]) == "readgltf");
   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
   {
@@ -144,6 +147,34 @@ static Standard_Integer ReadGltf (Draw_Interpretor& theDI,
         isDoublePrec = !isDoublePrec;
       }
     }
+    else if (anArgCase == "-skiplateloading")
+    {
+      toSkipLateDataLoading = Standard_True;
+      if (anArgIter + 1 < theNbArgs
+       && Draw::ParseOnOff (theArgVec[anArgIter + 1], toSkipLateDataLoading))
+      {
+        ++anArgIter;
+      }
+    }
+    else if (anArgCase == "-keeplate")
+    {
+      toKeepLateData = Standard_True;
+      if (anArgIter + 1 < theNbArgs
+       && Draw::ParseOnOff (theArgVec[anArgIter + 1], toKeepLateData))
+      {
+        ++anArgIter;
+      }
+    }
+    else if (anArgCase == "-toprintinfo"
+          || anArgCase == "-toprintdebuginfo")
+    {
+      toPrintDebugInfo = Standard_True;
+      if (anArgIter + 1 < theNbArgs
+       && Draw::ParseOnOff (theArgVec[anArgIter + 1], toPrintDebugInfo))
+      {
+        ++anArgIter;
+      }
+    }
     else if (anArgCase == "-listexternalfiles"
           || anArgCase == "-listexternals"
           || anArgCase == "-listexternal"
@@ -202,6 +233,9 @@ static Standard_Integer ReadGltf (Draw_Interpretor& theDI,
   aReader.SetDocument (aDoc);
   aReader.SetParallel (isParallel);
   aReader.SetDoublePrecision (isDoublePrec);
+  aReader.SetToSkipLateDataLoading (toSkipLateDataLoading);
+  aReader.SetToKeepLateData (toKeepLateData);
+  aReader.SetToPrintDebugMessages (toPrintDebugInfo);
   if (toListExternalFiles)
   {
     aReader.ProbeHeader (aFilePath);
@@ -1743,7 +1777,12 @@ void  XSDRAWSTLVRML::InitCommands (Draw_Interpretor& theCommands)
                    "\n\t\t:   -listExternalFiles do not read mesh and only list external files"
                    "\n\t\t:   -noCreateDoc read into existing XDE document"
                    "\n\t\t:   -doublePrecision store triangulation with double or single floating point"
-                   "\n\t\t:                    precision (single by default)",
+                   "\n\t\t:                    precision (single by default)"
+                   "\n\t\t:   -skipLateLoading data loading is skipped and can be performed later"
+                   "\n\t\t:                    (false by default)"
+                   "\n\t\t:   -keepLate data is loaded into itself with preservation of information"
+                   "\n\t\t:             about deferred storage to load/unload this data later.",
+                   "\n\t\t:   -toPrintDebugInfo print additional debug inforamtion during data reading"
                    __FILE__, ReadGltf, g);
   theCommands.Add ("readgltf",
                    "readgltf shape file"
index db0cc9b..16ba41b 100644 (file)
@@ -11,14 +11,14 @@ restore [locate_data_file bug25519_testtriangulation.brep] a
 tclean a
 incmesh a 0.01 -a 50
 set bug_info [trinfo a]
-set TNumber_1 [lindex $bug_info 3]
-set NNumber_1 [lindex $bug_info 5]
+set TNumber_1 [lindex $bug_info 5]
+set NNumber_1 [lindex $bug_info 7]
 
 tclean a
 incmesh a 0.01 -a 50 -surf_def_off
 set bug_info [trinfo a]
-set TNumber_2 [lindex $bug_info 3]
-set NNumber_2 [lindex $bug_info 5]
+set TNumber_2 [lindex $bug_info 5]
+set NNumber_2 [lindex $bug_info 7]
 
 if {$TNumber_2 >= $TNumber_1} {
    puts "ERROR: OCC25612 is reproduced. Flag -surf_def_off does not work (triangles)."
index ba17735..09d0ad7 100644 (file)
@@ -15,7 +15,7 @@ mkface f c 0 6.28318530717958647 0 10
 # Mesh the face and store initial data
 incmesh f 0.1
 set base [trinfo f]
-regexp {This shape contains ([0-9]+) triangles.\s* ([0-9]+) nodes.} $base dummy base_tria base_nodes
+regexp {([0-9]+) +triangles.*[^0-9]([0-9]+) +nodes} $base dummy base_tria base_nodes
 regexp {Maximal deflection ([-0-9.+eE]+)} $base dummy base_defl
 
 # Copy face
diff --git a/tests/de_mesh/gltf_lateload/begin b/tests/de_mesh/gltf_lateload/begin
new file mode 100644 (file)
index 0000000..a6de429
--- /dev/null
@@ -0,0 +1,2 @@
+pload XDE OCAF MODELING VISUALIZATION
+catch { Close D }
diff --git a/tests/de_mesh/gltf_lateload/boxwithoutindices b/tests/de_mesh/gltf_lateload/boxwithoutindices
new file mode 100644 (file)
index 0000000..1b3b393
--- /dev/null
@@ -0,0 +1,51 @@
+puts "========"
+puts "0032086: Visualization - support deferred data loading"
+puts "========"
+
+# glTF file content
+set cubeWithoutIndicesGltf {
+{
+"asset": {"generator": "","version": "2.0"},
+"scene": "defaultScene",
+"scenes": {"defaultScene": {"nodes": ["rootNode"]}},
+"nodes": {"rootNode": {
+"children": [],"meshes": ["Geometry-mesh002"], "matrix":
+[1.0,0.0,0.0,0.0,0.0,0.0,-1.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0]}},
+"meshes": {"Geometry-mesh002": {"name": "Mesh", "primitives":
+[{"attributes": {"NORMAL": "accessor_20","POSITION": "accessor_18"},
+"material": 0,"mode": 4}]}},
+"accessors": {
+"accessor_18": {"bufferView": "bufferView_0","byteOffset": 0,"byteStride": 0,"componentType": 5126,"count": 36,"max": [0.5,0.5,0.5],"min": [-0.5,-0.5,-0.5],"type": "VEC3"},
+"accessor_20": {"bufferView": "bufferView_0","byteOffset": 432,"byteStride": 0,"componentType": 5126,"count": 36,"max": [1.0,1.0,1.0],"min": [-1.0,-1.0,-1.0],"type": "VEC3"}},
+"materials": {
+"Effect-Red": {"name": "Red","technique": "technique0","values":
+{"diffuse": [0.8,0.0,0.0,1.0],"shininess": 256,"specular": [0.2,0.2,0.2,1.0]}}},
+"bufferViews": {
+"bufferView_0": {"buffer": "BoxWithoutIndices","byteOffset": 0,"byteLength": 864,"target": 34962}},
+"buffers": {
+"BoxWithoutIndices": {"byteLength": 864,"type": "arraybuffer","uri": "data:application/octet-stream;base64,AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAA/AAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/"}}
+}
+}
+
+set fd [open ${imagedir}/${casename}.gltf w]
+fconfigure $fd -translation lf
+puts $fd $cubeWithoutIndicesGltf
+close $fd
+
+ReadGltf D ${imagedir}/${casename}.gltf -skiplateloading 1
+XGetOneShape s D
+trinfo s -lods
+
+vclear
+vinit View1
+XDisplay D -explore -dispMode 1 -outdisplist prsList
+vfit
+
+vdump ${imagedir}/${casename}_empty.png
+
+trlateload s -load
+checktrinfo s -tri 12 -nod 36
+vdisplay {*}$prsList -redisplay -noecho
+vfit
+
+vdump ${imagedir}/${casename}_loaded.png
diff --git a/tests/de_mesh/gltf_lateload/engine b/tests/de_mesh/gltf_lateload/engine
new file mode 100644 (file)
index 0000000..b1d1089
--- /dev/null
@@ -0,0 +1,23 @@
+puts "========"
+puts "0032086: Visualization - support deferred data loading"
+puts "========"
+
+ReadGltf D [locate_data_file bug30691_2CylinderEngine.glb] -skiplateloading 1
+XGetOneShape s D
+checktrinfo s -tri 0 -nod 0
+
+vclear
+vinit View1
+XDisplay D -explore -dispMode 1 -outdisplist prsList
+vfit
+
+vdump ${imagedir}/${casename}_empty.png
+
+trlateload s -load
+checktrinfo s -face 115 -tri 121496 -nod 84657
+vdisplay {*}$prsList -redisplay -noecho
+vfit
+
+trinfo s -lods
+
+vdump ${imagedir}/${casename}_loaded.png
index 60189db..55f4aca 100644 (file)
@@ -3,3 +3,4 @@
 003 gltf_read
 004 obj_read
 005 gltf_write
+006 gltf_lateload