File: edge_collapse_visitor_surface_mesh.cpp

package info (click to toggle)
cgal 6.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 141,840 kB
  • sloc: cpp: 797,081; ansic: 203,398; sh: 490; python: 411; makefile: 286; javascript: 174
file content (142 lines) | stat: -rw-r--r-- 4,887 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
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>

// Simplification function
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>

// Visitor base
#include <CGAL/Surface_mesh_simplification/Edge_collapse_visitor_base.h>

// Stop-condition policy
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_count_ratio_stop_predicate.h>

#include <iostream>
#include <fstream>

typedef CGAL::Simple_cartesian<double>                                  Kernel;
typedef Kernel::Point_3                                                 Point_3;

typedef CGAL::Surface_mesh<Point_3>                                     Surface_mesh;

typedef boost::graph_traits<Surface_mesh>::halfedge_descriptor          halfedge_descriptor;
typedef boost::graph_traits<Surface_mesh>::vertex_descriptor            vertex_descriptor;

namespace SMS = CGAL::Surface_mesh_simplification;

typedef SMS::Edge_profile<Surface_mesh>                                 Profile;

// The following is a Visitor that keeps track of the simplification process.
// In this example the progress is printed real-time and a few statistics are
// recorded (and printed in the end).
//
struct Stats
{
  std::size_t collected = 0;
  std::size_t processed = 0;
  std::size_t collapsed = 0;
  std::size_t non_collapsable = 0;
  std::size_t cost_uncomputable = 0;
  std::size_t placement_uncomputable = 0;
};

struct My_visitor : SMS::Edge_collapse_visitor_base<Surface_mesh>
{
  My_visitor(Stats* s) : stats(s) {}

  // Called during the collecting phase for each edge collected.
  void OnCollected(const Profile&, const std::optional<double>&)
  {
    ++(stats->collected);
    std::cerr << "\rEdges collected: " << stats->collected << std::flush;
  }

  // Called during the processing phase for each edge selected.
  // If cost is absent the edge won't be collapsed.
  void OnSelected(const Profile&,
                  std::optional<double> cost,
                  std::size_t initial,
                  std::size_t current)
  {
    ++(stats->processed);
    if(!cost)
      ++(stats->cost_uncomputable);

    if(current == initial)
      std::cerr << "\n" << std::flush;
    std::cerr << "\r" << current << std::flush;
  }

  // Called during the processing phase for each edge being collapsed.
  // If placement is absent the edge is left uncollapsed.
  void OnCollapsing(const Profile&,
                    std::optional<Point> placement)
  {
    if(!placement)
      ++(stats->placement_uncomputable);
  }

  // Called for each edge which failed the so called link-condition,
  // that is, which cannot be collapsed because doing so would
  // turn the surface mesh into a non-manifold.
  void OnNonCollapsable(const Profile&)
  {
    ++(stats->non_collapsable);
  }

  // Called after each edge has been collapsed
  void OnCollapsed(const Profile&, vertex_descriptor)
  {
    ++(stats->collapsed);
  }

  Stats* stats;
};

int main(int argc, char** argv)
{
  Surface_mesh surface_mesh;
  const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/small_cube.off");
  std::ifstream is(filename);
  if(!is || !(is >> surface_mesh))
  {
    std::cerr << "Failed to read input mesh: " << filename << std::endl;
    return EXIT_FAILURE;
  }

  if(!CGAL::is_triangle_mesh(surface_mesh))
  {
    std::cerr << "Input geometry is not triangulated." << std::endl;
    return EXIT_FAILURE;
  }

  // In this example, the simplification stops when the number of undirected edges
  // drops below xx% of the initial count
  const double ratio = (argc > 2) ? std::stod(argv[2]) : 0.1;
  SMS::Edge_count_ratio_stop_predicate<Surface_mesh> stop(ratio);

  Stats stats;
  My_visitor vis(&stats);

  // The index maps are not explicitelty passed as in the previous
  // example because the surface mesh items have a proper id() field.
  // On the other hand, we pass here explicit cost and placement
  // function which differ from the default policies, omitted in
  // the previous example.
  int r = SMS::edge_collapse(surface_mesh, stop, CGAL::parameters::visitor(vis));

  std::cout << "\nEdges collected: "  << stats.collected
            << "\nEdges processed: "  << stats.processed
            << "\nEdges collapsed: "  << stats.collapsed
            << std::endl
            << "\nEdges not collapsed due to topological constraints: "  << stats.non_collapsable
            << "\nEdge not collapsed due to cost computation constraints: "  << stats.cost_uncomputable
            << "\nEdge not collapsed due to placement computation constraints: " << stats.placement_uncomputable
            << std::endl;

  std::cout << "\nFinished!\n" << r << " edges removed.\n"
            << surface_mesh.number_of_edges() << " final edges.\n";

  CGAL::IO::write_polygon_mesh((argc > 3) ? argv[3] : "out.off", surface_mesh, CGAL::parameters::stream_precision(17));

  return EXIT_SUCCESS;
}