Subversion Repositories gelsvn

Rev

Rev 595 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 595 Rev 601
1
/* ----------------------------------------------------------------------- *
1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
5
 * ----------------------------------------------------------------------- */
6
 
6
 
7
#include "quadric_simplify.h"
7
#include "quadric_simplify.h"
8
 
8
 
9
#include <queue>
9
#include <queue>
10
#include <iostream>
10
#include <iostream>
11
#include <CGLA/Vec3d.h>
11
#include "../CGLA/Vec3d.h"
12
#include <Geometry/QEM.h>
12
#include "../Geometry/QEM.h"
13
 
13
 
14
#include "Manifold.h"
14
#include "Manifold.h"
15
#include "AttributeVector.h"
15
#include "AttributeVector.h"
16
#include "smooth.h"
16
#include "smooth.h"
17
 
17
 
18
 
18
 
19
namespace HMesh
19
namespace HMesh
20
{
20
{
21
	using namespace std;
21
	using namespace std;
22
	using namespace CGLA;
22
	using namespace CGLA;
23
    using namespace Geometry;
23
    using namespace Geometry;
24
    
24
    
25
    namespace
25
    namespace
26
    {
26
    {
27
        /* We create a record for each halfedge where we can keep its time
27
        /* We create a record for each halfedge where we can keep its time
28
         stamp. If the time stamp on the halfedge record is bigger than
28
         stamp. If the time stamp on the halfedge record is bigger than
29
         the stamp on the simplification record, we cannot use the 
29
         the stamp on the simplification record, we cannot use the 
30
         simplification record (see below). */
30
         simplification record (see below). */
31
        struct HalfEdgeRec
31
        struct HalfEdgeRec
32
        {
32
        {
33
            HalfEdgeID h;
33
            HalfEdgeID h;
34
            int time_stamp;
34
            int time_stamp;
35
            void halfedge_removed() {time_stamp = -1;}
35
            void halfedge_removed() {time_stamp = -1;}
36
            HalfEdgeRec(): time_stamp(0) {}
36
            HalfEdgeRec(): time_stamp(0) {}
37
        };
37
        };
38
        
38
        
39
        /* The simpliciation record contains information about a potential
39
        /* The simpliciation record contains information about a potential
40
         edge contraction */
40
         edge contraction */
41
        struct SimplifyRec
41
        struct SimplifyRec
42
        {
42
        {
43
            Vec3d opt_pos;  // optimal vertex position
43
            Vec3d opt_pos;  // optimal vertex position
44
            HalfEdgeID h;   // Index (into HalfEdgeRec vector) of edge
44
            HalfEdgeID h;   // Index (into HalfEdgeRec vector) of edge
45
            // we want to contract
45
            // we want to contract
46
            float err;      // Error associated with contraction
46
            float err;      // Error associated with contraction
47
            int time_stamp; // Time stamp (see comment on HalfEdgeRec)
47
            int time_stamp; // Time stamp (see comment on HalfEdgeRec)
48
            int visits;     // Visits (number of times we considered this 
48
            int visits;     // Visits (number of times we considered this 
49
            // record).
49
            // record).
50
        };
50
        };
51
        
51
        
52
        bool operator<(const SimplifyRec& s1, const SimplifyRec& s2)
52
        bool operator<(const SimplifyRec& s1, const SimplifyRec& s2)
53
        {
53
        {
54
            return s1.err > s2.err;
54
            return s1.err > s2.err;
55
        }
55
        }
56
        
56
        
57
        class QuadricSimplifier
57
        class QuadricSimplifier
58
        {
58
        {
59
            typedef priority_queue<SimplifyRec> SimplifyQueue;
59
            typedef priority_queue<SimplifyRec> SimplifyQueue;
60
            typedef VertexAttributeVector<QEM> QEMVec;
60
            typedef VertexAttributeVector<QEM> QEMVec;
61
            typedef HalfEdgeAttributeVector<HalfEdgeRec> HalfEdgeVec;
61
            typedef HalfEdgeAttributeVector<HalfEdgeRec> HalfEdgeVec;
62
            typedef VertexAttributeVector<int> CollapseMask;
62
            typedef VertexAttributeVector<int> CollapseMask;
63
            
63
            
64
            Manifold& m;
64
            Manifold& m;
65
            HalfEdgeVec halfedge_vec;
65
            HalfEdgeVec halfedge_vec;
66
            QEMVec qem_vec;
66
            QEMVec qem_vec;
67
            CollapseMask collapse_mask;
67
            CollapseMask collapse_mask;
68
            SimplifyQueue sim_queue;
68
            SimplifyQueue sim_queue;
69
            double singular_thresh;
69
            double singular_thresh;
70
            bool choose_optimal_positions;
70
            bool choose_optimal_positions;
71
            
71
            
72
            /* Compute the error associated with contraction of he and the
72
            /* Compute the error associated with contraction of he and the
73
             optimal position of resulting vertex. */
73
             optimal position of resulting vertex. */
74
            void push_simplify_rec(HalfEdgeID h);
74
            void push_simplify_rec(HalfEdgeID h);
75
            
75
            
76
            /* Check whether the contraction is valid. See below for details*/
76
            /* Check whether the contraction is valid. See below for details*/
77
            bool check_consistency(HalfEdgeID h, const Vec3d& opt_pos);
77
            bool check_consistency(HalfEdgeID h, const Vec3d& opt_pos);
78
            
78
            
79
            /* Update the time stamp of a halfedge. A halfedge and its opp edge
79
            /* Update the time stamp of a halfedge. A halfedge and its opp edge
80
             may have different stamps. We choose a stamp that is greater
80
             may have different stamps. We choose a stamp that is greater
81
             than either and assign to both.*/
81
             than either and assign to both.*/
82
            void update_time_stamp(HalfEdgeID h)
82
            void update_time_stamp(HalfEdgeID h)
83
            {
83
            {
84
				Walker w = m.walker(h);
84
				Walker w = m.walker(h);
85
				HalfEdgeID ho = w.opp().halfedge();
85
				HalfEdgeID ho = w.opp().halfedge();
86
                
86
                
87
                int time_stamp = s_max( halfedge_vec[h].time_stamp, halfedge_vec[ho].time_stamp);
87
                int time_stamp = s_max( halfedge_vec[h].time_stamp, halfedge_vec[ho].time_stamp);
88
                ++time_stamp;
88
                ++time_stamp;
89
                halfedge_vec[h].time_stamp = time_stamp;
89
                halfedge_vec[h].time_stamp = time_stamp;
90
                halfedge_vec[ho].time_stamp = time_stamp;
90
                halfedge_vec[ho].time_stamp = time_stamp;
91
            }
91
            }
92
            
92
            
93
            /* Update time stamps for all halfedges in one ring of vi */
93
            /* Update time stamps for all halfedges in one ring of vi */
94
            void update_onering_timestamp(VertexID v);
94
            void update_onering_timestamp(VertexID v);
95
            
95
            
96
            /* Perform a collapse - if conditions are met. Returns 1 or 0 
96
            /* Perform a collapse - if conditions are met. Returns 1 or 0 
97
             accordingly. */
97
             accordingly. */
98
            int collapse(SimplifyRec& simplify_rec);
98
            int collapse(SimplifyRec& simplify_rec);
99
            
99
            
100
        public:
100
        public:
101
            
101
            
102
            /* Create a simplifier for a manifold */
102
            /* Create a simplifier for a manifold */
103
            QuadricSimplifier(Manifold& _m, VertexAttributeVector<int> _collapse_mask,
103
            QuadricSimplifier(Manifold& _m, VertexAttributeVector<int> _collapse_mask,
104
                              double _singular_thresh, bool _choose_optimal_positions):
104
                              double _singular_thresh, bool _choose_optimal_positions):
105
            m(_m), 
105
            m(_m), 
106
            halfedge_vec(_m.allocated_halfedges()), 
106
            halfedge_vec(_m.allocated_halfedges()), 
107
            qem_vec(_m.allocated_vertices()),
107
            qem_vec(_m.allocated_vertices()),
108
            collapse_mask(_collapse_mask),
108
            collapse_mask(_collapse_mask),
109
            singular_thresh(_singular_thresh),
109
            singular_thresh(_singular_thresh),
110
            choose_optimal_positions(_choose_optimal_positions)
110
            choose_optimal_positions(_choose_optimal_positions)
111
            {}
111
            {}
112
            
112
            
113
            /* Simplify doing at most max_work contractions */
113
            /* Simplify doing at most max_work contractions */
114
            void reduce(long int max_work);
114
            void reduce(long int max_work);
115
        };
115
        };
116
        
116
        
117
        bool QuadricSimplifier::check_consistency(HalfEdgeID h, const Vec3d& opt_pos)
117
        bool QuadricSimplifier::check_consistency(HalfEdgeID h, const Vec3d& opt_pos)
118
        {
118
        {
119
			Walker w = m.walker(h);
119
			Walker w = m.walker(h);
120
            
120
            
121
            
121
            
122
            VertexID v0 = w.vertex();
122
            VertexID v0 = w.vertex();
123
            VertexID v1 = w.opp().vertex();
123
            VertexID v1 = w.opp().vertex();
124
            Vec3d p0(m.pos(v0));
124
            Vec3d p0(m.pos(v0));
125
            
125
            
126
            /* This test is inspired by Garland's Ph.D. thesis. We try
126
            /* This test is inspired by Garland's Ph.D. thesis. We try
127
             to detect whether flipped triangles will occur by sort of
127
             to detect whether flipped triangles will occur by sort of
128
             ensuring that the new vertex is in the hull of the one rings
128
             ensuring that the new vertex is in the hull of the one rings
129
             of the vertices at either end of the edge being contracted 
129
             of the vertices at either end of the edge being contracted 
130
             
130
             
131
             I also had an additional check intended to ensure that poor valencies
131
             I also had an additional check intended to ensure that poor valencies
132
             would not be introduced, but it seemed to be unnecessary.
132
             would not be introduced, but it seemed to be unnecessary.
133
             
133
             
134
             */
134
             */
135
            
135
            
136
			for(Walker w = m.walker(v0); !w.full_circle(); w = w.circulate_vertex_cw()){
136
			for(Walker w = m.walker(v0); !w.full_circle(); w = w.circulate_vertex_cw()){
137
                //ConstHalfEdgeHandle h = vc.halfedge();
137
                //ConstHalfEdgeHandle h = vc.halfedge();
138
                
138
                
139
                if(w.vertex()!= v1 && w.next().vertex() != v1){
139
                if(w.vertex()!= v1 && w.next().vertex() != v1){
140
                    Vec3d pa(m.pos(w.vertex()));
140
                    Vec3d pa(m.pos(w.vertex()));
141
                    Vec3d pb(m.pos(w.next().vertex()));
141
                    Vec3d pb(m.pos(w.next().vertex()));
142
                    
142
                    
143
                    Vec3d dir = normalize(pb - pa);
143
                    Vec3d dir = normalize(pb - pa);
144
                    
144
                    
145
                    Vec3d n = p0 - pa;
145
                    Vec3d n = p0 - pa;
146
                    n = n - dir * dot(dir,n);
146
                    n = n - dir * dot(dir,n);
147
                    
147
                    
148
                    if(dot(n,opt_pos - pa) <= 0)
148
                    if(dot(n,opt_pos - pa) <= 0)
149
                        return false;
149
                        return false;
150
                }
150
                }
151
            }
151
            }
152
            
152
            
153
            return true;
153
            return true;
154
        }
154
        }
155
        
155
        
156
        
156
        
157
        void QuadricSimplifier::push_simplify_rec(HalfEdgeID h)
157
        void QuadricSimplifier::push_simplify_rec(HalfEdgeID h)
158
        {
158
        {
159
			Walker w = m.walker(h);
159
			Walker w = m.walker(h);
160
            if(collapse_mask[w.opp().vertex()] == 0)
160
            if(collapse_mask[w.opp().vertex()] == 0)
161
            {
161
            {
162
                
162
                
163
                update_time_stamp(h);
163
                update_time_stamp(h);
164
                
164
                
165
                VertexID hv = w.vertex();
165
                VertexID hv = w.vertex();
166
                VertexID hov = w.opp().vertex();
166
                VertexID hov = w.opp().vertex();
167
                
167
                
168
                // Get QEM for both end points
168
                // Get QEM for both end points
169
                const QEM& Q1 = qem_vec[hv];
169
                const QEM& Q1 = qem_vec[hv];
170
                const QEM& Q2 = qem_vec[hov];
170
                const QEM& Q2 = qem_vec[hov];
171
                
171
                
172
                QEM q = Q1;
172
                QEM q = Q1;
173
                q += Q2;
173
                q += Q2;
174
                
174
                
175
                float err;
175
                float err;
176
                Vec3d opt_pos(0);
176
                Vec3d opt_pos(0);
177
                Vec3d opt_origin = Vec3d(m.pos(hv) + m.pos(hov)) * 0.5;
177
                Vec3d opt_origin = Vec3d(m.pos(hv) + m.pos(hov)) * 0.5;
178
                if(choose_optimal_positions)
178
                if(choose_optimal_positions)
179
                    opt_pos = q.opt_pos(singular_thresh,opt_origin);
179
                    opt_pos = q.opt_pos(singular_thresh,opt_origin);
180
                else
180
                else
181
                    opt_pos = Vec3d(m.pos(hv));
181
                    opt_pos = Vec3d(m.pos(hv));
182
                
182
                
183
                err = q.error(opt_pos);
183
                err = q.error(opt_pos);
184
                
184
                
185
                // Create SimplifyRec
185
                // Create SimplifyRec
186
                SimplifyRec simplify_rec;
186
                SimplifyRec simplify_rec;
187
                simplify_rec.opt_pos = opt_pos;
187
                simplify_rec.opt_pos = opt_pos;
188
                simplify_rec.err = err;
188
                simplify_rec.err = err;
189
                simplify_rec.h = h;
189
                simplify_rec.h = h;
190
                simplify_rec.time_stamp = halfedge_vec[h].time_stamp;
190
                simplify_rec.time_stamp = halfedge_vec[h].time_stamp;
191
                simplify_rec.visits = 0;
191
                simplify_rec.visits = 0;
192
                // push it.
192
                // push it.
193
                sim_queue.push(simplify_rec);
193
                sim_queue.push(simplify_rec);
194
            }
194
            }
195
        }
195
        }
196
        
196
        
197
        
197
        
198
        void QuadricSimplifier::update_onering_timestamp(VertexID v)
198
        void QuadricSimplifier::update_onering_timestamp(VertexID v)
199
        {
199
        {
200
            // For all emanating edges h
200
            // For all emanating edges h
201
			for(Walker w = m.walker(v); !w.full_circle(); w = w.circulate_vertex_cw())
201
			for(Walker w = m.walker(v); !w.full_circle(); w = w.circulate_vertex_cw())
202
                push_simplify_rec(w.halfedge());
202
                push_simplify_rec(w.halfedge());
203
        }
203
        }
204
        
204
        
205
        int QuadricSimplifier::collapse(SimplifyRec& simplify_rec)
205
        int QuadricSimplifier::collapse(SimplifyRec& simplify_rec)
206
        { 
206
        { 
207
            HalfEdgeID h = halfedge_vec[simplify_rec.h].h;
207
            HalfEdgeID h = halfedge_vec[simplify_rec.h].h;
208
            
208
            
209
			Walker w = m.walker(h);
209
			Walker w = m.walker(h);
210
            
210
            
211
            // Check the time stamp to verify that the simplification 
211
            // Check the time stamp to verify that the simplification 
212
            // record is the newest. If the halfedge has been removed
212
            // record is the newest. If the halfedge has been removed
213
            // the time stamp is -1 and the comparison will also fail.
213
            // the time stamp is -1 and the comparison will also fail.
214
            if(halfedge_vec[h].time_stamp == simplify_rec.time_stamp){
214
            if(halfedge_vec[h].time_stamp == simplify_rec.time_stamp){
215
				Walker wo = w.opp();
215
				Walker wo = w.opp();
216
                VertexID v = wo.vertex();
216
                VertexID v = wo.vertex();
217
                VertexID n = w.vertex();
217
                VertexID n = w.vertex();
218
                
218
                
219
                // If the edge is, in fact, collapsible
219
                // If the edge is, in fact, collapsible
220
                if(precond_collapse_edge(m, h)){      
220
                if(precond_collapse_edge(m, h)){      
221
                    // If our consistency checks pass, we are relatively
221
                    // If our consistency checks pass, we are relatively
222
                    // sure that the contraction does not lead to a face flip.
222
                    // sure that the contraction does not lead to a face flip.
223
                    if(check_consistency(h, simplify_rec.opt_pos) && check_consistency(wo.halfedge(), simplify_rec.opt_pos)){
223
                    if(check_consistency(h, simplify_rec.opt_pos) && check_consistency(wo.halfedge(), simplify_rec.opt_pos)){
224
                        //cout << simplify_rec.err << " " << &(*he->vert) << endl;
224
                        //cout << simplify_rec.err << " " << &(*he->vert) << endl;
225
                        // Get QEM for both end points
225
                        // Get QEM for both end points
226
                        const QEM& Q1 = qem_vec[n];
226
                        const QEM& Q1 = qem_vec[n];
227
                        const QEM& Q2 = qem_vec[v];
227
                        const QEM& Q2 = qem_vec[v];
228
                        
228
                        
229
                        // Compute Q_new = Q_1 + Q_2
229
                        // Compute Q_new = Q_1 + Q_2
230
                        QEM q = Q1;
230
                        QEM q = Q1;
231
                        q += Q2;
231
                        q += Q2;
232
                        
232
                        
233
                        // Mark all halfedges that will be removed as dead
233
                        // Mark all halfedges that will be removed as dead
234
                        halfedge_vec[w.halfedge()].halfedge_removed();
234
                        halfedge_vec[w.halfedge()].halfedge_removed();
235
                        halfedge_vec[wo.halfedge()].halfedge_removed();
235
                        halfedge_vec[wo.halfedge()].halfedge_removed();
236
                        
236
                        
237
                        if(w.next().next().next().halfedge() == h){
237
                        if(w.next().next().next().halfedge() == h){
238
                            halfedge_vec[w.next().halfedge()].halfedge_removed();
238
                            halfedge_vec[w.next().halfedge()].halfedge_removed();
239
                            halfedge_vec[w.next().next().halfedge()].halfedge_removed();
239
                            halfedge_vec[w.next().next().halfedge()].halfedge_removed();
240
                        }
240
                        }
241
                        if(wo.next().next().next().halfedge() == wo.halfedge()){
241
                        if(wo.next().next().next().halfedge() == wo.halfedge()){
242
                            halfedge_vec[wo.next().halfedge()].halfedge_removed();
242
                            halfedge_vec[wo.next().halfedge()].halfedge_removed();
243
                            halfedge_vec[wo.next().next().halfedge()].halfedge_removed();
243
                            halfedge_vec[wo.next().next().halfedge()].halfedge_removed();
244
                        }
244
                        }
245
                        
245
                        
246
                        // Do collapse
246
                        // Do collapse
247
                        m.collapse_edge(h);
247
                        m.collapse_edge(h);
248
                        m.pos(n) = simplify_rec.opt_pos;
248
                        m.pos(n) = simplify_rec.opt_pos;
249
                        qem_vec[n] = q;
249
                        qem_vec[n] = q;
250
                        
250
                        
251
                        update_onering_timestamp(n);
251
                        update_onering_timestamp(n);
252
                        return 1;
252
                        return 1;
253
                    }
253
                    }
254
                }
254
                }
255
                
255
                
256
                
256
                
257
                // If we are here, the collapse was not allowed. If we have
257
                // If we are here, the collapse was not allowed. If we have
258
                // seen this simplify record less than 100 times, we try to
258
                // seen this simplify record less than 100 times, we try to
259
                // increase the error and store the record again. Maybe some
259
                // increase the error and store the record again. Maybe some
260
                // other contractions will make it more digestible later.
260
                // other contractions will make it more digestible later.
261
                if(simplify_rec.visits < 100){
261
                if(simplify_rec.visits < 100){
262
                    simplify_rec.err *= 1.01f;
262
                    simplify_rec.err *= 1.01f;
263
                    ++simplify_rec.visits;
263
                    ++simplify_rec.visits;
264
                    sim_queue.push(simplify_rec);
264
                    sim_queue.push(simplify_rec);
265
                }
265
                }
266
            }
266
            }
267
            
267
            
268
            return 0;
268
            return 0;
269
        }
269
        }
270
        
270
        
271
        void QuadricSimplifier::reduce(long int max_work)
271
        void QuadricSimplifier::reduce(long int max_work)
272
        {
272
        {
273
            // Set t = 0 for all halfedges
273
            // Set t = 0 for all halfedges
274
            for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end(); ++h){
274
            for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end(); ++h){
275
                halfedge_vec[*h].h = *h;
275
                halfedge_vec[*h].h = *h;
276
            }
276
            }
277
            cout << "Computing quadrics" << endl;
277
            cout << "Computing quadrics" << endl;
278
            
278
            
279
            // For all vertices, compute quadric and store in qem_vec
279
            // For all vertices, compute quadric and store in qem_vec
280
            for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
280
            for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
281
                Vec3d p(m.pos(*v));
281
                Vec3d p(m.pos(*v));
282
                Vec3d vn(normal(m, *v));
282
                Vec3d vn(normal(m, *v));
283
                QEM q;
283
                QEM q;
284
				for(Walker w = m.walker(*v); !w.full_circle(); w = w.circulate_vertex_cw()){
284
				for(Walker w = m.walker(*v); !w.full_circle(); w = w.circulate_vertex_cw()){
285
                    FaceID f = w.face();
285
                    FaceID f = w.face();
286
                    if(f != InvalidFaceID){
286
                    if(f != InvalidFaceID){
287
                        Vec3d n(normal(m, f));
287
                        Vec3d n(normal(m, f));
288
                        double a = area(m, f);
288
                        double a = area(m, f);
289
                        q += QEM(p, n, a / 3.0);
289
                        q += QEM(p, n, a / 3.0);
290
                    }
290
                    }
291
                    if ((f == InvalidFaceID || w.opp().face() == InvalidFaceID ) && sqr_length(vn) > 0.0){
291
                    if ((f == InvalidFaceID || w.opp().face() == InvalidFaceID ) && sqr_length(vn) > 0.0){
292
                        Vec3d edge = Vec3d(m.pos(w.vertex())) - p;
292
                        Vec3d edge = Vec3d(m.pos(w.vertex())) - p;
293
                        double edge_len = sqr_length(edge); 
293
                        double edge_len = sqr_length(edge); 
294
                        if(edge_len > 0.0){
294
                        if(edge_len > 0.0){
295
                            Vec3d n = cross(vn, edge);
295
                            Vec3d n = cross(vn, edge);
296
                            q += QEM(p, n, 2*edge_len);
296
                            q += QEM(p, n, 2*edge_len);
297
                        }
297
                        }
298
                    }
298
                    }
299
                }
299
                }
300
                qem_vec[*v] = q;
300
                qem_vec[*v] = q;
301
            }
301
            }
302
            cout << "Pushing initial halfedges" << endl;
302
            cout << "Pushing initial halfedges" << endl;
303
            
303
            
304
            for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end(); ++h){
304
            for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end(); ++h){
305
                if(halfedge_vec[*h].time_stamp == 0)
305
                if(halfedge_vec[*h].time_stamp == 0)
306
                    push_simplify_rec(*h);
306
                    push_simplify_rec(*h);
307
            }
307
            }
