CARLA
Loading...
Searching...
No Matches
Simplify.h
Go to the documentation of this file.
1/////////////////////////////////////////////
2//
3// Mesh Simplification Tutorial
4//
5// (C) by Sven Forstmann in 2014
6//
7// License : MIT
8// http://opensource.org/licenses/MIT
9//
10// https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification
11//
12// 5/2016: Chris Rorden created minimal version for OSX/Linux/Windows compile
13
14#include <iostream>
15#include <fstream>
16#include <algorithm>
17#include <string.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <map>
21#include <vector>
22#include <string>
23#include <math.h>
24#include <float.h> //FLT_EPSILON, DBL_EPSILON
25
26#define loopi(start_l, end_l) for (size_t i = static_cast<size_t>(start_l); i < static_cast<size_t>(end_l); ++i)
27#define loopj(start_l, end_l) for (size_t j = static_cast<size_t>(start_l); j < static_cast<size_t>(end_l); ++j)
28#define loopk(start_l, end_l) for (size_t k = static_cast<size_t>(start_l); k < static_cast<size_t>(end_l); ++k)
29
30struct vector3
31{
32 double x, y, z;
33};
34
35struct vec3f
36{
37 double x, y, z;
38
39 inline vec3f(void) {}
40
41 inline vec3f(const vec3f &a) : x(a.x), y(a.y), z(a.z) {}
42
43 inline vec3f(vector3 a)
44 {
45 x = a.x;
46 y = a.y;
47 z = a.z;
48 }
49
50 inline vec3f(const double X, const double Y, const double Z)
51 {
52 x = X;
53 y = Y;
54 z = Z;
55 }
56
57 inline vec3f operator+(const vec3f &a) const
58 {
59 return vec3f(x + a.x, y + a.y, z + a.z);
60 }
61
62 inline vec3f operator+=(const vec3f &a) const
63 {
64 return vec3f(x + a.x, y + a.y, z + a.z);
65 }
66
67 inline vec3f operator*(const double a) const
68 {
69 return vec3f(x * a, y * a, z * a);
70 }
71
72 inline vec3f operator*(const vec3f a) const
73 {
74 return vec3f(x * a.x, y * a.y, z * a.z);
75 }
76
77 inline vec3f v3() const
78 {
79 return vec3f(x, y, z);
80 }
81
82 inline vec3f operator=(const vector3 a)
83 {
84 x = a.x;
85 y = a.y;
86 z = a.z;
87 return *this;
88 }
89
90 inline vec3f operator=(const vec3f a)
91 {
92 x = a.x;
93 y = a.y;
94 z = a.z;
95 return *this;
96 }
97
98 inline vec3f operator/(const vec3f a) const
99 {
100 return vec3f(x / a.x, y / a.y, z / a.z);
101 }
102
103 inline vec3f operator-(const vec3f &a) const
104 {
105 return vec3f(x - a.x, y - a.y, z - a.z);
106 }
107
108 inline vec3f operator/(const double a) const
109 {
110 return vec3f(x / a, y / a, z / a);
111 }
112
113 inline double dot(const vec3f &a) const
114 {
115 return a.x * x + a.y * y + a.z * z;
116 }
117
118 inline vec3f cross(const vec3f &a, const vec3f &b)
119 {
120 x = a.y * b.z - a.z * b.y;
121 y = a.z * b.x - a.x * b.z;
122 z = a.x * b.y - a.y * b.x;
123 return *this;
124 }
125
126 inline double angle(const vec3f &v)
127 {
128 vec3f a = v, b = *this;
129 double dot = v.x * x + v.y * y + v.z * z;
130 double len = a.length() * b.length();
131 if (len == 0)
132 len = 0.00001f;
133 double input = dot / len;
134 if (input < -1)
135 input = -1;
136 if (input > 1)
137 input = 1;
138 return acos(input);
139 }
140
141 inline double angle2(const vec3f &v, const vec3f &w)
142 {
143 vec3f a = v, b = *this;
144 double dot = a.x * b.x + a.y * b.y + a.z * b.z;
145 double len = a.length() * b.length();
146 if (len == 0)
147 len = 1;
148
149 vec3f plane;
150 plane.cross(b, w);
151
152 if (plane.x * a.x + plane.y * a.y + plane.z * a.z > 0)
153 return -acos(dot / len);
154
155 return acos(dot / len);
156 }
157
158 inline vec3f rot_x(double a)
159 {
160 double yy = cos(a) * y + sin(a) * z;
161 double zz = cos(a) * z - sin(a) * y;
162 y = yy;
163 z = zz;
164 return *this;
165 }
166 inline vec3f rot_y(double a)
167 {
168 double xx = cos(-a) * x + sin(-a) * z;
169 double zz = cos(-a) * z - sin(-a) * x;
170 x = xx;
171 z = zz;
172 return *this;
173 }
174 inline void clamp(double min, double max)
175 {
176 if (x < min)
177 x = min;
178 if (y < min)
179 y = min;
180 if (z < min)
181 z = min;
182 if (x > max)
183 x = max;
184 if (y > max)
185 y = max;
186 if (z > max)
187 z = max;
188 }
189 inline vec3f rot_z(double a)
190 {
191 double yy = cos(a) * y + sin(a) * x;
192 double xx = cos(a) * x - sin(a) * y;
193 y = yy;
194 x = xx;
195 return *this;
196 }
197 inline vec3f invert()
198 {
199 x = -x;
200 y = -y;
201 z = -z;
202 return *this;
203 }
204 inline vec3f frac()
205 {
206 return vec3f(
207 x - double(int(x)),
208 y - double(int(y)),
209 z - double(int(z)));
210 }
211
212 inline vec3f integer()
213 {
214 return vec3f(
215 double(int(x)),
216 double(int(y)),
217 double(int(z)));
218 }
219
220 inline double length() const
221 {
222 return sqrt(x * x + y * y + z * z);
223 }
224
225 inline vec3f normalize(double /*desired_length*/ = 1)
226 {
227 double square = sqrt(x * x + y * y + z * z);
228 x /= square;
229 y /= square;
230 z /= square;
231
232 return *this;
233 }
235
236 static void random_init();
237 static double random_double();
238 static vec3f random();
239
240 static int random_number;
241
242 double random_double_01(double a)
243 {
244 double rnf = a * 14.434252 + a * 364.2343 + a * 4213.45352 + a * 2341.43255 + a * 254341.43535 + a * 223454341.3523534245 + 23453.423412;
245 int rni = static_cast<int>(rnf) % 100000;
246 return double(rni) / (100000.0f - 1.0f);
247 }
248
250 {
254 return *this;
255 }
256};
257
258vec3f barycentric(const vec3f &p, const vec3f &a, const vec3f &b, const vec3f &c)
259{
260 vec3f v0 = b - a;
261 vec3f v1 = c - a;
262 vec3f v2 = p - a;
263 double d00 = v0.dot(v0);
264 double d01 = v0.dot(v1);
265 double d11 = v1.dot(v1);
266 double d20 = v2.dot(v0);
267 double d21 = v2.dot(v1);
268 double denom = d00 * d11 - d01 * d01;
269 double v = (d11 * d20 - d01 * d21) / denom;
270 double w = (d00 * d21 - d01 * d20) / denom;
271 double u = 1.0 - v - w;
272 return vec3f(u, v, w);
273}
274
275vec3f interpolate(const vec3f &p, const vec3f &a, const vec3f &b, const vec3f &c, const vec3f attrs[3])
276{
277 vec3f bary = barycentric(p, a, b, c);
278 vec3f out = vec3f(0, 0, 0);
279 out = out + attrs[0] * bary.x;
280 out = out + attrs[1] * bary.y;
281 out = out + attrs[2] * bary.z;
282 return out;
283}
284
285double min(double v1, double v2)
286{
287 return fmin(v1, v2);
288}
289
291{
292
293public:
294 // Constructor
295
296 SymetricMatrix(double c = 0) { loopi(0, 10) m[i] = c; }
297
298 SymetricMatrix(double m11, double m12, double m13, double m14,
299 double m22, double m23, double m24,
300 double m33, double m34,
301 double m44)
302 {
303 m[0] = m11;
304 m[1] = m12;
305 m[2] = m13;
306 m[3] = m14;
307 m[4] = m22;
308 m[5] = m23;
309 m[6] = m24;
310 m[7] = m33;
311 m[8] = m34;
312 m[9] = m44;
313 }
314
315 // Make plane
316
317 SymetricMatrix(double a, double b, double c, double d)
318 {
319 m[0] = a * a;
320 m[1] = a * b;
321 m[2] = a * c;
322 m[3] = a * d;
323 m[4] = b * b;
324 m[5] = b * c;
325 m[6] = b * d;
326 m[7] = c * c;
327 m[8] = c * d;
328 m[9] = d * d;
329 }
330
331 double operator[](int c) const { return m[c]; }
332
333 // Determinant
334
335 double det(int a11, int a12, int a13,
336 int a21, int a22, int a23,
337 int a31, int a32, int a33)
338 {
339 double det = m[a11] * m[a22] * m[a33] + m[a13] * m[a21] * m[a32] + m[a12] * m[a23] * m[a31] - m[a13] * m[a22] * m[a31] - m[a11] * m[a23] * m[a32] - m[a12] * m[a21] * m[a33];
340 return det;
341 }
342
344 {
345 return SymetricMatrix(m[0] + n[0], m[1] + n[1], m[2] + n[2], m[3] + n[3],
346 m[4] + n[4], m[5] + n[5], m[6] + n[6],
347 m[7] + n[7], m[8] + n[8],
348 m[9] + n[9]);
349 }
350
352 {
353 m[0] += n[0];
354 m[1] += n[1];
355 m[2] += n[2];
356 m[3] += n[3];
357 m[4] += n[4];
358 m[5] += n[5];
359 m[6] += n[6];
360 m[7] += n[7];
361 m[8] += n[8];
362 m[9] += n[9];
363 return *this;
364 }
365
366 double m[10];
367};
368///////////////////////////////////////////
369
370namespace Simplify
371{
372 // Global Variables & Strctures
374 {
378 COLOR = 8
379 };
380 struct Triangle
381 {
382 int v[3];
383 double err[4];
388 };
396 struct Ref
397 {
399 };
400
402 {
403 public:
404 std::vector<Triangle> triangles;
405 std::vector<Vertex> vertices;
406 std::vector<Ref> refs;
407 std::string mtllib;
408 std::vector<std::string> materials;
409
410 // Helper functions
411
412 //
413 // Main simplification function
414 //
415 // target_count : target nr. of triangles
416 // agressiveness : sharpness to increase the threshold.
417 // 5..8 are good numbers
418 // more iterations yield higher quality
419 //
420
421 void simplify_mesh(int target_count, double agressiveness = 7, bool verbose = false)
422 {
423 // init
424 loopi(0, triangles.size())
425 {
426 triangles[i].deleted = 0;
427 }
428
429 // main iteration loop
430 int deleted_triangles = 0;
431 std::vector<int> deleted0, deleted1;
432 int triangle_count = static_cast<int>(triangles.size());
433 // int iteration = 0;
434 // loop(iteration,0,100)
435 for (int iteration = 0; iteration < 100; iteration++)
436 {
437 if (triangle_count - deleted_triangles <= target_count)
438 break;
439
440 // update mesh once in a while
441 if (iteration % 5 == 0)
442 {
443 update_mesh(iteration);
444 }
445
446 // clear dirty flag
447 loopi(0, triangles.size()) triangles[i].dirty = 0;
448
449 //
450 // All triangles with edges below the threshold will be removed
451 //
452 // The following numbers works well for most models.
453 // If it does not, try to adjust the 3 parameters
454 //
455 double threshold = 0.000000001 * pow(double(iteration + 3), agressiveness);
456
457 // target number of triangles reached ? Then break
458 if ((verbose) && (iteration % 5 == 0))
459 {
460 printf("iteration %d - triangles %d threshold %g\n", iteration, triangle_count - deleted_triangles, threshold);
461 }
462
463 // remove vertices & mark deleted triangles
464 loopi(0, triangles.size())
465 {
466 Triangle &t = triangles[i];
467 if (t.err[3] > threshold)
468 continue;
469 if (t.deleted)
470 continue;
471 if (t.dirty)
472 continue;
473
474 loopj(0, 3) if (t.err[j] < threshold)
475 {
476
477 int i0 = t.v[j];
478 Vertex &v0 = vertices[static_cast<size_t>(i0)];
479 int i1 = t.v[(j + 1) % 3];
480 Vertex &v1 = vertices[static_cast<size_t>(i1)];
481 // Border check
482 if (v0.border || v1.border)
483 continue;
484
485 // Compute vertex to collapse to
486 vec3f p;
487 calculate_error(i0, i1, p);
488 deleted0.resize(static_cast<size_t>(v0.tcount)); // normals temporarily
489 deleted1.resize(static_cast<size_t>(v1.tcount)); // normals temporarily
490 // don't remove if flipped
491 if (flipped(p, i0, i1, v0, v1, deleted0))
492 continue;
493
494 if (flipped(p, i1, i0, v1, v0, deleted1))
495 continue;
496
497 if ((t.attr & TEXCOORD) == TEXCOORD)
498 {
499 update_uvs(i0, v0, p, deleted0);
500 update_uvs(i0, v1, p, deleted1);
501 }
502
503 // not flipped, so remove edge
504 v0.p = p;
505 v0.q = v1.q + v0.q;
506 int tstart = static_cast<int>(refs.size());
507
508 update_triangles(i0, v0, deleted0, deleted_triangles);
509 update_triangles(i0, v1, deleted1, deleted_triangles);
510
511 int tcount = static_cast<int>(refs.size()) - tstart;
512
513 if (tcount <= v0.tcount)
514 {
515 // save ram
516 if (tcount)
517 memcpy(&refs[static_cast<size_t>(v0.tstart)], &refs[static_cast<size_t>(tstart)], static_cast<size_t>(tcount) * sizeof(Ref));
518 }
519 else
520 // append
521 v0.tstart = tstart;
522
523 v0.tcount = tcount;
524 break;
525 }
526 // done?
527 if (triangle_count - deleted_triangles <= target_count)
528 break;
529 }
530 }
531 // clean up mesh
532 compact_mesh();
533 } // simplify_mesh()
534
535 void simplify_mesh_lossless(bool verbose = false)
536 {
537 // init
538 loopi(0, triangles.size()) triangles[i].deleted = 0;
539
540 // main iteration loop
541 int deleted_triangles = 0;
542 std::vector<int> deleted0, deleted1;
543
544 // int iteration = 0;
545 // loop(iteration,0,100)
546 for (int iteration = 0; iteration < 9999; iteration++)
547 {
548 // update mesh constantly
549 update_mesh(iteration);
550 // clear dirty flag
551 loopi(0, triangles.size()) triangles[i].dirty = 0;
552 //
553 // All triangles with edges below the threshold will be removed
554 //
555 // The following numbers works well for most models.
556 // If it does not, try to adjust the 3 parameters
557 //
558 double threshold = DBL_EPSILON; // 1.0E-3 EPS;
559 if (verbose)
560 {
561 printf("lossless iteration %d\n", iteration);
562 }
563
564 // remove vertices & mark deleted triangles
565 loopi(0, triangles.size())
566 {
567 Triangle &t = triangles[i];
568 if (t.err[3] > threshold)
569 continue;
570 if (t.deleted)
571 continue;
572 if (t.dirty)
573 continue;
574
575 loopj(0, 3) if (t.err[j] < threshold)
576 {
577 int i0 = t.v[j];
578 Vertex &v0 = vertices[static_cast<size_t>(i0)];
579 int i1 = t.v[(j + 1) % 3];
580 Vertex &v1 = vertices[static_cast<size_t>(i1)];
581
582 // Border check
583 if (v0.border != v1.border)
584 continue;
585
586 // Compute vertex to collapse to
587 vec3f p;
588 calculate_error(i0, i1, p);
589
590 deleted0.resize(static_cast<size_t>(v0.tcount)); // normals temporarily
591 deleted1.resize(static_cast<size_t>(v1.tcount)); // normals temporarily
592
593 // don't remove if flipped
594 if (flipped(p, i0, i1, v0, v1, deleted0))
595 continue;
596 if (flipped(p, i1, i0, v1, v0, deleted1))
597 continue;
598
599 if ((t.attr & TEXCOORD) == TEXCOORD)
600 {
601 update_uvs(i0, v0, p, deleted0);
602 update_uvs(i0, v1, p, deleted1);
603 }
604
605 // not flipped, so remove edge
606 v0.p = p;
607 v0.q = v1.q + v0.q;
608 int tstart = static_cast<int>(refs.size());
609
610 update_triangles(i0, v0, deleted0, deleted_triangles);
611 update_triangles(i0, v1, deleted1, deleted_triangles);
612
613 int tcount = static_cast<int>(refs.size()) - tstart;
614
615 if (tcount <= v0.tcount)
616 {
617 // save ram
618 if (tcount)
619 memcpy(&refs[static_cast<size_t>(v0.tstart)], &refs[static_cast<size_t>(tstart)], static_cast<size_t>(tcount) * sizeof(Ref));
620 }
621 else
622 // append
623 v0.tstart = tstart;
624
625 v0.tcount = tcount;
626 break;
627 }
628 }
629 if (deleted_triangles <= 0)
630 break;
631 deleted_triangles = 0;
632 } // for each iteration
633 // clean up mesh
634 compact_mesh();
635 } // simplify_mesh_lossless()
636
637 // Check if a triangle flips when this edge is removed
638
639 bool flipped(vec3f p, int /*i0*/, int i1, Vertex &v0, Vertex &/*v1*/, std::vector<int> &deleted)
640 {
641
642 loopk(0, static_cast<size_t>(v0.tcount))
643 {
644 Triangle &t = triangles[static_cast<size_t>(refs[static_cast<size_t>(v0.tstart) + k].tid)];
645 if (t.deleted)
646 continue;
647
648 int s = refs[static_cast<size_t>(v0.tstart) + k].tvertex;
649 int id1 = t.v[(s + 1) % 3];
650 int id2 = t.v[(s + 2) % 3];
651
652 if (id1 == i1 || id2 == i1) // delete ?
653 {
654
655 deleted[k] = 1;
656 continue;
657 }
658 vec3f d1 = vertices[static_cast<size_t>(id1)].p - p;
659 d1.normalize();
660 vec3f d2 = vertices[static_cast<size_t>(id2)].p - p;
661 d2.normalize();
662 if (fabs(d1.dot(d2)) > 0.999)
663 return true;
664 vec3f n;
665 n.cross(d1, d2);
666 n.normalize();
667 deleted[k] = 0;
668 if (n.dot(t.n) < 0.2)
669 return true;
670 }
671 return false;
672 }
673
674 // update_uvs
675
676 void update_uvs(int /*i0*/, const Vertex &v, const vec3f &p, std::vector<int> &deleted)
677 {
678 loopk(0, static_cast<size_t>(v.tcount))
679 {
680 Ref &r = refs[static_cast<size_t>(v.tstart) + k];
681 Triangle &t = triangles[static_cast<size_t>(r.tid)];
682 if (t.deleted)
683 continue;
684 if (deleted[k])
685 continue;
686 vec3f p1 = vertices[static_cast<size_t>(t.v[0])].p;
687 vec3f p2 = vertices[static_cast<size_t>(t.v[1])].p;
688 vec3f p3 = vertices[static_cast<size_t>(t.v[2])].p;
689 t.uvs[static_cast<size_t>(r.tvertex)] = interpolate(p, p1, p2, p3, t.uvs);
690 }
691 }
692
693 // Update triangle connections and edge error after a edge is collapsed
694
695 void update_triangles(int i0, Vertex &v, std::vector<int> &deleted, int &deleted_triangles)
696 {
697 vec3f p;
698 loopk(0, static_cast<size_t>(v.tcount))
699 {
700 Ref &r = refs[static_cast<size_t>(v.tstart) + k];
701 Triangle &t = triangles[static_cast<size_t>(r.tid)];
702 if (t.deleted)
703 continue;
704 if (deleted[k])
705 {
706 t.deleted = 1;
707 deleted_triangles++;
708 continue;
709 }
710 t.v[static_cast<size_t>(r.tvertex)] = i0;
711 t.dirty = 1;
712 t.err[0] = calculate_error(t.v[0], t.v[1], p);
713 t.err[1] = calculate_error(t.v[1], t.v[2], p);
714 t.err[2] = calculate_error(t.v[2], t.v[0], p);
715 t.err[3] = min(t.err[0], min(t.err[1], t.err[2]));
716 refs.push_back(r);
717 }
718 }
719
720 // compact triangles, compute edge error and build reference list
721
722 void update_mesh(int iteration)
723 {
724 if (iteration > 0) // compact triangles
725 {
726 size_t dst = 0;
727 loopi(0, triangles.size()) if (!triangles[i].deleted)
728 {
729 triangles[dst++] = triangles[i];
730 }
731 triangles.resize(dst);
732 }
733 //
734
735 // Init Reference ID list
736 loopi(0, vertices.size())
737 {
738 vertices[i].tstart = 0;
739 vertices[i].tcount = 0;
740 }
741
742 loopi(0, triangles.size())
743 {
744 Triangle &t = triangles[i];
745 loopj(0, 3) vertices[static_cast<size_t>(t.v[j])].tcount++;
746 }
747 int tstart = 0;
748 loopi(0, vertices.size())
749 {
750 Vertex &v = vertices[i];
751 v.tstart = tstart;
752 tstart += v.tcount;
753 v.tcount = 0;
754 }
755
756 // Write References
757 refs.resize(triangles.size() * 3);
758 loopi(0, triangles.size())
759 {
760 Triangle &t = triangles[i];
761 loopj(0, 3)
762 {
763 Vertex &v = vertices[static_cast<size_t>(t.v[j])];
764 refs[static_cast<size_t>(v.tstart + v.tcount)].tid = static_cast<int>(i);
765 refs[static_cast<size_t>(v.tstart + v.tcount)].tvertex = static_cast<int>(j);
766 v.tcount++;
767 }
768 }
769
770 // Init Quadrics by Plane & Edge Errors
771 //
772 // required at the beginning ( iteration == 0 )
773 // recomputing during the simplification is not required,
774 // but mostly improves the result for closed meshes
775 //
776 if (iteration == 0)
777 {
778 // Identify boundary : vertices[].border=0,1
779
780 std::vector<int> vcount, vids;
781
782 loopi(0, vertices.size())
783 vertices[i]
784 .border = 0;
785
786 loopi(0, vertices.size())
787 {
788 Vertex &v = vertices[i];
789 vcount.clear();
790 vids.clear();
791 loopj(0, static_cast<size_t>(v.tcount))
792 {
793 int k = refs[static_cast<size_t>(v.tstart) + j].tid;
794 Triangle &t = triangles[static_cast<size_t>(k)];
795 loopk(0, 3)
796 {
797 size_t ofs = 0;
798 int id = t.v[k];
799 while (ofs < vcount.size())
800 {
801 if (vids[ofs] == id)
802 break;
803 ofs++;
804 }
805 if (ofs == vcount.size())
806 {
807 vcount.push_back(1);
808 vids.push_back(id);
809 }
810 else
811 vcount[ofs]++;
812 }
813 }
814 loopj(0, vcount.size()) if (vcount[j] == 1)
815 vertices[static_cast<size_t>(vids[j])]
816 .border = 1;
817 }
818 // initialize errors
819 loopi(0, vertices.size())
820 vertices[i]
821 .q = SymetricMatrix(0.0);
822
823 loopi(0, triangles.size())
824 {
825 Triangle &t = triangles[i];
826 vec3f n, p[3];
827 loopj(0, 3) p[j] = vertices[static_cast<size_t>(t.v[j])].p;
828 n.cross(p[1] - p[0], p[2] - p[0]);
829 n.normalize();
830 t.n = n;
831 loopj(0, 3) vertices[static_cast<size_t>(t.v[j])].q =
832 vertices[static_cast<size_t>(t.v[j])].q + SymetricMatrix(n.x, n.y, n.z, -n.dot(p[0]));
833 }
834 loopi(0, triangles.size())
835 {
836 // Calc Edge Error
837 Triangle &t = triangles[i];
838 vec3f p;
839 loopj(0, 3) t.err[j] = calculate_error(t.v[j], t.v[(j + 1) % 3], p);
840 t.err[3] = min(t.err[0], min(t.err[1], t.err[2]));
841 }
842 }
843 }
844
845 // Finally compact mesh before exiting
846
848 {
849 size_t dst = 0;
850 loopi(0, vertices.size())
851 {
852 vertices[i].tcount = 0;
853 }
854 loopi(0, triangles.size()) if (!triangles[i].deleted)
855 {
856 Triangle &t = triangles[i];
857 triangles[dst++] = t;
858 loopj(0, 3) vertices[static_cast<size_t>(t.v[j])].tcount = 1;
859 }
860 triangles.resize(dst);
861 dst = 0;
862 loopi(0, vertices.size()) if (vertices[i].tcount)
863 {
864 vertices[i].tstart = static_cast<int>(dst);
865 vertices[dst].p = vertices[i].p;
866 dst++;
867 }
868 loopi(0, triangles.size())
869 {
870 Triangle &t = triangles[i];
871 loopj(0, 3) t.v[j] = vertices[static_cast<size_t>(t.v[j])].tstart;
872 }
873 vertices.resize(dst);
874 }
875
876 // Error between vertex and Quadric
877
878 double vertex_error(SymetricMatrix q, double x, double y, double z)
879 {
880 return q[0] * x * x + 2 * q[1] * x * y + 2 * q[2] * x * z + 2 * q[3] * x + q[4] * y * y + 2 * q[5] * y * z + 2 * q[6] * y + q[7] * z * z + 2 * q[8] * z + q[9];
881 }
882
883 // Error for one edge
884
885 double calculate_error(int id_v1, int id_v2, vec3f &p_result)
886 {
887 // compute interpolated vertex
888
889 SymetricMatrix q = vertices[static_cast<size_t>(id_v1)].q + vertices[static_cast<size_t>(id_v2)].q;
890 bool border = vertices[static_cast<size_t>(id_v1)].border & vertices[static_cast<size_t>(id_v2)].border;
891 double error = 0;
892 double det = q.det(0, 1, 2, 1, 4, 5, 2, 5, 7);
893 if (det != 0 && !border)
894 {
895
896 // q_delta is invertible
897 p_result.x = -1 / det * (q.det(1, 2, 3, 4, 5, 6, 5, 7, 8)); // vx = A41/det(q_delta)
898 p_result.y = 1 / det * (q.det(0, 2, 3, 1, 5, 6, 2, 7, 8)); // vy = A42/det(q_delta)
899 p_result.z = -1 / det * (q.det(0, 1, 3, 1, 4, 6, 2, 5, 8)); // vz = A43/det(q_delta)
900
901 error = vertex_error(q, p_result.x, p_result.y, p_result.z);
902 }
903 else
904 {
905 // det = 0 -> try to find best result
906 vec3f p1 = vertices[static_cast<size_t>(id_v1)].p;
907 vec3f p2 = vertices[static_cast<size_t>(id_v2)].p;
908 vec3f p3 = (p1 + p2) / 2;
909 double error1 = vertex_error(q, p1.x, p1.y, p1.z);
910 double error2 = vertex_error(q, p2.x, p2.y, p2.z);
911 double error3 = vertex_error(q, p3.x, p3.y, p3.z);
912 error = min(error1, min(error2, error3));
913 if (error1 == error)
914 p_result = p1;
915 if (error2 == error)
916 p_result = p2;
917 if (error3 == error)
918 p_result = p3;
919 }
920 return error;
921 }
922
923 char *trimwhitespace(char *str)
924 {
925 char *end;
926
927 // Trim leading space
928 while (isspace(static_cast<unsigned char>(*str)))
929 str++;
930
931 if (*str == 0) // All spaces?
932 return str;
933
934 // Trim trailing space
935 end = str + strlen(str) - 1;
936 while (end > str && isspace(static_cast<unsigned char>(*end)))
937 end--;
938
939 // Write new null terminator
940 *(end + 1) = 0;
941
942 return str;
943 }
944
945 // Option : Load OBJ
946 void load_obj(const char *filename, bool process_uv = false)
947 {
948 vertices.clear();
949 triangles.clear();
950 // printf ( "Loading Objects %s ... \n",filename);
951 FILE *fn;
952 if (filename == NULL)
953 return;
954 if (static_cast<char>(filename[0]) == 0)
955 return;
956 if ((fn = fopen(filename, "rb")) == NULL)
957 {
958 printf("File %s not found!\n", filename);
959 return;
960 }
961 char line[1000];
962 memset(line, 0, 1000);
963 int vertex_cnt = 0;
964 int material = -1;
965 std::map<std::string, int> material_map;
966 std::vector<vec3f> uvs;
967 std::vector<std::vector<int>> uvMap;
968
969 while (fgets(line, 1000, fn) != NULL)
970 {
971 Vertex v;
972 vec3f uv;
973
974 if (strncmp(line, "mtllib", 6) == 0)
975 {
976 mtllib = trimwhitespace(&line[7]);
977 }
978 if (strncmp(line, "usemtl", 6) == 0)
979 {
980 std::string usemtl = trimwhitespace(&line[7]);
981 if (material_map.find(usemtl) == material_map.end())
982 {
983 material_map[usemtl] = static_cast<int>(materials.size());
984 materials.push_back(usemtl);
985 }
986 material = material_map[usemtl];
987 }
988
989 if (line[0] == 'v' && line[1] == 't')
990 {
991 if (line[2] == ' ')
992 {
993 if (sscanf(line, "vt %lf %lf",
994 &uv.x, &uv.y) == 2)
995 {
996 uv.z = 0;
997 uvs.push_back(uv);
998 }
999 else if (sscanf(line, "vt %lf %lf %lf",
1000 &uv.x, &uv.y, &uv.z) == 3)
1001 {
1002 uvs.push_back(uv);
1003 }
1004 }
1005 }
1006 else if (line[0] == 'v')
1007 {
1008 if (line[1] == ' ')
1009 if (sscanf(line, "v %lf %lf %lf",
1010 &v.p.x, &v.p.y, &v.p.z) == 3)
1011 {
1012 vertices.push_back(v);
1013 }
1014 }
1015 int integers[9];
1016 if (line[0] == 'f')
1017 {
1018 Triangle t;
1019 bool tri_ok = false;
1020 bool has_uv = false;
1021
1022 if (sscanf(line, "f %d %d %d",
1023 &integers[0], &integers[1], &integers[2]) == 3)
1024 {
1025 tri_ok = true;
1026 }
1027 else if (sscanf(line, "f %d// %d// %d//",
1028 &integers[0], &integers[1], &integers[2]) == 3)
1029 {
1030 tri_ok = true;
1031 }
1032 else if (sscanf(line, "f %d//%d %d//%d %d//%d",
1033 &integers[0], &integers[3],
1034 &integers[1], &integers[4],
1035 &integers[2], &integers[5]) == 6)
1036 {
1037 tri_ok = true;
1038 }
1039 else if (sscanf(line, "f %d/%d/%d %d/%d/%d %d/%d/%d",
1040 &integers[0], &integers[6], &integers[3],
1041 &integers[1], &integers[7], &integers[4],
1042 &integers[2], &integers[8], &integers[5]) == 9)
1043 {
1044 tri_ok = true;
1045 has_uv = true;
1046 }
1047 else // Add Support for v/vt only meshes
1048 if (sscanf(line, "f %d/%d %d/%d %d/%d",
1049 &integers[0], &integers[6],
1050 &integers[1], &integers[7],
1051 &integers[2], &integers[8]) == 6)
1052 {
1053 tri_ok = true;
1054 has_uv = true;
1055 }
1056 else
1057 {
1058 printf("unrecognized sequence\n");
1059 printf("%s\n", line);
1060 while (1)
1061 ;
1062 }
1063 if (tri_ok)
1064 {
1065 t.v[0] = integers[0] - 1 - vertex_cnt;
1066 t.v[1] = integers[1] - 1 - vertex_cnt;
1067 t.v[2] = integers[2] - 1 - vertex_cnt;
1068 t.attr = 0;
1069
1070 if (process_uv && has_uv)
1071 {
1072 std::vector<int> indices;
1073 indices.push_back(integers[6] - 1 - vertex_cnt);
1074 indices.push_back(integers[7] - 1 - vertex_cnt);
1075 indices.push_back(integers[8] - 1 - vertex_cnt);
1076 uvMap.push_back(indices);
1077 t.attr |= TEXCOORD;
1078 }
1079
1080 t.material = material;
1081 // geo.triangles.push_back ( tri );
1082 triangles.push_back(t);
1083 // state_before = state;
1084 // state ='f';
1085 }
1086 }
1087 }
1088
1089 if (process_uv && uvs.size())
1090 {
1091 loopi(0, triangles.size())
1092 {
1093 loopj(0, 3)
1094 triangles[i]
1095 .uvs[j] = uvs[static_cast<size_t>(uvMap[i][j])];
1096 }
1097 }
1098
1099 fclose(fn);
1100
1101 // printf("load_obj: vertices = %lu, triangles = %lu, uvs = %lu\n", vertices.size(), triangles.size(), uvs.size() );
1102 } // load_obj()
1103
1104 // Optional : Store as OBJ
1105
1106 void write_obj(const char *filename)
1107 {
1108 FILE *file = fopen(filename, "w");
1109 bool has_uv = (triangles.size() && (triangles[0].attr & TEXCOORD) == TEXCOORD);
1110
1111 if (!file)
1112 {
1113 printf("write_obj: can't write data file \"%s\".\n", filename);
1114 exit(0);
1115 }
1116 if (!mtllib.empty())
1117 {
1118 fprintf(file, "mtllib %s\n", mtllib.c_str());
1119 }
1120 loopi(0, vertices.size())
1121 {
1122 // fprintf(file, "v %lf %lf %lf\n", vertices[i].p.x,vertices[i].p.y,vertices[i].p.z);
1123 fprintf(file, "v %g %g %g\n", vertices[i].p.x, vertices[i].p.y, vertices[i].p.z); // more compact: remove trailing zeros
1124 }
1125 if (has_uv)
1126 {
1127 loopi(0, triangles.size()) if (!triangles[i].deleted)
1128 {
1129 fprintf(file, "vt %g %g\n", triangles[i].uvs[0].x, triangles[i].uvs[0].y);
1130 fprintf(file, "vt %g %g\n", triangles[i].uvs[1].x, triangles[i].uvs[1].y);
1131 fprintf(file, "vt %g %g\n", triangles[i].uvs[2].x, triangles[i].uvs[2].y);
1132 }
1133 }
1134 int uv = 1;
1135 loopi(0, triangles.size()) if (!triangles[i].deleted)
1136 {
1137 if (has_uv)
1138 {
1139 fprintf(file, "f %d/%d %d/%d %d/%d\n", triangles[i].v[0] + 1, uv, triangles[i].v[1] + 1, uv + 1, triangles[i].v[2] + 1, uv + 2);
1140 uv += 3;
1141 }
1142 else
1143 {
1144 fprintf(file, "f %d %d %d\n", triangles[i].v[0] + 1, triangles[i].v[1] + 1, triangles[i].v[2] + 1);
1145 }
1146 // fprintf(file, "f %d// %d// %d//\n", triangles[i].v[0]+1, triangles[i].v[1]+1, triangles[i].v[2]+1); //more compact: remove trailing zeros
1147 }
1148 fclose(file);
1149 }
1150 };
1151
1152}
1153///////////////////////////////////////////
float y
float x
float z
double min(double v1, double v2)
Definition Simplify.h:285
#define loopk(start_l, end_l)
Definition Simplify.h:28
vec3f interpolate(const vec3f &p, const vec3f &a, const vec3f &b, const vec3f &c, const vec3f attrs[3])
Definition Simplify.h:275
#define loopj(start_l, end_l)
Definition Simplify.h:27
#define loopi(start_l, end_l)
Definition Simplify.h:26
vec3f barycentric(const vec3f &p, const vec3f &a, const vec3f &b, const vec3f &c)
Definition Simplify.h:258
void simplify_mesh_lossless(bool verbose=false)
Definition Simplify.h:535
bool flipped(vec3f p, int, int i1, Vertex &v0, Vertex &, std::vector< int > &deleted)
Definition Simplify.h:639
void write_obj(const char *filename)
Definition Simplify.h:1106
void update_mesh(int iteration)
Definition Simplify.h:722
double calculate_error(int id_v1, int id_v2, vec3f &p_result)
Definition Simplify.h:885
std::vector< std::string > materials
Definition Simplify.h:408
std::vector< Triangle > triangles
Definition Simplify.h:404
std::vector< Vertex > vertices
Definition Simplify.h:405
char * trimwhitespace(char *str)
Definition Simplify.h:923
void update_uvs(int, const Vertex &v, const vec3f &p, std::vector< int > &deleted)
Definition Simplify.h:676
std::vector< Ref > refs
Definition Simplify.h:406
void load_obj(const char *filename, bool process_uv=false)
Definition Simplify.h:946
void simplify_mesh(int target_count, double agressiveness=7, bool verbose=false)
Definition Simplify.h:421
void update_triangles(int i0, Vertex &v, std::vector< int > &deleted, int &deleted_triangles)
Definition Simplify.h:695
double vertex_error(SymetricMatrix q, double x, double y, double z)
Definition Simplify.h:878
SymetricMatrix & operator+=(const SymetricMatrix &n)
Definition Simplify.h:351
SymetricMatrix(double a, double b, double c, double d)
Definition Simplify.h:317
double m[10]
Definition Simplify.h:366
double det(int a11, int a12, int a13, int a21, int a22, int a23, int a31, int a32, int a33)
Definition Simplify.h:335
const SymetricMatrix operator+(const SymetricMatrix &n) const
Definition Simplify.h:343
SymetricMatrix(double c=0)
Definition Simplify.h:296
SymetricMatrix(double m11, double m12, double m13, double m14, double m22, double m23, double m24, double m33, double m34, double m44)
Definition Simplify.h:298
double operator[](int c) const
Definition Simplify.h:331
static double fn[10]
Definition odrSpiral.cpp:82
SymetricMatrix q
Definition Simplify.h:393
double y
Definition Simplify.h:37
vec3f rot_y(double a)
Definition Simplify.h:166
vec3f random01_fxyz()
Definition Simplify.h:249
vec3f operator/(const double a) const
Definition Simplify.h:108
static int random_number
Definition Simplify.h:240
vec3f rot_x(double a)
Definition Simplify.h:158
vec3f frac()
Definition Simplify.h:204
vec3f operator*(const double a) const
Definition Simplify.h:67
void clamp(double min, double max)
Definition Simplify.h:174
vec3f operator=(const vec3f a)
Definition Simplify.h:90
static double random_double()
vec3f operator*(const vec3f a) const
Definition Simplify.h:72
vec3f(void)
Definition Simplify.h:39
static void random_init()
double length() const
Definition Simplify.h:220
vec3f integer()
Definition Simplify.h:212
vec3f(const vec3f &a)
Definition Simplify.h:41
double angle2(const vec3f &v, const vec3f &w)
Definition Simplify.h:141
vec3f invert()
Definition Simplify.h:197
double dot(const vec3f &a) const
Definition Simplify.h:113
vec3f(vector3 a)
Definition Simplify.h:43
vec3f operator/(const vec3f a) const
Definition Simplify.h:98
double z
Definition Simplify.h:37
vec3f operator=(const vector3 a)
Definition Simplify.h:82
vec3f rot_z(double a)
Definition Simplify.h:189
static vec3f normalize(vec3f a)
vec3f cross(const vec3f &a, const vec3f &b)
Definition Simplify.h:118
double angle(const vec3f &v)
Definition Simplify.h:126
vec3f operator-(const vec3f &a) const
Definition Simplify.h:103
double random_double_01(double a)
Definition Simplify.h:242
vec3f operator+(const vec3f &a) const
Definition Simplify.h:57
vec3f normalize(double=1)
Definition Simplify.h:225
vec3f(const double X, const double Y, const double Z)
Definition Simplify.h:50
static vec3f random()
double x
Definition Simplify.h:37
vec3f v3() const
Definition Simplify.h:77
vec3f operator+=(const vec3f &a) const
Definition Simplify.h:62
double y
Definition Simplify.h:32
double z
Definition Simplify.h:32
double x
Definition Simplify.h:32