0027772: Foundation Classes - define Standard_Boolean using C++ type "bool" instead...
[occt.git] / src / RWStl / RWStl.cxx
old mode 100755 (executable)
new mode 100644 (file)
index 8079a57..d574f34
@@ -1,33 +1,78 @@
-// File:       RWStl.cxx
-// Created:    Thu Oct 13 13:41:29 1994
-// Author:     Marc LEGAY
-//             <mle@bourdon>
-
-// Copyright:    Matra Datavision      
-
-#include <RWStl.ixx>   
-#include <OSD_Protection.hxx>
+// Created on: 1994-10-13
+// Created by: Marc LEGAY
+// Copyright (c) 1994-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.
+
+
+#include <BRepBuilderAPI_CellFilter.hxx>
+#include <BRepBuilderAPI_VertexInspector.hxx>
+#include <gp.hxx>
+#include <gp_Vec.hxx>
+#include <gp_XYZ.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <Message_ProgressIndicator.hxx>
+#include <Message_ProgressSentry.hxx>
+#include <OSD.hxx>
 #include <OSD_File.hxx>
-#include <TCollection_AsciiString.hxx>
+#include <OSD_Host.hxx>
+#include <OSD_OpenFile.hxx>
+#include <OSD_Path.hxx>
+#include <OSD_Protection.hxx>
+#include <Precision.hxx>
+#include <RWStl.hxx>
 #include <Standard_NoMoreObject.hxx>
 #include <Standard_TypeMismatch.hxx>
-#include <Precision.hxx>
+#include <StlMesh_Mesh.hxx>
 #include <StlMesh_MeshExplorer.hxx>
-#include <OSD.hxx>
-#include <OSD_Host.hxx>
-#include <gp_XYZ.hxx>
-#include <gp.hxx>
-#include <stdio.h>
-#include <gp_Vec.hxx>
+#include <TCollection_AsciiString.hxx>
 
+#include <stdio.h>
+// A static method adding nodes to a mesh and keeping coincident (sharing) nodes.
+static Standard_Integer AddVertex(Handle(StlMesh_Mesh)& mesh,
+                                  BRepBuilderAPI_CellFilter& filter, 
+                                  BRepBuilderAPI_VertexInspector& inspector,
+                                  const gp_XYZ& p)
+{
+  Standard_Integer index;
+  inspector.SetCurrent(p);
+  gp_XYZ minp = inspector.Shift(p, -Precision::Confusion());
+  gp_XYZ maxp = inspector.Shift(p, +Precision::Confusion());
+  filter.Inspect(minp, maxp, inspector);
+  const TColStd_ListOfInteger& indices = inspector.ResInd();
+  if (indices.IsEmpty() == Standard_False)
+  {
+    index = indices.First(); // it should be only one
+    inspector.ClearResList();
+  }
+  else
+  {
+    index = mesh->AddVertex(p.X(), p.Y(), p.Z());
+    filter.Add(index, p);
+    inspector.Add(p);
+  }
+  return index;
+}
 
 // constants
-static const int HEADER_SIZE           =  84; 
-static const int SIZEOF_STL_FACET      =  50; 
-static const int STL_MIN_FILE_SIZE     = 284; 
-static const int ASCII_LINES_PER_FACET =   7; 
+static const size_t HEADER_SIZE           =  84;
+static const size_t SIZEOF_STL_FACET      =  50;
+static const size_t ASCII_LINES_PER_FACET =   7;
+
+static const int IND_THRESHOLD = 1000; // increment the indicator every 1k triangles
 
-//=============== =======================================================
+//=======================================================================
 //function : WriteInteger
 //purpose  : writing a Little Endian 32 bits integer
 //=======================================================================
@@ -42,7 +87,7 @@ inline static void WriteInteger(OSD_File& ofile,const Standard_Integer value)
   bidargum.i = value;
 
   Standard_Integer entier;
-  
+
   entier  =  bidargum.c[0] & 0xFF;
   entier |= (bidargum.c[1] & 0xFF) << 0x08;
   entier |= (bidargum.c[2] & 0xFF) << 0x10;
@@ -66,7 +111,7 @@ inline static void WriteDouble2Float(OSD_File& ofile,Standard_Real value)
   bidargum.f = (Standard_ShortReal)value;
 
   Standard_Integer entier;
