1 // Copyright (c) 2015 GeometryFactory 2 // 3 // This file is part of CGAL (www.cgal.org); 4 // 5 // $URL: https://github.com/CGAL/cgal/blob/v5.3/Stream_support/include/CGAL/IO/STL/STL_reader.h $ 6 // $Id: STL_reader.h fb6f703 2021-05-04T14:07:49+02:00 Sébastien Loriot 7 // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial 8 // 9 // Author(s) : Andreas Fabri, 10 // Mael Rouxel-Labbé 11 12 #ifndef CGAL_IO_STL_STL_READER_H 13 #define CGAL_IO_STL_STL_READER_H 14 15 #include <CGAL/IO/io.h> 16 #include <CGAL/IO/helpers.h> 17 18 #include <boost/cstdint.hpp> 19 #include <boost/range/value_type.hpp> 20 21 #include <cctype> 22 #include <iostream> 23 #include <map> 24 #include <string> 25 #include <vector> 26 27 namespace CGAL { 28 namespace IO { 29 namespace internal { 30 31 template <class PointRange, class TriangleRange, typename IndexMap> 32 bool read_ASCII_facet(std::istream& is, 33 PointRange& points, 34 TriangleRange& facets, 35 int& index, 36 IndexMap& index_map, 37 const bool verbose = false) 38 { 39 typedef typename boost::range_value<PointRange>::type Point; 40 typedef typename boost::range_value<TriangleRange>::type Triangle; 41 42 // Here, we have already read the word 'facet' and are looking to read till 'endfacet' 43 44 std::string s; 45 std::string vertex("vertex"), endfacet("endfacet"); 46 47 int count = 0; 48 double x,y,z; 49 Point p; 50 Triangle ijk; 51 CGAL::internal::resize(ijk, 3); 52 53 while(is >> s) 54 { 55 if(s == endfacet) 56 { 57 if(count != 3) 58 { 59 if(verbose) 60 std::cerr << "Error: only triangulated surfaces are supported" << std::endl; 61 62 return false; 63 } 64 65 facets.push_back(ijk); 66 return true; 67 } 68 else if(s == vertex) 69 { 70 if(count >= 3) 71 { 72 if(verbose) 73 std::cerr << "Error: only triangulated surfaces are supported" << std::endl; 74 75 return false; 76 } 77 78 if(!(is >> iformat(x) >> iformat(y) >> iformat(z))) 79 { 80 if(verbose) 81 std::cerr << "Error while reading point coordinates (premature end of file)" << std::endl; 82 83 return false; 84 } 85 else 86 { 87 fill_point(x, y, z, 1 /*w*/, p); 88 typename std::map<Point, int>::iterator iti = index_map.insert(std::make_pair(p, -1)).first; 89 90 if(iti->second == -1) 91 { 92 ijk[count] = index; 93 iti->second = index++; 94 points.push_back(p); 95 } 96 else 97 { 98 ijk[count] = iti->second; 99 } 100 } 101 102 ++count; 103 } 104 } 105 106 if(verbose) 107 std::cerr << "Error while reading facet (premature end of file)" << std::endl; 108 109 return false; 110 } 111 112 template <class PointRange, class TriangleRange> 113 bool parse_ASCII_STL(std::istream& is, 114 PointRange& points, 115 TriangleRange& facets, 116 const bool verbose = false) 117 { 118 typedef typename boost::range_value<PointRange>::type Point; 119 bool solid_found = false; 120 if(verbose) 121 std::cout << "Parsing ASCII file..." << std::endl; 122 123 if(!is.good()) 124 return false; 125 126 // Here, we have already read the word 'solid' 127 128 int index = 0; 129 std::map<Point, int> index_map; 130 131 std::string s, facet("facet"), endsolid("endsolid"), solid("solid"); 132 bool in_solid(false); 133 while(is >> s) 134 { 135 if(s == solid) 136 { 137 if(in_solid) 138 break; 139 140 in_solid = true; 141 } 142 if(s == facet) 143 { 144 if(!read_ASCII_facet(is, points, facets, index, index_map, verbose)) 145 return false; 146 } 147 else if(s == endsolid) 148 { 149 in_solid = false; 150 solid_found = true; 151 } 152 } 153 154 if(in_solid) 155 { 156 if(verbose) 157 std::cerr << "Error while parsing ASCII file" << std::endl; 158 159 return false; 160 } 161 162 return solid_found && !in_solid; 163 } 164 165 template <class PointRange, class TriangleRange> 166 bool parse_binary_STL(std::istream& is, 167 PointRange& points, 168 TriangleRange& facets, 169 const bool verbose = false) 170 { 171 typedef typename boost::range_value<PointRange>::type Point; 172 typedef typename boost::range_value<TriangleRange>::type Triangle; 173 174 if(verbose) 175 std::cout << "Parsing binary file..." << std::endl; 176 177 // Start from the beginning again to simplify things 178 is.clear(); 179 is.seekg(0, std::ios::beg); 180 181 if(!is.good()) 182 return false; 183 184 // Discard the first 80 chars (unused header) 185 int pos = 0; 186 char c; 187 188 if(verbose) 189 std::cout << "header: "; 190 191 while(pos < 80) 192 { 193 is.read(reinterpret_cast<char*>(&c), sizeof(c)); 194 if(!is.good()) 195 break; 196 197 if(verbose) 198 std::cout << c; 199 200 ++pos; 201 } 202 203 if(verbose) 204 std::cout << std::endl; 205 206 if(pos != 80) 207 return true; // empty file 208 209 int index = 0; 210 std::map<Point, int> index_map; 211 212 boost::uint32_t N32; 213 if(!(is.read(reinterpret_cast<char*>(&N32), sizeof(N32)))) 214 { 215 if(verbose) 216 std::cerr << "Error while reading number of facets" << std::endl; 217 218 return false; 219 } 220 221 unsigned int N = N32; 222 if(verbose) 223 std::cout << N << " facets to read" << std::endl; 224 225 for(unsigned int i=0; i<N; ++i) 226 { 227 float normal[3]; 228 if(!(is.read(reinterpret_cast<char*>(&normal[0]), sizeof(normal[0]))) || 229 !(is.read(reinterpret_cast<char*>(&normal[1]), sizeof(normal[1]))) || 230 !(is.read(reinterpret_cast<char*>(&normal[2]), sizeof(normal[2])))) 231 { 232 if(verbose) 233 std::cerr << "Error while reading normal coordinates (premature end of file)" << std::endl; 234 235 return false; 236 } 237 238 Triangle ijk; 239 CGAL::internal::resize(ijk, 3); 240 241 for(int j=0; j<3; ++j) 242 { 243 float x,y,z; 244 if(!(is.read(reinterpret_cast<char*>(&x), sizeof(x))) || 245 !(is.read(reinterpret_cast<char*>(&y), sizeof(y))) || 246 !(is.read(reinterpret_cast<char*>(&z), sizeof(z)))) 247 { 248 if(verbose) 249 std::cerr << "Error while reading vertex coordinates (premature end of file)" << std::endl; 250 251 return false; 252 } 253 254 Point p; 255 fill_point(x, y, z, 1 /*w*/, p); 256 257 typename std::map<Point, int>::iterator iti = index_map.insert(std::make_pair(p, -1)).first; 258 259 if(iti->second == -1) 260 { 261 ijk[j] = index; 262 iti->second = index++; 263 points.push_back(p); 264 } 265 else 266 { 267 ijk[j] = iti->second; 268 } 269 } 270 271 facets.push_back(ijk); 272 273 // Read so-called attribute byte count and ignore it 274 char c; 275 if(!(is.read(reinterpret_cast<char*>(&c), sizeof(c))) || 276 !(is.read(reinterpret_cast<char*>(&c), sizeof(c)))) 277 { 278 if(verbose) 279 std::cerr << "Error while reading attribute byte count (premature end of file)" << std::endl; 280 281 return false; 282 } 283 } 284 285 return !is.fail(); 286 } 287 288 } // namespace internal 289 } // namespace IO 290 } // namespace CGAL 291 292 #endif // CGAL_IO_STL_STL_READER_H 293