308
            cout << "Simplify";
308
            cout << "Simplify";
309
            
309
            
310
            int work = 0;
310
            int work = 0;
311
            while(!sim_queue.empty() && work < max_work){
311
            while(!sim_queue.empty() && work < max_work){
312
                SimplifyRec simplify_record = sim_queue.top();
312
                SimplifyRec simplify_record = sim_queue.top();
313
                sim_queue.pop();
313
                sim_queue.pop();
314
                
314
                
315
                work += 2*collapse(simplify_record);
315
                work += 2*collapse(simplify_record);
316
                if((sim_queue.size() % 10000) == 0){
316
                if((sim_queue.size() % 10000) == 0){
317
                    cout << ".";
317
                    cout << ".";
318
                }
318
                }
319
//                cout << "work = " << work << endl;
319
//                cout << "work = " << work << endl;
320
//                cout << "sim Q size = " << sim_queue.size() << endl;
320
//                cout << "sim Q size = " << sim_queue.size() << endl;
321
            }
321
            }
322
            cout << endl;
322
            cout << endl;
323
        }
323
        }
324
    }
324
    }
325
    
325
    
326
    void quadric_simplify(Manifold& m, double keep_fraction, double singular_thresh, bool choose_optimal_positions)
326
    void quadric_simplify(Manifold& m, double keep_fraction, double singular_thresh, bool choose_optimal_positions)