-  
+
   entier  =  bidargum.c[0] & 0xFF;
   entier |= (bidargum.c[1] & 0xFF) << 0x08;
   entier |= (bidargum.c[2] & 0xFF) << 0x10;
@@ -84,8 +129,8 @@ inline static void WriteDouble2Float(OSD_File& ofile,Standard_Real value)
 inline static Standard_Real ReadFloat2Double(OSD_File &aFile)
 {
   union {
-    Standard_Boolean i; // don't be afraid, this is just an unsigned int
-    Standard_ShortReal f;
+    uint32_t i;
+    float    f;
   }bidargum;
 
   char c[4];
@@ -108,188 +153,180 @@ inline static Standard_Real ReadFloat2Double(OSD_File &aFile)
 //purpose  : write a binary STL file in Little Endian format
 //=======================================================================
 
-Standard_Boolean RWStl::WriteBinary(const Handle(StlMesh_Mesh)& aMesh, const OSD_Path& aPath)
+Standard_Boolean RWStl::WriteBinary (const Handle(StlMesh_Mesh)& theMesh,
+                                     const OSD_Path& thePath,
+                                     const Handle(Message_ProgressIndicator)& theProgInd)
 {
-  
-  OSD_File theFile = OSD_File (aPath);
-  theFile.Build(OSD_WriteOnly,OSD_Protection());
+  OSD_File aFile (thePath);
+  aFile.Build (OSD_WriteOnly, OSD_Protection());
 
   Standard_Real x1, y1, z1;
   Standard_Real x2, y2, z2;
   Standard_Real x3, y3, z3;
-  
-  //pgo  Standard_Real x,y,z;
-  
+
+  // writing 80 bytes of the trash?
   char sval[80];
-  Standard_Integer NBTRIANGLES=0;
-  unsigned int NBT;
-  NBTRIANGLES = aMesh->NbTriangles();
-  NBT = NBTRIANGLES ;
-  theFile.Write ((Standard_Address)sval,80);
-  WriteInteger(theFile,NBT);  
-//  theFile.Write ((Standard_Address)&NBT,4);
+  aFile.Write ((Standard_Address)sval,80);
+  WriteInteger (aFile, theMesh->NbTriangles());
+
   int dum=0;
-  StlMesh_MeshExplorer aMexp (aMesh);
-  
-  
-  for (Standard_Integer nbd=1;nbd<=aMesh->NbDomains();nbd++) {
-    for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle (); aMexp.NextTriangle ()) {
-       aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
-       //pgo     aMexp.TriangleOrientation (x,y,z);
-       gp_XYZ Vect12 ((x2-x1), (y2-y1), (z2-z1));
-       gp_XYZ Vect13 ((x3-x1), (y3-y1), (z3-z1));
-       gp_XYZ Vnorm = Vect12 ^ Vect13;
-       Standard_Real Vmodul = Vnorm.Modulus ();
-       if (Vmodul > gp::Resolution()) {
-         Vnorm.Divide(Vmodul);
-       }
-       else {
-         // si Vnorm est quasi-nul, on le charge a 0 explicitement
-         Vnorm.SetCoord (0., 0., 0.);
-       }
-       
-       WriteDouble2Float (theFile,Vnorm.X());
-       WriteDouble2Float (theFile,Vnorm.Y());
-       WriteDouble2Float (theFile,Vnorm.Z());
-       
-       WriteDouble2Float (theFile,x1);
-       WriteDouble2Float (theFile,y1);
-       WriteDouble2Float (theFile,z1);
-
-       WriteDouble2Float (theFile,x2);
-       WriteDouble2Float (theFile,y2);
-       WriteDouble2Float (theFile,z2);
-       
-       WriteDouble2Float (theFile,x3);
-       WriteDouble2Float (theFile,y3);
-       WriteDouble2Float (theFile,z3);
-
-       theFile.Write (&dum,2);
-       
+  StlMesh_MeshExplorer aMexp (theMesh);
+
+  // create progress sentry for domains
+  Standard_Integer aNbDomains = theMesh->NbDomains();
+  Message_ProgressSentry aDPS (theProgInd, "Mesh domains", 0, aNbDomains, 1);
+  for (Standard_Integer nbd = 1; nbd <= aNbDomains && aDPS.More(); nbd++, aDPS.Next())
+  {
+    // create progress sentry for triangles in domain
+    Message_ProgressSentry aTPS (theProgInd, "Triangles", 0,
+        theMesh->NbTriangles (nbd), IND_THRESHOLD);
+    Standard_Integer aTriangleInd = 0;
+    for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle(); aMexp.NextTriangle())
+    {
+      aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
+      //pgo      aMexp.TriangleOrientation (x,y,z);
+      gp_XYZ Vect12 ((x2-x1), (y2-y1), (z2-z1));
+      gp_XYZ Vect13 ((x3-x1), (y3-y1), (z3-z1));
+      gp_XYZ Vnorm = Vect12 ^ Vect13;
+      Standard_Real Vmodul = Vnorm.Modulus ();
+      if (Vmodul > gp::Resolution())
+      {
+        Vnorm.Divide(Vmodul);
+      }
+      else
+      {
+        // si Vnorm est quasi-nul, on le charge a 0 explicitement
+        Vnorm.SetCoord (0., 0., 0.);
       }
+
+      WriteDouble2Float (aFile, Vnorm.X());
+      WriteDouble2Float (aFile, Vnorm.Y());
+      WriteDouble2Float (aFile, Vnorm.Z());
+
+      WriteDouble2Float (aFile, x1);
+      WriteDouble2Float (aFile, y1);
+      WriteDouble2Float (aFile, z1);
+
+      WriteDouble2Float (aFile, x2);
+      WriteDouble2Float (aFile, y2);
+      WriteDouble2Float (aFile, z2);
+
+      WriteDouble2Float (aFile, x3);
+      WriteDouble2Float (aFile, y3);
+      WriteDouble2Float (aFile, z3);
+
+      aFile.Write (&dum, 2);
+
+      // update progress only per 1k triangles
+      if (++aTriangleInd % IND_THRESHOLD == 0)
+      {
+        if (!aTPS.More())
+          break;
+        aTPS.Next();
+      }
+    }
   }
-  
-  theFile.Close ();
-  return Standard_True;
+  aFile.Close();
+  Standard_Boolean isInterrupted = !aDPS.More();
+  return !isInterrupted;
 }
 //=======================================================================
 //function : WriteAscii
 //purpose  : write an ASCII STL file
 //=======================================================================
 
-Standard_Boolean RWStl::WriteAscii(const Handle(StlMesh_Mesh)& aMesh, const OSD_Path& aPath)
+Standard_Boolean RWStl::WriteAscii (const Handle(StlMesh_Mesh)& theMesh,
+                                    const OSD_Path& thePath,
+                                    const Handle(Message_ProgressIndicator)& theProgInd)
 {
-  OSD_File theFile = OSD_File (aPath);
+  OSD_File theFile (thePath);
   theFile.Build(OSD_WriteOnly,OSD_Protection());
-  TCollection_AsciiString buf = TCollection_AsciiString ("solid\n");
+  TCollection_AsciiString buf ("solid\n");
   theFile.Write (buf,buf.Length());buf.Clear();
-  
+
   Standard_Real x1, y1, z1;
   Standard_Real x2, y2, z2;
   Standard_Real x3, y3, z3;
-  
-  //pgo  Standard_Real x,y,z;
-  
-  char sval[16];
-  
-  StlMesh_MeshExplorer aMexp (aMesh);
-  
-  for (Standard_Integer nbd=1;nbd<=aMesh->NbDomains();nbd++) {
-    for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle (); aMexp.NextTriangle ()) {
+  char sval[512];
+
+  // create progress sentry for domains
+  Standard_Integer aNbDomains = theMesh->NbDomains();
+  Message_ProgressSentry aDPS (theProgInd, "Mesh domains", 0, aNbDomains, 1);
+  StlMesh_MeshExplorer aMexp (theMesh);
+  for (Standard_Integer nbd = 1; nbd <= aNbDomains && aDPS.More(); nbd++, aDPS.Next())
+  {
+    // create progress sentry for triangles in domain
+    Message_ProgressSentry aTPS (theProgInd, "Triangles", 0,
+        theMesh->NbTriangles (nbd), IND_THRESHOLD);
+    Standard_Integer aTriangleInd = 0;
+    for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle(); aMexp.NextTriangle())
+    {
       aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
-      
+
 //      Standard_Real x, y, z;
 //      aMexp.TriangleOrientation (x,y,z);
-      
+
       gp_XYZ Vect12 ((x2-x1), (y2-y1), (z2-z1));
       gp_XYZ Vect23 ((x3-x2), (y3-y2), (z3-z2));
-       gp_XYZ Vnorm = Vect12 ^ Vect23;
+      gp_XYZ Vnorm = Vect12 ^ Vect23;
       Standard_Real Vmodul = Vnorm.Modulus ();
-      if (Vmodul > gp::Resolution()){
-       Vnorm.Divide (Vmodul);
+      if (Vmodul > gp::Resolution())
+      {
+        Vnorm.Divide (Vmodul);
       }
-      else {
-       // si Vnorm est quasi-nul, on le charge a 0 explicitement
-       Vnorm.SetCoord (0., 0., 0.);
+      else
+      {
+        // si Vnorm est quasi-nul, on le charge a 0 explicitement
+        Vnorm.SetCoord (0., 0., 0.);
       }
-      buf += " facet normal "; 
-      sprintf (sval,"% 12e",Vnorm.X());
-      buf += sval;
-      buf += " "; 
-      sprintf (sval,"% 12e",Vnorm.Y());
-      buf += sval;
-      buf += " "; 
-      sprintf (sval,"% 12e",Vnorm.Z());
-      buf += sval;
-      buf += '\n';
-      theFile.Write (buf,buf.Length());buf.Clear();
-      buf += "   outer loop\n"; 
-      theFile.Write (buf,buf.Length());buf.Clear();
-      
-      buf += "     vertex "; 
-      sprintf (sval,"% 12e",x1);
-      buf += sval;
-      buf += " "; 
-      sprintf (sval,"% 12e",y1);
+      Sprintf (sval,
+          " facet normal % 12e % 12e % 12e\n"
+          "   outer loop\n"
+          "     vertex % 12e % 12e % 12e\n"
+          "     vertex % 12e % 12e % 12e\n"
+          "     vertex % 12e % 12e % 12e\n"
+          "   endloop\n"
+          " endfacet\n",
+          Vnorm.X(), Vnorm.Y(), Vnorm.Z(),
+          x1, y1, z1,
+          x2, y2, z2,
+          x3, y3, z3);
       buf += sval;
-      buf += " "; 
-      sprintf (sval,"% 12e",z1);
-      buf += sval;
-      buf += '\n';
-      theFile.Write (buf,buf.Length());buf.Clear();
-      
-      buf += "     vertex "; 
-      sprintf (sval,"% 12e",x2);
-      buf += sval;
-      buf += " "; 
-      sprintf (sval,"% 12e",y2);
-      buf += sval;
-      buf += " "; 
-      sprintf (sval,"% 12e",z2);
-      buf += sval;
-      buf += '\n';
-      theFile.Write (buf,buf.Length());buf.Clear();
-      
-      buf += "     vertex "; 
-      sprintf (sval,"% 12e",x3);
-      buf += sval;
-      buf += " "; 
-      sprintf (sval,"% 12e",y3);
-      buf += sval;
-      buf += " "; 
-      sprintf (sval,"% 12e",z3);
-      buf += sval;
-      buf += '\n';
-      theFile.Write (buf,buf.Length());buf.Clear();
-      buf += "   endloop\n"; 
-      theFile.Write (buf,buf.Length());buf.Clear();
-      buf += " endfacet\n"; 
-      theFile.Write (buf,buf.Length());buf.Clear();
+      theFile.Write (buf, buf.Length()); buf.Clear();
+
+      // update progress only per 1k triangles
+      if (++aTriangleInd % IND_THRESHOLD == 0)
+      {
+        if (!aTPS.More())
+            break;
+        aTPS.Next();
+      }
     }
   }
-  
+
   buf += "endsolid\n";
-  theFile.Write (buf,buf.Length());buf.Clear();
-  
-  theFile.Close ();
-  return Standard_True;
+  theFile.Write (buf, buf.Length()); buf.Clear();
+  theFile.Close();
+  Standard_Boolean isInterrupted = !aDPS.More();
+  return !isInterrupted;
 }
 //=======================================================================
 //function : ReadFile
-//Design   : 
-//Warning  : 
+//Design   :
+//Warning  :
 //=======================================================================
 
-Handle_StlMesh_Mesh RWStl::ReadFile(const OSD_Path& aPath)
+Handle(StlMesh_Mesh) RWStl::ReadFile (const OSD_Path& thePath,
+                                     const Handle(Message_ProgressIndicator)& theProgInd)
 {
-  OSD_File file = OSD_File (aPath);
+  OSD_File file (thePath);
   file.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
   Standard_Boolean IsAscii;
   unsigned char str[128];
   Standard_Integer lread,i;
   Standard_Address ach;
   ach = (Standard_Address)str;
-  
+
   // we skip the header which is in Ascii for both modes
   file.Read(ach,HEADER_SIZE,lread);
 
@@ -302,27 +339,24 @@ Handle_StlMesh_Mesh RWStl::ReadFile(const OSD_Path& aPath)
       IsAscii = Standard_False;
     }
   }
-
-  printf("%s\n",(IsAscii?"ascii":"binary"));
-  
+#ifdef OCCT_DEBUG
+  cout << (IsAscii ? "ascii\n" : "binary\n");
+#endif
   file.Close();
-  
-  if (IsAscii) {
-    return RWStl::ReadAscii (aPath);
-  } else {
-    return RWStl::ReadBinary (aPath);
-  }
+
+  return IsAscii ? RWStl::ReadAscii  (thePath, theProgInd)
+                 : RWStl::ReadBinary (thePath, theProgInd);
 }
 
 //=======================================================================
 //function : ReadBinary
-//Design   : 
-//Warning  : 
+//Design   :
+//Warning  :
 //=======================================================================
 
-Handle_StlMesh_Mesh RWStl::ReadBinary(const OSD_Path& aPath)
+Handle(StlMesh_Mesh) RWStl::ReadBinary (const OSD_Path& thePath,
+                                       const Handle(Message_ProgressIndicator)& /*theProgInd*/)
 {
-  Standard_Integer NBFACET;
   Standard_Integer ifacet;
   Standard_Real fx,fy,fz,fx1,fy1,fz1,fx2,fy2,fz2,fx3,fy3,fz3;
   Standard_Integer i1,i2,i3,lread;
@@ -330,24 +364,44 @@ Handle_StlMesh_Mesh RWStl::ReadBinary(const OSD_Path& aPath)
   Standard_Address adr;
   adr = (Standard_Address)buftest;
 
-  // Open the file 
-  OSD_File theFile = OSD_File(aPath);
+  // Open the file
+  OSD_File theFile (thePath);
   theFile.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
 
   // the size of the file (minus the header size)
   // must be a multiple of SIZEOF_STL_FACET
 
   // compute file size
-  Standard_Integer filesize = theFile.Size();
+  Standard_Size filesize = theFile.Size();
 
-  if ( (filesize - HEADER_SIZE) % SIZEOF_STL_FACET !=0 
-       || (filesize < STL_MIN_FILE_SIZE)) {
+  // don't trust the number of triangles which is coded in the file sometimes it is wrong
+  Standard_Integer NBFACET = (Standard_Integer)((filesize - HEADER_SIZE) / SIZEOF_STL_FACET);
+  if (NBFACET < 1)
+  {
     Standard_NoMoreObject::Raise("RWStl::ReadBinary (wrong file size)");
   }
 
-  // don't trust the number of triangles which is coded in the file
-  // sometimes it is wrong, and with this technique we don't need to swap endians for integer
-  NBFACET = ((filesize - HEADER_SIZE) / SIZEOF_STL_FACET);
+  theFile.Seek (80, OSD_FromBeginning);
+  theFile.Read (adr, 4, lread);
+  Standard_Integer aNbTrisInHeader = (((char*           )buftest)[3] << 24) | (((Standard_Byte* )buftest)[2] << 16)
+                                    | (((Standard_Byte* )buftest)[1] << 8 ) | (((Standard_Byte* )buftest)[0] << 0 );
+  if (NBFACET < aNbTrisInHeader)
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString ("RWStl - Binary STL file defines more triangles (") + aNbTrisInHeader
+                                     + ") that can be read (" + NBFACET + ") - probably corrupted file",
+                                       Message_Warning);
+  }
+  else if (NBFACET > aNbTrisInHeader)
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString ("RWStl - Binary STL file defines less triangles (") + aNbTrisInHeader
+                                     + ") that can be read (" + NBFACET + ") - probably corrupted file",
+                                       Message_Warning);
+  }
+  else if ((filesize - HEADER_SIZE) % SIZEOF_STL_FACET != 0)
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString ("RWStl - Binary STL file has unidentified tail"),
+                                       Message_Warning);
+  }
 
   // skip the header
   theFile.Seek(HEADER_SIZE,OSD_FromBeginning);
