LCOV - code coverage report
Current view: top level - ugbase/lib_grid/file_io - stl_reader.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 110 0
Test Date: 2025-09-21 23:31:46 Functions: 0.0 % 5 0

            Line data    Source code
       1              : /*
       2              :  Copyright (c) 2018, Sebastian Reiter (s.b.reiter@gmail.com)
       3              :  All rights reserved.
       4              :  
       5              :  Redistribution and use in source and binary forms, with or without
       6              :  modification, are permitted provided that the following conditions are met:
       7              :      * Redistributions of source code must retain the above copyright
       8              :        notice, this list of conditions and the following disclaimer.
       9              :      * Redistributions in binary form must reproduce the above copyright
      10              :        notice, this list of conditions and the following disclaimer in the
      11              :        documentation and/or other materials provided with the distribution.
      12              :  
      13              :  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
      14              :  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      15              :  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      16              :  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
      17              :  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      18              :  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      19              :  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
      20              :  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      21              :  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      22              :  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      23              : */
      24              : 
      25              : 
      26              : /** \file
      27              :  * \brief       Provides functions to read **stl files** into user provided arrays
      28              :  *
      29              :  * The central function of this file is `ReadStlFile(...)`. It automatically recognizes
      30              :  * whether an *ASCII* or a *Binary* file is to be read. It identifies matching corner
      31              :  * coordinates of triangles with each other, so that the resulting coordinate
      32              :  * array does not contain the same coordinate-triple multiple times.
      33              :  *
      34              :  * The function operates on template container types. Those containers should
      35              :  * have similar interfaces as `std::vector` and operate on `float` or `double` types
      36              :  * (`TNumberContainer`) or on `int` or `size_t` types (`TIndexContainer`).
      37              :  *
      38              :  *
      39              :  * A conveniance class `StlMesh` is also provided, which makes accessing triangle
      40              :  * corners and corresponding corner coordinates much more easy. It still provides
      41              :  * raw access to the underlying data arrays.
      42              :  *
      43              :  *
      44              :  * ### Usage example 1 (using `StlMesh`):
      45              :  *
      46              :  * \code
      47              :  *      try {
      48              :  *              stl_reader::StlMesh <float, unsigned int> mesh ("geometry.stl");
      49              :  *
      50              :  *              for(size_t itri = 0; itri < mesh.num_tris(); ++itri) {
      51              :  *                      std::cout << "coordinates of triangle " << itri << ": ";
      52              :  *                      for(size_t icorner = 0; icorner < 3; ++icorner) {
      53              :  *                              float* c = mesh.vrt_coords (mesh.tri_corner_ind (itri, icorner));
      54              :  *                              std::cout << "(" << c[0] << ", " << c[1] << ", " << c[2] << ") ";
      55              :  *                      }
      56              :  *                      std::cout << std::endl;
      57              :  *              
      58              :  *                      float* n = mesh.tri_normal (itri);
      59              :  *                      std::cout       << "normal of triangle " << itri << ": "
      60              :  *                                              << "(" << n[0] << ", " << n[1] << ", " << n[2] << ")\n";
      61              :  *              }
      62              :  *      }
      63              :  *      catch (std::exception& e) {
      64              :  *              std::cout << e.what() << std::endl;
      65              :  *      }
      66              :  * \endcode
      67              :  *
      68              :  *
      69              :  * ### Usage example 2 (using `StlMesh` and *solids*)
      70              :  *
      71              :  * \code
      72              :  *      try {
      73              :  *              stl_reader::StlMesh <float, unsigned int> mesh ("geometry.stl");
      74              :  *
      75              :  *              for(size_t isolid = 0; isolid < mesh.num_solids(); ++isolid) {
      76              :  *                      std::cout << "solid " << isolid << std::endl;
      77              :  *
      78              :  *                      for(size_t itri = mesh.solid_tris_begin(isolid);
      79              :  *                          itri < mesh.solid_tris_end(isolid); ++itri)
      80              :  *                      {
      81              :  *                              const float* n = mesh.tri_normal (itri);
      82              :  *                              std::cout       << "normal of triangle " << itri << ": "
      83              :  *                                                      << "(" << n[0] << ", " << n[1] << ", " << n[2] << ")\n";
      84              :  *                      }
      85              :  *              }
      86              :  *      }
      87              :  *      catch (std::exception& e) {
      88              :  *              std::cout << e.what() << std::endl;
      89              :  *      }
      90              :  * \endcode
      91              :  *
      92              :  *
      93              :  * ### Usage example 3 (using raw data arrays)
      94              :  *
      95              :  * \code
      96              :  *      std::vector<float> coords, normals;
      97              :  *      std::vector<unsigned int> tris, solids;
      98              :  *
      99              :  *      try {
     100              :  *              stl_reader::ReadStlFile ("geometry.stl", coords, normals, tris, solids);
     101              :  *              const size_t numTris = tris.size() / 3;
     102              :  *              for(size_t itri = 0; itri < numTris; ++itri) {
     103              :  *                      std::cout << "coordinates of triangle " << itri << ": ";
     104              :  *                      for(size_t icorner = 0; icorner < 3; ++icorner) {
     105              :  *                              float* c = &coords[3 * tris [3 * itri + icorner]];
     106              :  *                              std::cout << "(" << c[0] << ", " << c[1] << ", " << c[2] << ") ";
     107              :  *                      }
     108              :  *                      std::cout << std::endl;
     109              :  *              
     110              :  *                      float* n = &normals [3 * itri];
     111              :  *                      std::cout       << "normal of triangle " << itri << ": "
     112              :  *                                              << "(" << n[0] << ", " << n[1] << ", " << n[2] << ")\n";
     113              :  *              }
     114              :  *      }
     115              :  *      catch (std::exception& e) {
     116              :  *              std::cout << e.what() << std::endl;
     117              :  *      }
     118              :  * \endcode
     119              :  *
     120              :  * If you do not want to use exceptions, you may define the macro
     121              :  * STL_READER_NO_EXCEPTIONS before including 'stl_reader.h'. In that case,
     122              :  * functions will return `false` if an error occurred.
     123              :  */
     124              : 
     125              : #ifndef __H__STL_READER
     126              : #define __H__STL_READER
     127              : 
     128              : #include <algorithm>
     129              : #include <exception>
     130              : #include <fstream>
     131              : #include <sstream>
     132              : #include <vector>
     133              : 
     134              : #ifdef STL_READER_NO_EXCEPTIONS
     135              :         #define STL_READER_THROW(msg) return false;
     136              :         #define STL_READER_COND_THROW(cond, msg) if(cond) return false;
     137              : #else
     138              :         ///     Throws an std::runtime_error with the given message.
     139              :         #define STL_READER_THROW(msg)   {std::stringstream ss; ss << msg; throw(std::runtime_error(ss.str()));}
     140              : 
     141              :         /// Throws an std::runtime_error with the given message, if the given condition evaluates to true.
     142              :         #define STL_READER_COND_THROW(cond, msg)        if(cond){std::stringstream ss; ss << msg; throw(std::runtime_error(ss.str()));}
     143              : #endif
     144              : 
     145              : 
     146              : namespace stl_reader {
     147              : 
     148              : /// Reads an ASCII or binary stl file into several arrays
     149              : /** Reads a stl file and writes its coordinates, normals and triangle-corner-indices
     150              :  * to the provided containers. It also fills a container solidRangesOut, which
     151              :  * provides the triangle ranges for individual solids.
     152              :  *
     153              :  * Double vertex entries are removed on the fly, so that triangle corners with
     154              :  * equal coordinates are represented by a single coordinate entry in coordsOut.
     155              :  * 
     156              :  *
     157              :  * \param filename      [in] The name of the file which shall be read
     158              :  *
     159              :  * \param coordsOut     [out] Coordinates are written to this container. On termination,
     160              :  *                                      it has size numVertices * 3. Each triple of entries forms a
     161              :  *                                      3d coordinate. The type TNumberContainer should have the same
     162              :  *                                      interface as std::vector<float>.
     163              :  *
     164              :  * \param normalsOut    [out] Face normals are written to this container. On termination,
     165              :  *                                              it has size numFaces * 3. Each triple of entries forms a
     166              :  *                                              3d normal. The type TNumberContainer should have the same
     167              :  *                                              interface as std::vector<float>.
     168              :  *
     169              :  * \param trisOut       [out] Triangle corner indices are written to this container.
     170              :  *                                      On termination, it has size numFaces * 3. Each triple of
     171              :  *                                      entries defines a triangle. The type TIndexContainer should
     172              :  *                                      have the same interface as std::vector<size_t>.
     173              :  *                                      Multiply corner indices from trisOut by 3 to obtain the index
     174              :  *                                      of the first coordinate of that corner in coordsOut.
     175              :  *
     176              :  * \param solidRangesOut        [out] On termination, it holds the ranges of triangle indices
     177              :  *                                                      for each solid. It has the size numSolids + 1. Each entry
     178              :  *                                                      can be interpreted as a end/begin triangle index for the
     179              :  *                                                      previous/next solid. E.g., if there are 3 solids, the
     180              :  *                                                      returned array would look like this:
     181              :  *                                                      \code
     182              :  *                                                        {sol1Begin, sol1End/sol2Begin, sol2End/sol3Begin, sol3End}.
     183              :  *                                                      \endcode
     184              :  *                                                      The type TIndexContainer should have the same interface
     185              :  *                                                      as std::vector<size_t>.
     186              :  *
     187              :  * \returns             true if the file was successfully read into the provided container.
     188              :  */
     189              : template <class TNumberContainer, class TIndexContainer>
     190              : bool ReadStlFile(const char* filename,
     191              :                 TNumberContainer& coordsOut,
     192              :                 TNumberContainer& normalsOut,
     193              :                 TIndexContainer& trisOut,
     194              :                                 TIndexContainer& solidRangesOut);
     195              : 
     196              : 
     197              : /// Reads an ASCII stl file into several arrays
     198              : /** \copydetails ReadStlFile
     199              :  * \sa ReadStlFile, ReadStlFile_ASCII
     200              :  */
     201              : template <class TNumberContainer, class TIndexContainer>
     202              : bool ReadStlFile_ASCII(const char* filename,
     203              :                        TNumberContainer& coordsOut,
     204              :                        TNumberContainer& normalsOut,
     205              :                        TIndexContainer& trisOut,
     206              :                                            TIndexContainer& solidRangesOut);
     207              : 
     208              : /// Reads a binary stl file into several arrays
     209              : /** \copydetails ReadStlFile
     210              :  * \todo        support systems with big endianess
     211              :  * \sa          ReadStlFile, ReadStlFile_BINARY
     212              :  */
     213              : template <class TNumberContainer, class TIndexContainer>
     214              : bool ReadStlFile_BINARY(const char* filename,
     215              :                         TNumberContainer& coordsOut,
     216              :                         TNumberContainer& normalsOut,
     217              :                         TIndexContainer& trisOut,
     218              :                                             TIndexContainer& solidRangesOut);
     219              : 
     220              : /// Determines whether a stl file has ASCII format
     221              : /** The underlying mechanism is simply checks whether the provided file starts
     222              :  * with the keyword solid. This should work for many stl files, but may
     223              :  * fail, of course.
     224              :  */
     225              : inline bool StlFileHasASCIIFormat(const char* filename);
     226              : 
     227              : 
     228              : ///     convenience mesh class which makes accessing the stl data more easy
     229              : template <class TNumber = float, class TIndex = unsigned int>
     230              : class StlMesh {
     231              : public:
     232              :         /// initializes an empty mesh
     233              :         StlMesh ()
     234              :         {
     235              :                 solids.resize (2, 0);
     236              :         }
     237              : 
     238              :         /// initializes the mesh from the stl-file specified through filename
     239              :         StlMesh (const char* filename)
     240              :         {
     241              :                 read_file (filename);
     242              :         }
     243              : 
     244              :         /// fills the mesh with the contents of the specified stl-file
     245              :         bool read_file (const char* filename)
     246              :         {
     247              :                 bool res = false;
     248              : 
     249              :                 #ifndef STL_READER_NO_EXCEPTIONS
     250              :                 try {
     251              :                 #endif
     252              : 
     253              :                         res = ReadStlFile (filename, coords, normals, tris, solids);
     254              : 
     255              :                 #ifndef STL_READER_NO_EXCEPTIONS
     256              :                 } catch (std::exception& e) {
     257              :                 #else
     258              :                 if (!res) {
     259              :                 #endif
     260              : 
     261              :                         coords.clear ();
     262              :                         normals.clear ();
     263              :                         tris.clear ();
     264              :                         solids.clear ();
     265              :                         STL_READER_THROW (e.what());
     266              :                 }
     267              : 
     268              :                 return res;
     269              :         }
     270              : 
     271              :         ///     returns the number of vertices in the mesh
     272              :         size_t num_vrts () const
     273              :         {
     274              :                 return coords.size() / 3;
     275              :         }
     276              : 
     277              :         /// returns an array of 3 floating point values, one for each coordinate of the vertex
     278              :         const TNumber* vrt_coords (const size_t vi) const
     279              :         {
     280              :                 return &coords[vi * 3];
     281              :         }
     282              : 
     283              :         ///     returns the number of triangles in the mesh
     284              :         size_t num_tris () const
     285              :         {
     286              :                 return tris.size() / 3;
     287              :         }
     288              : 
     289              :         ///     returns an array of 3 indices, one for each corner vertex of the triangle
     290              :         const TIndex* tri_corner_inds (const size_t ti) const
     291              :         {
     292              :                 return &tris [ti * 3];
     293              :         }
     294              : 
     295              :         /// returns the index of the corner with index `0<=ci<3` of triangle ti
     296              :         const TIndex tri_corner_ind (const size_t ti, const size_t ci) const
     297              :         {
     298              :                 return tris [ti * 3 + ci];
     299              :         }
     300              : 
     301              :         /** \brief      returns an array of 3 floating point values, one for each
     302              :          *                      coordinate of the specified corner of the specified tri.
     303              :          * \note        same result as calling on a `StlMesh mesh`:
     304              :          *                      \code
     305              :          *                              mesh.vrt_coords (mesh.tri_corner_ind (itri, icorner))
     306              :          *                      \endcode
     307              :          */
     308              :         const TNumber* tri_corner_coords (const size_t ti, const size_t ci) const
     309              :         {
     310              :                 return &coords[tri_corner_ind(ti, ci) * 3];
     311              :         }
     312              : 
     313              :         /// returns an array of 3 floating point values defining the normal of a tri
     314              :         const TNumber* tri_normal (const size_t ti) const
     315              :         {
     316              :                 return &normals [ti * 3];
     317              :         }
     318              : 
     319              :         /// returns the number of solids of the mesh
     320              :         /** solids can be seen as a partitioning of the triangles of a mesh.
     321              :          * By iterating consecutively from the index of the first triangle of a
     322              :          * solid `si` (using `solid_tris_begin(si)`) to the index of the last
     323              :          * triangle of a solid (using `solid_tris_end(...)-1`), one visits all
     324              :          * triangles of the solid `si`.*/
     325              :         size_t num_solids () const
     326              :         {
     327              :                 if(solids.empty ())
     328              :                         return 0;
     329              :                 return solids.size () - 1;
     330              :         }
     331              : 
     332              :         /// returns the index of the first triangle in the given solid
     333              :         TIndex solid_tris_begin (const size_t si) const
     334              :         {
     335              :                 return solids [si];
     336              :         }
     337              : 
     338              :         /// returns the index of the triangle behind the last triangle in the given solid
     339              :         TIndex solid_tris_end (const size_t si) const
     340              :         {
     341              :                 return solids [si + 1];
     342              :         }
     343              : 
     344              :         /// returns a pointer to the coordinate array, containing `num_vrts()*3` entries.
     345              :         /** Storage layout: `x0,y0,z0,x1,y1,z1,...`
     346              :          * \returns     pointer to a contiguous array of numbers, or `NULL` if no coords exist.*/
     347              :         const TNumber* raw_coords () const
     348              :         {
     349              :                 if(coords.empty())
     350              :                         return NULL;
     351              :                 return &coords[0];
     352              :         }
     353              : 
     354              :         /// returns a pointer to the normal array, containing `num_tris()*3` entries.
     355              :         /** Storage layout: `nx0,ny0,nz0,nx1,ny1,nz1,...`
     356              :          * \returns     pointer to a contiguous array of numbers, or `NULL` if no normals exist.*/
     357              :         const TNumber* raw_normals () const
     358              :         {
     359              :                 if(normals.empty())
     360              :                         return NULL;
     361              :                 return &normals[0];
     362              :         }
     363              : 
     364              :         /// returns a pointer to the triangle array, containing `num_tris()*3` entries.
     365              :         /** Storage layout: `t0c0,t0c1,t0c2,t1c0,t1c1,t1c2,...`
     366              :          * \returns     pointer to a contiguous array of indices, or `NULL` if no tris exist.*/
     367              :         const TIndex* raw_tris () const
     368              :         {
     369              :                 if(tris.empty())
     370              :                         return NULL;
     371              :                 return &tris[0];
     372              :         }
     373              : 
     374              :         /// returns a pointer to the solids array, containing `num_solids()+1` entries.
     375              :         /** Storage layout: `s0begin, s0end/s1begin, s1end/s2begin, ..., sNend`
     376              :          * \returns     pointer to a contiguous array of indices, or `NULL` if no solids exist.*/
     377              :         const TIndex* raw_solids () const
     378              :         {
     379              :                 if(solids.empty())
     380              :                         return NULL;
     381              :                 return &solids[0];
     382              :         }
     383              : 
     384              : private:
     385              :         std::vector<TNumber>      coords;
     386              :         std::vector<TNumber>      normals;
     387              :         std::vector<TIndex>               tris;
     388              :         std::vector<TIndex>               solids;
     389              : };
     390              : 
     391              : 
     392              : ////////////////////////////////////////////////////////////////////////////////
     393              : //      IMPLEMENTATION
     394              : ////////////////////////////////////////////////////////////////////////////////
     395              : 
     396              : 
     397              : namespace stl_reader_impl {
     398              : 
     399              :         // a coordinate triple with an additional index. The index is required
     400              :         // for RemoveDoubles, so that triangles can be reindexed properly.
     401              :         template <typename number_t, typename index_t>
     402              :         struct CoordWithIndex {
     403              :                 number_t data[3];
     404              :                 index_t index;
     405              : 
     406              :                 bool operator == (const CoordWithIndex& c) const
     407              :                 {
     408              :                         return (c[0] == data[0]) && (c[1] == data[1]) && (c[2] == data[2]);
     409              :                 }
     410              : 
     411              :                 bool operator != (const CoordWithIndex& c) const
     412              :                 {
     413            0 :                         return (c[0] != data[0]) || (c[1] != data[1]) || (c[2] != data[2]);
     414              :                 }
     415              : 
     416              :                 bool operator < (const CoordWithIndex& c) const
     417              :                 {
     418            0 :                         return          (data[0] < c[0])
     419            0 :                                         ||      (data[0] == c[0] && data[1] < c[1])
     420            0 :                                         ||      (data[0] == c[0] && data[1] == c[1] && data[2] < c[2]);
     421              :                 }
     422              : 
     423              :                 inline number_t& operator [] (const size_t i)               {return data[i];}
     424            0 :                 inline number_t operator [] (const size_t i) const      {return data[i];}
     425              :         };
     426              : 
     427              :         // sorts the array coordsWithIndexInOut and copies unique indices to coordsOut.
     428              :         // Triangle-corners are re-indexed on the fly and degenerated triangles are removed.
     429              :         template <class TNumberContainer, class TIndexContainer>
     430            0 :         void RemoveDoubles (TNumberContainer& uniqueCoordsOut,
     431              :                             TIndexContainer& trisInOut,
     432              :                             std::vector <CoordWithIndex<
     433              :                                 typename TNumberContainer::value_type,
     434              :                                 typename TIndexContainer::value_type> >
     435              :                                         &coordsWithIndexInOut)
     436              :         {
     437              :                 using namespace std;
     438              : 
     439              :                 typedef typename TNumberContainer::value_type   number_t;
     440              :                 typedef typename TIndexContainer::value_type    index_t;
     441              : 
     442            0 :                 sort (coordsWithIndexInOut.begin(), coordsWithIndexInOut.end());
     443              :         
     444              :         //      first count unique indices
     445              :                 size_t numUnique = 1;
     446            0 :                 for(size_t i = 1; i < coordsWithIndexInOut.size(); ++i){
     447            0 :                         if(coordsWithIndexInOut[i] != coordsWithIndexInOut[i - 1])
     448            0 :                                 ++numUnique;
     449              :                 }
     450              : 
     451            0 :                 uniqueCoordsOut.resize (numUnique * 3);
     452            0 :                 vector<index_t> newIndex (coordsWithIndexInOut.size());
     453              : 
     454              :         //      copy unique coordinates to 'uniqueCoordsOut' and create an index-map
     455              :         //      'newIndex', which allows to re-index triangles later on.
     456              :                 size_t curInd = 0;
     457            0 :                 newIndex[0] = 0;
     458            0 :                 for(size_t i = 0; i < 3; ++i)
     459            0 :                         uniqueCoordsOut[i] = coordsWithIndexInOut[0][i];
     460              : 
     461            0 :                 for(size_t i = 1; i < coordsWithIndexInOut.size(); ++i){
     462            0 :                         const CoordWithIndex <number_t, index_t> c = coordsWithIndexInOut[i];
     463            0 :                         if(c != coordsWithIndexInOut[i - 1]){
     464            0 :                                 ++curInd;
     465            0 :                                 for(size_t j = 0; j < 3; ++j)
     466            0 :                                         uniqueCoordsOut[curInd * 3 + j] = coordsWithIndexInOut[i][j];
     467              :                         }
     468              : 
     469            0 :                         newIndex[c.index] = curInd;
     470              :                 }
     471              : 
     472              :         //      re-index triangles, so that they refer to 'uniqueCoordsOut'
     473              :         //      make sure to only add triangles which refer to three different indices
     474              :                 size_t numUniqueTriInds = 0;
     475            0 :                 for(size_t i = 0; i < trisInOut.size(); i+=3){
     476              :                         int ni[3];
     477            0 :                         for(int j = 0; j < 3; ++j)
     478            0 :                                 ni[j] = newIndex[trisInOut[i+j]];
     479              : 
     480            0 :                         if((ni[0] != ni[1]) && (ni[0] != ni[2]) && (ni[1] != ni[2])){
     481            0 :                                 for(int j = 0; j < 3; ++j)
     482            0 :                                         trisInOut[numUniqueTriInds + j] = ni[j];
     483            0 :                                 numUniqueTriInds += 3;
     484              :                         }
     485              :                 }
     486              : 
     487            0 :                 if(numUniqueTriInds < trisInOut.size())
     488            0 :                         trisInOut.resize (numUniqueTriInds);
     489            0 :         }
     490              : }// end of namespace stl_reader_impl
     491              : 
     492              : 
     493              : template <class TNumberContainer, class TIndexContainer>
     494            0 : bool ReadStlFile(const char* filename,
     495              :                 TNumberContainer& coordsOut,
     496              :                 TNumberContainer& normalsOut,
     497              :                 TIndexContainer& trisOut,
     498              :                                 TIndexContainer& solidRangesOut)
     499              : {
     500            0 :         if(StlFileHasASCIIFormat(filename))
     501            0 :                 return ReadStlFile_ASCII(filename, coordsOut, normalsOut, trisOut, solidRangesOut);
     502              :         else
     503            0 :                 return ReadStlFile_BINARY(filename, coordsOut, normalsOut, trisOut, solidRangesOut);
     504              : }
     505              : 
     506              : 
     507              : template <class TNumberContainer, class TIndexContainer>
     508            0 : bool ReadStlFile_ASCII(const char* filename,
     509              :                        TNumberContainer& coordsOut,
     510              :                        TNumberContainer& normalsOut,
     511              :                        TIndexContainer& trisOut,
     512              :                                            TIndexContainer& solidRangesOut)
     513              : {
     514              :         using namespace std;
     515              :         using namespace stl_reader_impl;
     516              : 
     517              :         typedef typename TNumberContainer::value_type   number_t;
     518              :         typedef typename TIndexContainer::value_type    index_t;
     519              : 
     520              :         coordsOut.clear();
     521              :         normalsOut.clear();
     522              :         trisOut.clear();
     523              :         solidRangesOut.clear();
     524              : 
     525            0 :         ifstream in(filename);
     526            0 :         STL_READER_COND_THROW(!in, "Couldn't open file " << filename);
     527              : 
     528              :         vector<CoordWithIndex <number_t, index_t> > coordsWithIndex;
     529              : 
     530              :         string buffer;
     531              :         vector<string> tokens;
     532              :         int lineCount = 1;
     533              :         int maxNumTokens = 0;
     534              :         size_t numFaceVrts = 0;
     535              : 
     536            0 :         while(!(in.eof() || in.fail()))
     537              :         {
     538              :         //      read the line and tokenize.
     539              :         //      In order to reuse memory in between lines, 'tokens' won't be cleared.
     540              :         //      Instead we count the number of tokens using 'tokenCount'.
     541            0 :                 getline(in, buffer);
     542              : 
     543            0 :                 istringstream line(buffer);
     544              :                 int tokenCount = 0;
     545            0 :                 while(!(line.eof() || line.fail())){
     546            0 :                         if(tokenCount >= maxNumTokens){
     547            0 :                                 maxNumTokens = tokenCount + 1;
     548            0 :                                 tokens.resize(maxNumTokens);
     549              :                         }
     550            0 :                         line >> tokens[tokenCount];
     551            0 :                         ++tokenCount;
     552              :                 }
     553              : 
     554            0 :                 if(tokenCount > 0)
     555              :                 {
     556              :                         string& tok = tokens[0];
     557            0 :                         if(tok.compare("vertex") == 0){
     558            0 :                                 if(tokenCount < 4){
     559            0 :                                         STL_READER_THROW("ERROR while reading from " << filename <<
     560              :                                                 ": vertex not specified correctly in line " << lineCount);
     561              :                                 }
     562              :                                 
     563              :                         //      read the position
     564              :                                 CoordWithIndex <number_t, index_t> c;
     565            0 :                                 for(size_t i = 0; i < 3; ++i)
     566            0 :                                         c[i] = atof(tokens[i+1].c_str());
     567            0 :                                 c.index = static_cast<index_t>(coordsWithIndex.size());
     568            0 :                                 coordsWithIndex.push_back(c);
     569            0 :                                 ++numFaceVrts;
     570              :                         }
     571            0 :                         else if(tok.compare("facet") == 0)
     572              :                         {
     573            0 :                                 STL_READER_COND_THROW(tokenCount < 5,
     574              :                                                 "ERROR while reading from " << filename <<
     575              :                                                 ": triangle not specified correctly in line " << lineCount);
     576              :                                 
     577            0 :                                 STL_READER_COND_THROW(tokens[1].compare("normal") != 0,
     578              :                                                 "ERROR while reading from " << filename <<
     579              :                                                 ": Missing normal specifier in line " << lineCount);
     580              :                                 
     581              :                         //      read the normal
     582            0 :                                 for(size_t i = 0; i < 3; ++i)
     583            0 :                                         normalsOut.push_back (atof(tokens[i+2].c_str()));
     584              : 
     585              :                                 numFaceVrts = 0;
     586              :                         }
     587            0 :                         else if(tok.compare("outer") == 0){
     588            0 :                                 STL_READER_COND_THROW ((tokenCount < 2) || (tokens[1].compare("loop") != 0),
     589              :                                     "ERROR while reading from " << filename <<
     590              :                                         ": expecting outer loop in line " << lineCount);
     591              :                         }
     592            0 :                         else if(tok.compare("endfacet") == 0){
     593            0 :                                 STL_READER_COND_THROW(numFaceVrts != 3,
     594              :                                         "ERROR while reading from " << filename <<
     595              :                                         ": bad number of vertices specified for face in line " << lineCount);
     596              : 
     597            0 :                                 trisOut.push_back(coordsWithIndex.size() - 3);
     598            0 :                                 trisOut.push_back(coordsWithIndex.size() - 2);
     599            0 :                                 trisOut.push_back(coordsWithIndex.size() - 1);
     600              :                         }
     601            0 :                         else if(tok.compare("solid") == 0){
     602            0 :                                 solidRangesOut.push_back(trisOut.size() / 3);
     603              :                         }
     604              :                 }
     605            0 :                 lineCount++;
     606              :         }
     607              : 
     608            0 :         solidRangesOut.push_back(trisOut.size() / 3);
     609              : 
     610            0 :         RemoveDoubles (coordsOut, trisOut, coordsWithIndex);
     611              : 
     612            0 :         return true;
     613            0 : }
     614              : 
     615              : 
     616              : template <class TNumberContainer, class TIndexContainer>
     617            0 : bool ReadStlFile_BINARY(const char* filename,
     618              :                         TNumberContainer& coordsOut,
     619              :                         TNumberContainer& normalsOut,
     620              :                         TIndexContainer& trisOut,
     621              :                                             TIndexContainer& solidRangesOut)
     622              : {
     623              :         using namespace std;
     624              :         using namespace stl_reader_impl;
     625              : 
     626              :         typedef typename TNumberContainer::value_type   number_t;
     627              :         typedef typename TIndexContainer::value_type    index_t;
     628              : 
     629              :         coordsOut.clear();
     630              :         normalsOut.clear();
     631              :         trisOut.clear();
     632              :         solidRangesOut.clear();
     633              : 
     634            0 :         ifstream in(filename, ios::binary);
     635            0 :         STL_READER_COND_THROW(!in, "Couldnt open file " << filename);
     636              : 
     637              :         char stl_header[80];
     638            0 :         in.read(stl_header, 80);
     639            0 :         STL_READER_COND_THROW(!in, "Error while parsing binary stl header in file " << filename);
     640              : 
     641            0 :         unsigned int numTris = 0;
     642            0 :         in.read((char*)&numTris, 4);
     643            0 :         STL_READER_COND_THROW(!in, "Couldnt determine number of triangles in binary stl file " << filename);
     644              : 
     645              :         vector<CoordWithIndex <number_t, index_t> > coordsWithIndex;
     646              : 
     647            0 :         for(unsigned int tri = 0; tri < numTris; ++tri){
     648              :                 float d[12];
     649            0 :                 in.read((char*)d, 12 * 4);
     650            0 :                 STL_READER_COND_THROW(!in, "Error while parsing trianlge in binary stl file " << filename);
     651              : 
     652            0 :                 for(int i = 0; i < 3; ++i)
     653            0 :                         normalsOut.push_back (d[i]);
     654              : 
     655            0 :                 for(size_t ivrt = 1; ivrt < 4; ++ivrt){
     656              :                         CoordWithIndex <number_t, index_t> c;
     657            0 :                         for(size_t i = 0; i < 3; ++i)
     658            0 :                                 c[i] = d[ivrt * 3 + i];
     659            0 :                         c.index = static_cast<index_t>(coordsWithIndex.size());
     660            0 :                         coordsWithIndex.push_back(c);
     661              :                 }
     662              : 
     663            0 :                 trisOut.push_back(coordsWithIndex.size() - 3);
     664            0 :                 trisOut.push_back(coordsWithIndex.size() - 2);
     665            0 :                 trisOut.push_back(coordsWithIndex.size() - 1);
     666              : 
     667              :                 char addData[2];
     668            0 :                 in.read(addData, 2);
     669            0 :                 STL_READER_COND_THROW(!in, "Error while parsing additional triangle data in binary stl file " << filename);
     670              :         }
     671              : 
     672            0 :         solidRangesOut.push_back(0);
     673            0 :         solidRangesOut.push_back(trisOut.size() / 3);
     674              : 
     675            0 :         RemoveDoubles (coordsOut, trisOut, coordsWithIndex);
     676              : 
     677            0 :         return true;
     678            0 : }
     679              : 
     680              : 
     681            0 : inline bool StlFileHasASCIIFormat(const char* filename)
     682              : {
     683              :         using namespace std;
     684            0 :         ifstream in(filename);
     685            0 :         STL_READER_COND_THROW(!in, "Couldnt open file " << filename);
     686              : 
     687              :         string firstWord;
     688            0 :         in >> firstWord;
     689              :         transform(firstWord.begin(), firstWord.end(), firstWord.begin(), ::tolower);
     690              : 
     691            0 :         return firstWord.compare("solid") == 0;
     692            0 : }
     693              : 
     694              : } // end of namespace stl_reader
     695              : 
     696              : #endif  //__H__STL_READER
        

Generated by: LCOV version 2.0-1