Easy3D 2.6.1
Loading...
Searching...
No Matches
surface_mesh_simplification.h
1/********************************************************************
2 * Copyright (C) 2020-2021 by Liangliang Nan <liangliang.nan@gmail.com>
3 * Copyright (C) 2011-2020 the Polygon Mesh Processing Library developers.
4 *
5 * The code in this file is adapted from the PMP (Polygon Mesh Processing
6 * Library) with modifications.
7 * https://github.com/pmp-library/pmp-library
8 * The original code was distributed under a MIT-style license, see
9 * https://github.com/pmp-library/pmp-library/blob/master/LICENSE.txt
10 ********************************************************************/
11
12#ifndef EASY3D_ALGO_SURFACE_MESH_SIMPLIFICATION_H
13#define EASY3D_ALGO_SURFACE_MESH_SIMPLIFICATION_H
14
15#include <vector>
16
17#include <easy3d/core/surface_mesh.h>
18#include <easy3d/core/heap.h>
19
20
21
22
23namespace easy3d {
24
34 public:
40
45
54 void initialize(float aspect_ratio = 0.0, float edge_length = 0.0,
55 unsigned int max_valence = 0, float normal_deviation = 0.0,
56 float hausdorff_error = 0.0);
57
62 void simplify(unsigned int n_vertices);
63
64 private:
66 /*
67 vl
68 *
69 / \
70 / \
71 / fl \
72 v0 *------>* v1
73 \ fr /
74 \ /
75 \ /
76 *
77 vr
78 */
79 struct CollapseData {
80 CollapseData(SurfaceMesh *sm, SurfaceMesh::Halfedge h);
81
82 SurfaceMesh *mesh;
83
84 SurfaceMesh::Halfedge v0v1; // Halfedge to be collapsed
85 SurfaceMesh::Halfedge v1v0; // Reverse halfedge
86 SurfaceMesh::Vertex v0; // Vertex to be removed
87 SurfaceMesh::Vertex v1; // Remaining vertex
88 SurfaceMesh::Face fl; // Left face
89 SurfaceMesh::Face fr; // Right face
90 SurfaceMesh::Vertex vl; // Left vertex
91 SurfaceMesh::Vertex vr; // Right vertex
92 SurfaceMesh::Halfedge v1vl, vlv0, v0vr, vrv1;
93 };
94
96 class HeapInterface {
97 public:
99 : prio_(prio), pos_(pos) {
100 }
101
102 bool less(SurfaceMesh::Vertex v0, SurfaceMesh::Vertex v1) { return prio_[v0] < prio_[v1]; }
103
104 bool greater(SurfaceMesh::Vertex v0, SurfaceMesh::Vertex v1) { return prio_[v0] > prio_[v1]; }
105
106 int get_heap_position(SurfaceMesh::Vertex v) { return pos_[v]; }
107
108 void set_heap_position(SurfaceMesh::Vertex v, int pos) { pos_[v] = pos; }
109
110 private:
111 SurfaceMesh::VertexProperty<float> prio_;
112 SurfaceMesh::VertexProperty<int> pos_;
113 };
114
116 class Quadric {
117 public:
119 Quadric(double a, double b, double c, double d,
120 double e, double f, double g,
121 double h, double i,
122 double j)
123 : a_(a), b_(b), c_(c), d_(d),
124 e_(e), f_(f), g_(g),
125 h_(h), i_(i),
126 j_(j) {}
127
129 explicit Quadric(double a = 0.0, double b = 0.0, double c = 0.0, double d = 0.0)
130 : a_(a * a), b_(a * b), c_(a * c), d_(a * d),
131 e_(b * b), f_(b * c), g_(b * d),
132 h_(c * c), i_(c * d),
133 j_(d * d) {}
134
136 Quadric(const vec3 &n, const vec3 &p) {
137 *this = Quadric(n[0], n[1], n[2], -dot(n, p));
138 }
139
141 void clear() { a_ = b_ = c_ = d_ = e_ = f_ = g_ = h_ = i_ = j_ = 0.0; }
142
144 Quadric &operator+=(const Quadric &q) {
145 a_ += q.a_;
146 b_ += q.b_;
147 c_ += q.c_;
148 d_ += q.d_;
149 e_ += q.e_;
150 f_ += q.f_;
151 g_ += q.g_;
152 h_ += q.h_;
153 i_ += q.i_;
154 j_ += q.j_;
155 return *this;
156 }
157
159 Quadric &operator*=(double s) {
160 a_ *= s;
161 b_ *= s;
162 c_ *= s;
163 d_ *= s;
164 e_ *= s;
165 f_ *= s;
166 g_ *= s;
167 h_ *= s;
168 i_ *= s;
169 j_ *= s;
170 return *this;
171 }
172
174 double operator()(const vec3 &p) const {
175 const double x(p[0]), y(p[1]), z(p[2]);
176 return a_ * x * x + 2.0 * b_ * x * y + 2.0 * c_ * x * z + 2.0 * d_ * x
177 + e_ * y * y + 2.0 * f_ * y * z + 2.0 * g_ * y
178 + h_ * z * z + 2.0 * i_ * z
179 + j_;
180 }
181
182 private:
183
184 double a_, b_, c_, d_,
185 e_, f_, g_,
186 h_, i_,
187 j_;
188 };
189
190 //=============================================================================
191
193 class NormalCone {
194 public:
196 NormalCone() = default;
197
199 explicit NormalCone(const vec3 &normal, float angle = 0.0)
200 : center_normal_(normal), angle_(angle) {
201 }
202
204 const vec3 &center_normal() const { return center_normal_; }
205
207 float angle() const { return angle_; }
208
210 NormalCone &merge(const vec3 &n) { return merge(NormalCone(n)); }
211
213 NormalCone &merge(const NormalCone &nc) {
214 const float dp = dot(center_normal_, nc.center_normal_);
215
216 // axes point in same direction
217 if (dp > 0.99999) {
218 angle_ = std::max(angle_, nc.angle_);
219 }
220
221 // axes point in opposite directions
222 else if (dp < -0.99999) {
223 angle_ = static_cast<float>(2 * M_PI);
224 } else {
225 // new angle
226 float center_angle = std::acos(dp);
227 float min_angle = std::min(-angle_, center_angle - nc.angle_);
228 float max_angle = std::max(angle_, center_angle + nc.angle_);
229 angle_ = 0.5f * (max_angle - min_angle);
230
231 // axis by SLERP
232 float axis_angle = 0.5f * (min_angle + max_angle);
233 center_normal_ = ((center_normal_ * std::sin(center_angle - axis_angle) +
234 nc.center_normal_ * std::sin(axis_angle)) /
235 std::sin(center_angle));
236 }
237
238 return *this;
239 }
240
241 private:
242 vec3 center_normal_;
243 float angle_;
244 };
245
246 typedef Heap<SurfaceMesh::Vertex, HeapInterface> PriorityQueue;
247
248 typedef std::vector<vec3> Points;
249
250 private:
251 // put the vertex v in the priority queue
252 void enqueue_vertex(SurfaceMesh::Vertex v);
253
254 // is collapsing the halfedge h allowed?
255 bool is_collapse_legal(const CollapseData &cd);
256
257 // what is the priority of collapsing the halfedge h
258 float priority(const CollapseData &cd);
259
260 // postprocess halfedge collapse
261 void postprocess_collapse(const CollapseData &cd);
262
263 // compute aspect ratio for face f
264 float aspect_ratio(SurfaceMesh::Face f) const;
265
266 // compute distance from p to triangle f
267 float distance(SurfaceMesh::Face f, const vec3 &p) const;
268
269 private:
270 SurfaceMesh *mesh_;
271
272 bool initialized_;
273
274 SurfaceMesh::VertexProperty<float> vpriority_;
275 SurfaceMesh::VertexProperty<SurfaceMesh::Halfedge> vtarget_;
276 SurfaceMesh::VertexProperty<int> heap_pos_;
277 SurfaceMesh::VertexProperty<Quadric> vquadric_;
278 SurfaceMesh::FaceProperty<NormalCone> normal_cone_;
279 SurfaceMesh::FaceProperty<Points> face_points_;
280
281 SurfaceMesh::VertexProperty<vec3> vpoint_;
282 SurfaceMesh::FaceProperty<vec3> fnormal_;
283 SurfaceMesh::VertexProperty<bool> vselected_;
284 SurfaceMesh::VertexProperty<bool> vfeature_;
285 SurfaceMesh::EdgeProperty<bool> efeature_;
286
287 PriorityQueue *queue_;
288
289 bool has_selection_;
290 bool has_features_;
291 float normal_deviation_;
292 float hausdorff_error_;
293 float aspect_ratio_;
294 float edge_length_;
295 unsigned int max_valence_;
296 };
297
298} // namespace easy3d
299
300#endif // EASY3D_ALGO_SURFACE_MESH_SIMPLIFICATION_H
Vertex property of type T.
Definition surface_mesh.h:255
A halfedge data structure for polygonal meshes of 2-manifold.
Definition surface_mesh.h:51
SurfaceMeshSimplification(SurfaceMesh *mesh)
Construct with mesh to be simplified.
Definition surface_mesh_simplification.cpp:20
void simplify(unsigned int n_vertices)
Simplify mesh to n vertices.
Definition surface_mesh_simplification.cpp:124
void initialize(float aspect_ratio=0.0, float edge_length=0.0, unsigned int max_valence=0, float normal_deviation=0.0, float hausdorff_error=0.0)
Initialize with given parameters.
Definition surface_mesh_simplification.cpp:42
Definition collider.cpp:182
Vec< 3, float > vec3
A 3D point/vector of float type.
Definition types.h:44
FT dot(const std::vector< FT > &, const std::vector< FT > &)
Inner product for vectors.
Definition matrix.h:1834
Definition surface_mesh.h:191
This type represents a halfedge (internally it is basically an index).
Definition surface_mesh.h:155
This type represents a vertex (internally it is basically an index).
Definition surface_mesh.h:135