@@ -356,6 +410,10 @@ Handle_StlMesh_Mesh RWStl::ReadBinary(const OSD_Path& aPath)
   Handle(StlMesh_Mesh) ReadMesh = new StlMesh_Mesh ();
   ReadMesh->AddDomain ();
 
+  // Filter unique vertices to share the nodes of the mesh.
+  BRepBuilderAPI_CellFilter uniqueVertices(Precision::Confusion());
+  BRepBuilderAPI_VertexInspector inspector(Precision::Confusion());
+  
   for (ifacet=1; ifacet<=NBFACET; ++ifacet) {
     // read normal coordinates
     fx = ReadFloat2Double(theFile);
@@ -377,9 +435,12 @@ Handle_StlMesh_Mesh RWStl::ReadBinary(const OSD_Path& aPath)
     fy3 = ReadFloat2Double(theFile);
     fz3 = ReadFloat2Double(theFile);
 
-    i1 = ReadMesh->AddOnlyNewVertex (fx1,fy1,fz1);
-    i2 = ReadMesh->AddOnlyNewVertex (fx2,fy2,fz2);
-    i3 = ReadMesh->AddOnlyNewVertex (fx3,fy3,fz3);
+    // Add vertices.
+    i1 = AddVertex(ReadMesh, uniqueVertices, inspector, gp_XYZ(fx1, fy1, fz1));
+    i2 = AddVertex(ReadMesh, uniqueVertices, inspector, gp_XYZ(fx2, fy2, fz2));
+    i3 = AddVertex(ReadMesh, uniqueVertices, inspector, gp_XYZ(fx3, fy3, fz3));
+
+    // Add triangle.
     ReadMesh->AddTriangle (i1,i2,i3,fx,fy,fz);
 
     // skip extra bytes
@@ -388,38 +449,35 @@ Handle_StlMesh_Mesh RWStl::ReadBinary(const OSD_Path& aPath)
 
   theFile.Close ();
   return ReadMesh;
-  
 }
