28 #include <CGAL/Polyhedron_incremental_builder_3.h>
29 #include <CGAL/Min_sphere_of_spheres_d.h>
30 #include <CGAL/Min_sphere_of_spheres_d_traits_3.h>
32 #include <boost/tuple/tuple.hpp>
33 #include <boost/tuple/tuple_comparison.hpp>
34 #include <boost/tokenizer.hpp>
35 #include <boost/algorithm/string.hpp>
37 #include <vtkSmartPointer.h>
38 #include <vtkXMLPolyDataReader.h>
39 #include <vtkPolyDataReader.h>
40 #include <vtkPolyData.h>
41 #include <vtkSTLWriter.h>
43 #define MAX(a,b) (a < b ? b : a)
45 static inline double strToDouble(
const std::string& s,
bool print=
false)
47 std::istringstream is(s);
52 std::cout <<
"to_double " << s <<
" : " << val << std::endl;
62 BuildFromSTL(std::string filename) : _filename(filename){}
63 bool error() {
return _error; }
64 void operator()(HDS& hds)
68 CGAL::Polyhedron_incremental_builder_3<HDS> builder( hds,
true);
69 builder.begin_surface(100000, 100000);
71 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
73 std::ifstream file(_filename.c_str());
76 std::cerr << (
"PolyhedronUtils.cpp"
77 "open .stl file to read 3D surface"
78 "Failed to open file") << std::endl;
81 std::size_t num_vertices = 0;
82 std::map<boost::tuple<double, double, double>, std::size_t> vertex_map;
83 std::vector<std::vector<std::size_t> > facets;
85 const boost::char_separator<char> sep(
" ");
88 std::getline(file, line);
89 boost::algorithm::trim(line);
91 if (line.substr(0, 5) !=
"solid")
93 std::cerr << (
"PolyhedronUtils.cpp"
94 "open .stl file to read 3D surface"
95 "File does not start with \"solid\"") << std::endl;
100 std::getline(file, line);
101 boost::algorithm::trim(line);
110 tokenizer tokens(line, sep);
111 tokenizer::iterator tok_iter = tokens.begin();
113 if (*tok_iter !=
"facet")
114 std::cerr << (
"PolyhedronUtils.cpp"
115 "open .stl file to read 3D surface"
116 "Expected keyword \"facet\"") << std::endl;
120 if (tok_iter != tokens.end())
124 if (*tok_iter !=
"normal")
125 std::cerr << (
"PolyhedronUtils.cpp"
126 "open .stl file to read 3D surface"
127 "Expected keyword \"normal\"") << std::endl;
151 std::getline(file, line);
152 boost::algorithm::trim(line);
154 if (line !=
"outer loop")
155 std::cerr << (
"PolyhedronUtils.cpp"
156 "open .stl file to read 3D surface"
157 "Expected key word outer loop") << std::endl;
159 std::vector<std::size_t> v_indices(3);
162 for (std::size_t i = 0; i < 3; ++i)
164 std::getline(file, line);
165 boost::algorithm::trim(line);
169 tokenizer tokens(line, sep);
170 tokenizer::iterator tok_iter = tokens.begin();
172 if (*tok_iter !=
"vertex")
174 std::cerr << (
"PolyhedronUtils.cpp"
175 "open .stl file to read 3D surface"
176 "Expected key word vertex") << std::endl;
180 const double x = strToDouble(*tok_iter); ++tok_iter;
181 const double y = strToDouble(*tok_iter); ++tok_iter;
182 const double z = strToDouble(*tok_iter); ++tok_iter;
184 boost::tuple<double, double, double> v(x, y, z);
186 if (vertex_map.count(v) > 0)
187 v_indices[i] = vertex_map[v];
190 vertex_map[v] = num_vertices;
191 v_indices[i] = num_vertices;
193 builder.add_vertex(Exact_Point(x, y, z));
206 builder.add_facet(v_indices.begin(), v_indices.end());
210 std::getline(file, line);
211 boost::algorithm::trim(line);
212 if (line !=
"endloop")
214 std::cerr << (
"PolyhedronUtils.cpp"
215 "open .stl file to read 3D surface"
216 "Expected key word std::endloop") << std::endl;
219 std::getline(file, line);
220 boost::algorithm::trim(line);
221 if (line !=
"endfacet")
223 std::cerr << (
"PolyhedronUtils.cpp"
224 "open .stl file to read 3D surface"
225 "Expected key word endfacet") << std::endl;
228 std::getline(file, line);
229 boost::algorithm::trim(line);
231 if (line.substr(0, 5) !=
"facet")
236 tokenizer tokens(line, sep);
237 tokenizer::iterator tok_iter = tokens.begin();
239 if (*tok_iter !=
"endsolid")
241 std::cerr << (
"PolyhedronUtils.cpp"
242 "open .stl file to read 3D surface"
243 "Expected key word endsolid") << std::endl;
255 builder.end_surface();
257 _error = builder.error();
263 const std::string _filename;
265 bool PolyhedronUtils::_compare_ending(std::string filename,
const char* ending)
267 std::string suffix(ending);
268 if (filename.length() > suffix.length()) {
269 if (filename.compare(filename.length() - suffix.length(), suffix.length(), suffix) == 0)
276 bool PolyhedronUtils::readSurfaceFile(std::string filename, Exact_polyhedron& p)
279 if (_compare_ending(filename,
".stl"))
281 result = readSTLFile(filename, p);
283 else if(_compare_ending(filename,
".vtk"))
285 result = PolyhedronUtils::readVTKFile(filename, p);
287 else if(_compare_ending(filename,
".vtp"))
289 result = PolyhedronUtils::readVTKXMLFile(filename, p);
291 else if(_compare_ending(filename,
".off"))
293 std::ifstream fileinput(filename.c_str());
299 std::cerr << (
"PolyhedronUtils.cpp"
300 "open file to read 3D surface"
301 "Unknown file type") << std::endl;
306 bool PolyhedronUtils::readVTKXMLFile(std::string filename, Exact_polyhedron& p)
308 vtkSmartPointer<vtkXMLPolyDataReader> reader =
309 vtkSmartPointer<vtkXMLPolyDataReader>::New();
311 reader->SetFileName(filename.c_str());
314 char tmpnamebuffer[MAX(L_tmpnam, 128)] =
"/tmp/.gssfmesher-XXXXXX.stl";
316 vtkSmartPointer<vtkSTLWriter> writer =
317 vtkSmartPointer<vtkSTLWriter>::New();
319 #if VTK_MAJOR_VERSION >= 6
323 writer->WriteToOutputStringOn();
324 writer->SetInputData(reader->GetOutput());
327 if ((fd = mkstemp(tmpnamebuffer)) == -1 || !(f = fdopen(fd,
"w"))) {
328 std::cerr << (
"Could not create temporary file!") << std::endl;
332 fwrite(writer->GetOutputString(),
sizeof(char), writer->GetOutputStringLength(), f);
335 writer->SetInput(reader->GetOutput());
336 if (!tmpnam(tmpnamebuffer)) {
337 std::cerr << (
"Could not create temporary file!") << std::endl;
341 writer->SetFileName(tmpnamebuffer);
345 bool result = PolyhedronUtils::readSTLFile(tmpnamebuffer, p);
346 remove(tmpnamebuffer);
351 bool PolyhedronUtils::readVTKFile(std::string filename, Exact_polyhedron& p)
353 vtkSmartPointer<vtkPolyDataReader> reader =
354 vtkSmartPointer<vtkPolyDataReader>::New();
356 reader->SetFileName(filename.c_str());
358 std::string filenamestl = filename +
".stl";
359 const char *tmpnamebuffer = filenamestl.c_str();
361 std::string tmpname(tmpnamebuffer);
362 vtkSmartPointer<vtkSTLWriter> writer =
363 vtkSmartPointer<vtkSTLWriter>::New();
365 writer->SetFileName(tmpname.c_str());
366 #if VTK_MAJOR_VERSION >= 6
367 writer->SetInputData(reader->GetOutput());
369 writer->SetInput(reader->GetOutput());
373 bool result = PolyhedronUtils::readSTLFile(tmpname, p);
374 remove(tmpnamebuffer);
378 bool PolyhedronUtils::readSTLFile(std::string filename, Exact_polyhedron& p)
381 p.delegate(stl_builder);
382 return !stl_builder.error();
385 CGAL::Bbox_3 PolyhedronUtils::getBoundingBox(Polyhedron& polyhedron)
387 Polyhedron::Vertex_iterator it = polyhedron.vertices_begin();
390 Polyhedron::Point_3 p0 = it->point();
391 CGAL::Bbox_3 b(p0[0], p0[1], p0[2], p0[0], p0[1], p0[2]);
394 for (; it != polyhedron.vertices_end(); ++it)
396 Polyhedron::Point_3 p1 = it->point();
397 b = b + CGAL::Bbox_3(p1[0], p1[1], p1[2], p1[0], p1[1], p1[2]);
403 double PolyhedronUtils::getBoundingSphereRadius(Polyhedron& polyhedron)
405 typedef CGAL::Min_sphere_of_spheres_d_traits_3<Polyhedron::Traits, double> Traits;
406 typedef Traits::Sphere Sphere;
407 typedef CGAL::Min_sphere_of_spheres_d<Traits> Min_sphere;
409 std::vector<Sphere> s(polyhedron.size_of_vertices());
411 for (Polyhedron::Vertex_iterator it=polyhedron.vertices_begin();
412 it != polyhedron.vertices_end(); ++it)
414 const Polyhedron::Point_3 p = it->point();
415 s.push_back(Sphere(p, 0.0));
418 Min_sphere ms(s.begin(),s.end());
420 assert(ms.is_valid());
422 return CGAL::to_double(ms.radius());
425 template<
typename Polyhedron>
426 static inline double get_edge_length(
typename Polyhedron::Halfedge::Halfedge_handle halfedge)
428 return CGAL::to_double((halfedge->vertex()->point() -
429 halfedge->opposite()->vertex()->point()).squared_length());
432 template <
typename Polyhedron>
433 static inline double get_triangle_area(
typename Polyhedron::Facet_handle facet)
435 const typename Polyhedron::Halfedge_handle edge = facet->halfedge();
436 const typename Polyhedron::Point_3 a = edge->vertex()->point();
437 const typename Polyhedron::Point_3 b = edge->next()->vertex()->point();
438 const typename Polyhedron::Point_3 c = edge->next()->next()->vertex()->point();
439 return CGAL::to_double(CGAL::cross_product(b-a, c-a).squared_length());
442 template<
typename Polyhedron>
443 static inline double get_min_edge_length(
typename Polyhedron::Facet_handle facet)
445 typename Polyhedron::Facet::Halfedge_around_facet_circulator half_edge = facet->facet_begin();
446 double min_length = CGAL::to_double((half_edge->vertex()->point()
447 - half_edge->opposite()->vertex()->point()).squared_length());
450 min_length = std::min(min_length, get_edge_length<Polyhedron>(half_edge));
453 min_length = std::min(min_length, get_edge_length<Polyhedron>(half_edge));
458 template<
typename Polyhedron>
459 bool facet_is_degenerate(
typename Polyhedron::Facet_handle facet,
const double threshold)
467 return get_min_edge_length<Polyhedron>(facet) < threshold
468 || get_triangle_area<Polyhedron>(facet) < threshold;
472 template<
typename Polyhedron>
473 static int number_of_degenerate_facets(Polyhedron& p,
const double threshold)
476 for (
typename Polyhedron::Facet_iterator facet = p.facets_begin();
477 facet != p.facets_end(); facet++)
479 assert(facet->is_triangle());
480 if ( facet_is_degenerate<Polyhedron>(facet, threshold) )
486 template <
typename Polyhedron>
487 static typename Polyhedron::Halfedge_handle get_longest_edge(
typename Polyhedron::Facet_handle facet)
489 typename Polyhedron::Halfedge_handle edge = facet->halfedge();
490 double length = get_edge_length<Polyhedron>(edge);
493 typename Polyhedron::Halfedge_handle e_tmp = edge->next();
494 if (get_edge_length<Polyhedron>(e_tmp) > length)
496 length = get_edge_length<Polyhedron>(e_tmp);
502 typename Polyhedron::Halfedge_handle e_tmp = edge->next()->next();
503 if ( get_edge_length<Polyhedron>(e_tmp) > length )
505 length = get_edge_length<Polyhedron>(e_tmp);
513 template <
typename Polyhedron>
514 double shortest_edge(Polyhedron& p)
516 double shortest = std::numeric_limits<double>::max();
517 for (
typename Polyhedron::Halfedge_iterator halfedge = p.halfedges_begin();
518 halfedge != p.halfedges_end(); halfedge++)
520 const double length = get_edge_length<Polyhedron>(halfedge);
521 shortest = std::min(shortest, length);
527 template <
typename Polyhedron>
528 static void remove_edge(Polyhedron& p,
typename Polyhedron::Halfedge_handle& edge)
555 edge = p.join_facet(edge->next());
556 p.join_facet(edge->opposite()->prev());
563 template <
typename Polyhedron>
564 static void remove_short_edges(Polyhedron& p,
const double threshold)
568 bool removed =
false;
569 for (
typename Polyhedron::Halfedge_iterator halfedge = p.halfedges_begin();
570 halfedge != p.halfedges_end(); halfedge++)
572 if (get_edge_length<Polyhedron>(halfedge) < threshold)
574 remove_edge<Polyhedron>(p, halfedge);
585 template <
typename Polyhedron>
586 static typename Polyhedron::Point_3 facet_midpoint(
typename Polyhedron::Facet_handle facet)
588 typename Polyhedron::Point_3 p(CGAL::ORIGIN);
590 typename Polyhedron::Facet::Halfedge_around_facet_circulator half_edge = facet->facet_begin();
592 for (std::size_t i = 0; i < facet->facet_degree(); i++)
594 p = p + (half_edge->vertex()->point() - CGAL::ORIGIN);
598 p = CGAL::ORIGIN + (p - CGAL::ORIGIN)/static_cast<double>(facet->facet_degree());
612 template <
typename Polyhedron>
613 static void remove_triangle(Polyhedron& p,
typename Polyhedron::Facet_handle facet)
615 assert(facet->is_triangle());
621 typename Polyhedron::Halfedge_handle edge = get_longest_edge<Polyhedron>(facet);
629 edge = p.join_facet(edge);
636 typename Polyhedron::Point_3 new_center = facet_midpoint<Polyhedron>(edge->facet());
638 edge = p.create_center_vertex(edge);
640 edge->vertex()->point() = new_center;
651 template<
typename Polyhedron>
652 static void remove_small_triangles(Polyhedron& p,
const double threshold)
654 int n = number_of_degenerate_facets(p, threshold);
658 for (
typename Polyhedron::Facet_iterator facet = p.facets_begin();
659 facet != p.facets_end(); facet++)
661 assert(facet->is_triangle());
663 if (get_triangle_area<Polyhedron>(facet) < threshold)
667 remove_triangle<Polyhedron>(p, facet);
668 n = number_of_degenerate_facets<Polyhedron>(p, threshold);
675 void PolyhedronUtils::remove_degenerate_facets(Exact_polyhedron& p,
const double threshold)
677 int degenerate_facets = number_of_degenerate_facets(p, threshold);
679 std::cout <<
"Number of degenerate facets: " << degenerate_facets << std::endl;
681 if (degenerate_facets > 0)
683 assert(p.is_pure_triangle());
687 std::cout <<
"Removing triangles with short edges" << std::endl;
688 remove_short_edges(p, threshold);
690 std::cout <<
"Number of degenerate facets: " << number_of_degenerate_facets(p, threshold) << std::endl;
692 std::cout <<
"Removing small triangles" << std::endl;
693 remove_small_triangles(p, threshold);
695 std::cout <<
"Number of degenerate facets: " << number_of_degenerate_facets(p, threshold) << std::endl;
698 assert(p.is_pure_triangle());
702 bool PolyhedronUtils::has_degenerate_facets(Exact_polyhedron& p,
double threshold)
704 for (Exact_polyhedron::Facet_iterator facet = p.facets_begin();
705 facet != p.facets_end(); facet++)
707 assert(facet->is_triangle());
709 if ( facet_is_degenerate<Exact_polyhedron>(facet, threshold) )
Definition: PolyhedronUtils.imp.h:58