Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
688 khor 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
6
 
7
#include "triangulate.h"
8
 
9
#include <queue>
10
#include <vector>
11
#include <iterator>
12
#include <cassert>
13
 
14
#include "../CGLA/Vec3d.h"
15
 
16
#include "Manifold.h"
17
#include "AttributeVector.h"
18
 
19
namespace HMesh
20
{
21
    using namespace std;
22
    using namespace CGLA;
23
 
24
    void get_candidates(const Manifold& m, VertexID v, vector<HalfEdgeID>& candidates)
25
    {
26
        vector<VertexID> vertices;
27
        vector<HalfEdgeID> hedges;
28
 
29
        Walker wv = m.walker(v);
30
        for(;!wv.full_circle(); wv = wv.circulate_vertex_cw()){
31
            vertices.push_back(wv.vertex());
32
            hedges.push_back(wv.halfedge());
33
        }
34
        int N = wv.no_steps();
35
        vector<VertexID> vertices_check(vertices);
36
        assert(N == vertices.size());
37
 
38
        for(int i = N - 1; i >= 0; --i){
39
            for(Walker w = m.walker(hedges[i]).next(); w.vertex() != vertices[(i+N-1)%N]; w = w.next()){
40
                if(find(vertices_check.begin(), vertices_check.end(), w.vertex()) == vertices_check.end())
41
                    candidates.push_back(w.halfedge());       
42
            }
43
        }
44
    }
45
 
46
    float curv(const Vec3d& p, vector<Vec3d>& vec)
47
    {
48
        size_t N = vec.size();
49
        std::vector<Vec3d> normals;
50
        for(size_t i = 0; i < N; ++i){
51
            Vec3d norm = normalize(cross(vec[i]-p, vec[(i+1)%N]-p));
52
            normals.push_back(norm);
53
        }
54
        float alpha = 0;
55
        for(size_t i = 0; i < N; ++i)
56
            alpha += (vec[i]-p).length()*acos(dot(normals[i],normals[(i+1)%N]));
57
 
58
        return alpha;
59
    }
60
 
61
    float get_badness(const Manifold& m, VertexID v, VertexID n)
62
    {
63
        vector<HalfEdgeID> hedges;
64
 
65
        Walker wv = m.walker(v);
66
        for(; !wv.full_circle(); wv = wv.circulate_vertex_cw())
67
            hedges.push_back(wv.halfedge());
68
 
69
        vector<Vec3d> one_ring;
70
        vector<Vec3d> one_ring_n;
71
        int N = wv.no_steps();
72
        for(int i = N - 1; i >= 0; --i){
73
            for(Walker w = m.walker(hedges[i]).next(); w.vertex() != v; w = w.next()){
74
                one_ring.push_back(m.pos(w.vertex()));
75
                if(w.vertex() != n)
76
                    one_ring_n.push_back(m.pos(w.vertex()));
77
            }
78
        }
79
        return curv(m.pos(v), one_ring) - curv(m.pos(v), one_ring_n);
80
    }
81
 
82
 
83
    const CGLA::Vec3d get_normal(const Manifold& m, VertexID v)
84
    {
85
 
86
        vector<HalfEdgeID> hedges;
87
 
88
        Walker wv = m.walker(v);
89
        for(; !wv.full_circle(); wv = wv.circulate_vertex_cw())
90
            hedges.push_back(wv.halfedge());
91
 
92
        vector<Vec3d> one_ring;
93
        size_t N = wv.no_steps();
94
        for(int i = N - 1; i >= 0; --i){
95
            for(Walker w = m.walker(hedges[i]).next(); w.vertex() != v; w = w.next())
96
                one_ring.push_back(m.pos(w.vertex()));   
97
        }
98
 
99
        Vec3d norm(0);
100
        N = one_ring.size();
101
        Vec3d p0 = m.pos(v);
102
        for(size_t i = 0; i < N; ++i){
103
            Vec3d p1 = one_ring[i];
104
            Vec3d p2 = one_ring[(i+1) % N];
105
            Vec3d e0 = normalize(p1 - p0);
106
            Vec3d e1 = normalize(p2 - p0);
107
            norm += cross(e0, e1) * acos(dot(e0, e1));
108
        }
109
        return normalize(norm);
110
    }
111
 
112
    void triangulate_by_vertex_face_split(Manifold& m)
113
    {
114
        vector<FaceID> fv;
115
        fv.reserve(m.no_faces());
116
        copy(m.faces_begin(), m.faces_end(), back_inserter(fv));
117
 
118
        for(size_t i = 0; i < fv.size(); ++i)
119
            m.split_face_by_vertex(fv[i]);
120
    }
121
 
122
    void triangulate_by_edge_face_split(Manifold& m)
123
    {
124
        vector<FaceID> fv;
125
        fv.reserve(m.no_faces());
126
        copy(m.faces_begin(), m.faces_end(), back_inserter(fv));
127
 
128
        for(size_t i = 0; i < fv.size(); ++i)
129
            triangulate_face_by_edge_split(m, fv[i]);
130
    }
131
 
132
    struct PotentialEdge
133
    {
134
        int time_tag;
135
        float badness;
136
        FaceID f;
137
        VertexID v0, v1;
138
    };
139
 
140
    bool operator>(const PotentialEdge& e0, const PotentialEdge& e1)
141
    { return e0.badness>e1.badness; }
142
 
143
    typedef std::priority_queue<PotentialEdge,
144
        std::vector<PotentialEdge>,
145
        std::greater<PotentialEdge> > 
146
        PotentialEdgeQueue;
147
 
148
    void insert_potential_edges(const Manifold& m, VertexAttributeVector<int>& vtouched, VertexID v, PotentialEdgeQueue& pot_edges)
149
    {
150
        vector<Vec3d> one_ring;
151
        vector<HalfEdgeID> candidates;
152
        get_candidates(m, v, candidates);
153
 
154
        Vec3d p0 = m.pos(v);
155
        Vec3d norm = normal(m, v);
156
        int n = candidates.size();
157
        for(int i = 0; i < n; ++i){
158
            Walker w = m.walker(candidates[i]);
159
            VertexID v_n = w.vertex();
160
            Vec3d edir = normalize(m.pos(v_n) - p0);
161
            Vec3d norm_n = normal(m, v_n);
162
            float bad = sqr(dot(edir, norm));
163
            float bad_n = sqr(dot(edir, norm_n));
164
 
165
            PotentialEdge pot;
166
 
167
            /* So if the edge between two vertices is not orthogonal to 
168
            their normals, the badness is increased. Badness is also
169
            increased if the normals are very different. */
170
 
171
            pot.badness = bad+bad_n - dot(norm_n,norm);
172
            pot.time_tag = vtouched[v];
173
            pot.v0 = v;
174
            pot.v1 = w.vertex();
175
            pot.f = w.face();
176
 
177
            pot_edges.push(pot);
178
        }
179
    }
180
 
181
    void curvature_triangulate(Manifold& m)
182
    {
183
        PotentialEdgeQueue pot_edges;
184
        VertexAttributeVector<int> vtouched(m.allocated_vertices(), 0);
185
 
186
        // Create candidates
187
        for(VertexIDIterator v = m.vertices_begin(); v!= m.vertices_end(); ++v)
188
            insert_potential_edges(m, vtouched, *v, pot_edges);
189
 
190
        while(!pot_edges.empty()){
191
            const PotentialEdge& pot_edge = pot_edges.top();
192
            // Record all the vertices of the face. We need to 
193
            // recompute the candidates.
194
            std::vector<VertexID> reeval_vec;
195
 
196
            for(Walker w = m.walker(pot_edge.f); !w.full_circle(); w = w.circulate_face_cw())
197
                reeval_vec.push_back(w.vertex());
198
 
199
            // Make sure that the vertex has not been touched since 
200
            // we created the potential edge. If the vertex has been
201
            // touched the candidate edge has either (a) been processed,
202
            // (b) received a lower priority or (c) become invalid.
203
            if(pot_edge.time_tag == vtouched[pot_edge.v0]){
204
                vector<Vec3d> one_ring;
205
                vector<HalfEdgeID> candidates;
206
 
207
                m.split_face_by_edge(pot_edge.f, pot_edge.v0, pot_edge.v1);
208
 
209
                // Recompute priorities.
210
                for(size_t i = 0; i < reeval_vec.size(); ++i){
211
                    VertexID& v = reeval_vec[i];
212
                    ++vtouched[v];
213
                    insert_potential_edges(m, vtouched, v, pot_edges);
214
                }
215
 
216
            }
217
            pot_edges.pop();
218
        }
219
 
220
    }
221
 
222
    void shortest_edge_triangulate(Manifold& m)
223
    {
224
        int work;
225
        do{
226
            // For every face.
227
            work = 0;
228
            for(FaceIDIterator f = m.faces_begin(); f != m.faces_end(); ++f){
229
                // Create a vector of vertices.
230
                vector<VertexID> verts;
231
                for(Walker w = m.walker(*f); !w.full_circle(); w = w.circulate_face_ccw())
232
				{
233
					FaceID fa = w.face();
234
					FaceID fb = *f;
235
					assert(fa==fb);
236
                    verts.push_back(w.vertex());
237
				}
238
                // If there are just three we are done.
239
                if(verts.size() == 3) continue;
240
 
241
                // Find vertex pairs that may be connected.
242
                vector<pair<int,int> > vpairs;
243
                const int N = verts.size();
244
                for(int i = 0; i < N - 2; ++i){
245
                    for(int j = i + 2; j < N; ++j){
246
                        if(verts[i] != verts[j] && !connected(m, verts[i], verts[j]))
247
                            vpairs.push_back(pair<int,int>(i, j));
248
                    }
249
                }
250
                if(vpairs.empty()){
251
                    cout << "Warning: could not triangulate a face." 
252
                        << "Probably a vertex appears more than one time in other vertex's one-ring" << endl;
253
                    continue;
254
                }
255
 
256
                /* For all vertex pairs, find the edge lengths. Combine the
257
                vertices forming the shortest edge. */
258
 
259
                float min_len=FLT_MAX;
260
                int min_k = -1;
261
                for(size_t k = 0; k < vpairs.size(); ++k){
262
                    int i = vpairs[k].first;
263
                    int j = vpairs[k].second;
264
                    float len = sqr_length(m.pos(verts[i]) - m.pos(verts[j]));
265
 
266
                    if(len<min_len){
267
                        min_len = len;
268
                        min_k = k;
269
                    }
270
                }
271
                assert(min_k != -1);
272
 
273
                {
274
                    // Split faces along edge whose midpoint is closest to isovalue
275
                    int i = vpairs[min_k].first;
276
                    int j = vpairs[min_k].second;
277
                    m.split_face_by_edge(*f, verts[i], verts[j]);
278
                }
279
                ++work;
280
 
281
            }
282
        }
283
        while(work);
284
    }
285
 
286
    void triangulate_face_by_edge_split(Manifold& m, FaceID f)
287
    {
288
        if(no_edges(m, f)<=3)
289
            return;
290
 
291
        Walker w = m.walker(f);
292
 
293
        // as long as f is not a triangle
294
        while(w.next().next().next().halfedge() != w.halfedge()){
295
            // assert that face has at least 3 edges
296
            // f is split into triangle from first three vertices, and becomes remaining polygon in next iteration
297
            assert(w.next().next().halfedge() != w.halfedge());
298
            VertexID v0 = w.vertex();
299
            VertexID v1 = w.next().next().vertex();
300
            FaceID f_old = f;
301
            if(v0 != v1 && !connected(m, v0, v1))
302
                f = m.split_face_by_edge(f, v0, v1);
303
            if(f == f_old)
304
                return;
305
        }
306
    }
307
}