+
 //=======================================================================
 //function : ReadAscii
-//Design   : 
-//Warning  : 
+//Design   :
+//Warning  :
 //=======================================================================
 
-Handle_StlMesh_Mesh RWStl::ReadAscii(const OSD_Path& aPath)
+Handle(StlMesh_Mesh) RWStl::ReadAscii (const OSD_Path& thePath,
+                                      const Handle(Message_ProgressIndicator)& theProgInd)
 {
   TCollection_AsciiString filename;
   long ipos;
   Standard_Integer nbLines = 0;
   Standard_Integer nbTris = 0;
   Standard_Integer iTri;
-  Standard_ShortReal x[4],y[4],z[4];
   Standard_Integer i1,i2,i3;
   Handle(StlMesh_Mesh) ReadMesh;
 
-  aPath.SystemName( filename);
+  thePath.SystemName (filename);
 
-  // Open the file 
-  FILE* file = fopen(filename.ToCString(),"r");
+  // Open the file
+  FILE* file = OSD_OpenFile(filename.ToCString(),"r");
 
   fseek(file,0L,SEEK_END);
 
   long filesize = ftell(file);
 
-  fclose(file);
-  file = fopen(filename.ToCString(),"r");
-
-
+  rewind(file);
 
   // count the number of lines
   for (ipos = 0; ipos < filesize; ++ipos) {
@@ -431,47 +489,68 @@ Handle_StlMesh_Mesh RWStl::ReadAscii(const OSD_Path& aPath)
   nbTris = (nbLines / ASCII_LINES_PER_FACET);
 
   // go back to the beginning of the file
-//  fclose(file);
-//  file = fopen(filename.ToCString(),"r");
   rewind(file);
 
   // skip header
   while (getc(file) != '\n');
-
-  cout<< "start mesh\n";
-  ReadMesh = new StlMesh_Mesh(); 
+#ifdef OCCT_DEBUG
+  cout << "start mesh\n";
+#endif
+  ReadMesh = new StlMesh_Mesh();
   ReadMesh->AddDomain();
 
+  // Filter unique vertices to share the nodes of the mesh.
+  BRepBuilderAPI_CellFilter uniqueVertices(Precision::Confusion());
+  BRepBuilderAPI_VertexInspector inspector(Precision::Confusion());
+  
   // main reading
-  for (iTri = 0; iTri < nbTris; ++iTri) {
+  Message_ProgressSentry aPS (theProgInd, "Triangles", 0, (nbTris - 1) * 1.0 / IND_THRESHOLD, 1);
+  for (iTri = 0; iTri < nbTris && aPS.More();)
+  {
+    char x[256]="", y[256]="", z[256]="";
+
     // reading the facet normal
-    fscanf(file,"%*s %*s %f %f %f\n",&x[0],&y[0],&z[0]);
+    if (3 != fscanf(file,"%*s %*s %80s %80s %80s\n", x, y, z))
+      break; // error should be properly reported
+    gp_XYZ aN (Atof(x), Atof(y), Atof(z));
 
     // skip the keywords "outer loop"
-    fscanf(file,"%*s %*s");
+    if (fscanf(file,"%*s %*s") < 0)
+      break;
 
     // reading vertex
-    fscanf(file,"%*s %f %f %f\n",&x[1],&y[1],&z[1]);
-    fscanf(file,"%*s %f %f %f\n",&x[2],&y[2],&z[2]);
-    fscanf(file,"%*s %f %f %f\n",&x[3],&y[3],&z[3]);
-
-    // here the facet must be built and put in the mesh datastructure            
-
-    i1 = ReadMesh->AddOnlyNewVertex ((Standard_Real)x[1],(Standard_Real)y[1],(Standard_Real)z[1]);
-    i2 = ReadMesh->AddOnlyNewVertex ((Standard_Real)x[2],(Standard_Real)y[2],(Standard_Real)z[2]);
-    i3 = ReadMesh->AddOnlyNewVertex ((Standard_Real)x[3],(Standard_Real)y[3],(Standard_Real)z[3]);
-    ReadMesh->AddTriangle (i1,i2,i3,(Standard_Real)x[0],(Standard_Real)y[0],(Standard_Real)z[0]);
+    if (3 != fscanf(file,"%*s %80s %80s %80s\n", x, y, z))
+      break; // error should be properly reported
+    gp_XYZ aV1 (Atof(x), Atof(y), Atof(z));
+    if (3 != fscanf(file,"%*s %80s %80s %80s\n", x, y, z))
+      break; // error should be properly reported
+    gp_XYZ aV2 (Atof(x), Atof(y), Atof(z));
+    if (3 != fscanf(file,"%*s %80s %80s %80s\n", x, y, z))
+      break; // error should be properly reported
+    gp_XYZ aV3 (Atof(x), Atof(y), Atof(z));
+
+    // here the facet must be built and put in the mesh datastructure
+
+    i1 = AddVertex(ReadMesh, uniqueVertices, inspector, aV1);
+    i2 = AddVertex(ReadMesh, uniqueVertices, inspector, aV2);
+    i3 = AddVertex(ReadMesh, uniqueVertices, inspector, aV3);
+    ReadMesh->AddTriangle (i1, i2, i3, aN.X(), aN.Y(), aN.Z());
 
     // skip the keywords "endloop"
-    fscanf(file,"%*s");
+    if (fscanf(file,"%*s") < 0)
+      break;
 
     // skip the keywords "endfacet"
-    fscanf(file,"%*s");
+    if (fscanf(file,"%*s") < 0)
+      break;
 
+    // update progress only per 1k triangles
+    if (++iTri % IND_THRESHOLD == 0)
+      aPS.Next();
   }
-
-  cout<< "end mesh\n"<<endl;
+#ifdef OCCT_DEBUG
+  cout << "end mesh\n";
+#endif
   fclose(file);
   return ReadMesh;
-  
 }