327
    {
327
    {
328
        gel_srand(1210);
328
        gel_srand(1210);
329
        long int F = m.no_faces();
329
        long int F = m.no_faces();
330
        VertexAttributeVector<int> mask(m.no_faces(), 0);
330
        VertexAttributeVector<int> mask(m.no_faces(), 0);
331
        long int max_work = max(static_cast<long int>(0), F- static_cast<long int>(keep_fraction * F));
331
        long int max_work = max(static_cast<long int>(0), F- static_cast<long int>(keep_fraction * F));
332
        QuadricSimplifier qsim(m, mask, singular_thresh, choose_optimal_positions);
332
        QuadricSimplifier qsim(m, mask, singular_thresh, choose_optimal_positions);
333
        qsim.reduce(max_work);
333
        qsim.reduce(max_work);
334
    }
334
    }
335
    
335
    
336
    void quadric_simplify(Manifold& m, VertexAttributeVector<int> mask, double keep_fraction, double singular_thresh, bool choose_optimal_positions)
336
    void quadric_simplify(Manifold& m, VertexAttributeVector<int> mask, double keep_fraction, double singular_thresh, bool choose_optimal_positions)
337
    {
337
    {
338
        gel_srand(1210);
338
        gel_srand(1210);
339
        long int F = m.no_faces();
339
        long int F = m.no_faces();
340
        long int max_work = keep_fraction == 0.0 ? INT_MAX : max(static_cast<long int>(0),
340
        long int max_work = keep_fraction == 0.0 ? INT_MAX : max(static_cast<long int>(0),
341
                                                                 F- static_cast<long int>(keep_fraction * F));
341
                                                                 F- static_cast<long int>(keep_fraction * F));
342
        QuadricSimplifier qsim(m, mask, singular_thresh, choose_optimal_positions);
342
        QuadricSimplifier qsim(m, mask, singular_thresh, choose_optimal_positions);
343
        qsim.reduce(max_work);
343
        qsim.reduce(max_work);
344
    }
344
    }
345
    
345
    
346
    
346
    
347
}
347
}
348
 
348