File: hole_filling_visitor_example.cpp

package info (click to toggle)
cgal 6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 144,912 kB
  • sloc: cpp: 810,858; ansic: 208,477; sh: 493; python: 411; makefile: 286; javascript: 174
file content (185 lines) | stat: -rw-r--r-- 5,377 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>

#include <CGAL/Polygon_mesh_processing/triangulate_hole.h>
#include <CGAL/Polygon_mesh_processing/border.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
#include <CGAL/Real_timer.h>

#include <boost/lexical_cast.hpp>

#include <iostream>
#include <iterator>
#include <string>
#include <tuple>
#include <vector>
#include <stdexcept>

typedef CGAL::Real_timer                                    Timer;
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3                                     Point;
typedef CGAL::Surface_mesh<Point>                           Mesh;

typedef boost::graph_traits<Mesh>::vertex_descriptor        vertex_descriptor;
typedef boost::graph_traits<Mesh>::halfedge_descriptor      halfedge_descriptor;
typedef boost::graph_traits<Mesh>::face_descriptor          face_descriptor;

namespace PMP = CGAL::Polygon_mesh_processing;

bool is_small_hole(halfedge_descriptor h, Mesh & mesh,
                   double max_hole_diam, int max_num_hole_edges)
{
  int num_hole_edges = 0;
  CGAL::Bbox_3 hole_bbox;
  for (halfedge_descriptor hc : CGAL::halfedges_around_face(h, mesh))
  {
    const Point& p = mesh.point(target(hc, mesh));

    hole_bbox += p.bbox();
    ++num_hole_edges;

    // Exit early, to avoid unnecessary traversal of large holes
    if (num_hole_edges > max_num_hole_edges) return false;
    if (hole_bbox.xmax() - hole_bbox.xmin() > max_hole_diam) return false;
    if (hole_bbox.ymax() - hole_bbox.ymin() > max_hole_diam) return false;
    if (hole_bbox.zmax() - hole_bbox.zmin() > max_hole_diam) return false;
  }

  return true;
}

struct Stop : std::exception
{
    Stop()
    {}
};

struct Progress :
    public PMP::Hole_filling::Default_visitor
{
  Progress(double time_limit)
      : time_limit(time_limit)
  {}

  Progress(const Progress&) = delete;

  void start_planar_phase() const
  {
    std::cout << "Start planar phase"<< std::endl;
  }

  void end_planar_phase(bool success) const
  {
    std::cout << "End planar phase " << (success? "(success)" : "(failed)") << std::endl;
  }

  void start_quadratic_phase(std::size_t n)
  {
    timer.start();
    quadratic_i = 0;
    quadratic_n = n;
    quadratic_report = n / 10;
    std::cout << "Start quadratic phase with estimated " << n << " steps" << std::endl;
  }

  void quadratic_step()
  {
    if (quadratic_i++ == quadratic_report) {
      std::cout << double(quadratic_i) / double(quadratic_n) * 100 << "%" << std::endl;
      quadratic_report += quadratic_n / 10;
    }
  }

  void end_quadratic_phase(bool success) const
  {
    timer.stop();
    std::cout << "End quadratic phase " << timer.time() << " sec. " << (success ? "(success)" : "(failed)") << std::endl;
    timer.reset();
  }


  void start_cubic_phase(std::size_t n)
  {
    timer.start();
      cubic_n = n;
      cubic_report = n / 10;
      std::cout << "Start cubic phase with " << n << " steps" << std::endl;
  }


  void cubic_step()
  {
    if (timer.time() > time_limit) {
        std::cout << "Let's stop here" << std::endl;
        throw Stop();
    }
    if (cubic_i++ == cubic_report) {
      std::cout << double(cubic_i) / double(cubic_n) * 100 << "%" << std::endl;
      cubic_report += cubic_n / 10;
    }
  }

  void end_cubic_phase() const
  {
    std::cout << "End cubic phase " << timer.time() << " sec. "  << std::endl;
  }

  mutable Timer timer;
  double time_limit;
  std::size_t quadratic_n = 0, quadratic_i = 0, quadratic_report = 0;
  std::size_t cubic_n = 0, cubic_i = 0, cubic_report = 0;
};

// Incrementally fill the holes that are no larger than given diameter
// and with no more than a given number of edges (if specified).

int main(int argc, char* argv[])
{
  const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mech-holes-shark.off");

  Mesh mesh;
  if(!PMP::IO::read_polygon_mesh(filename, mesh))
  {
    std::cerr << "Invalid input." << std::endl;
    return 1;
  }

  // Both of these must be positive in order to be considered
  double max_hole_diam   = (argc > 2) ? boost::lexical_cast<double>(argv[2]): -1.0;
  int max_num_hole_edges = (argc > 3) ? boost::lexical_cast<int>(argv[3]) : -1;

  unsigned int nb_holes = 0;
  std::vector<halfedge_descriptor> border_cycles;

  // collect one halfedge per boundary cycle
  PMP::extract_boundary_cycles(mesh, std::back_inserter(border_cycles));

  for(halfedge_descriptor h : border_cycles)
  {
    if(max_hole_diam > 0 && max_num_hole_edges > 0 &&
       !is_small_hole(h, mesh, max_hole_diam, max_num_hole_edges))
      continue;

    Progress progress(10.0);
    bool success = false;

    try {
        success = std::get<0>(PMP::triangulate_refine_and_fair_hole(mesh,
            h,
            CGAL::parameters::visitor(std::ref(progress)).use_delaunay_triangulation(true)));
    }
    catch (const Stop&) {
        std::cout << "We stopped with a timeout" << std::endl;
    }
    std::cout << "  Is fairing successful: " << success << std::endl;
    ++nb_holes;
  }

  std::cout << std::endl;
  std::cout << nb_holes << " holes have been filled" << std::endl;

  CGAL::IO::write_polygon_mesh("filled_SM.off", mesh, CGAL::parameters::stream_precision(17));
  std::cout << "Mesh written to: filled_SM.off" << std::endl;

  return 0;
}