568 |
jab |
1 |
//
|
|
|
2 |
// polarize.cpp
|
|
|
3 |
// GEL
|
|
|
4 |
//
|
|
|
5 |
// Created by J. Andreas Bærentzen on 18/03/12.
|
|
|
6 |
// Copyright 2012 __MyCompanyName__. All rights reserved.
|
|
|
7 |
//
|
|
|
8 |
#include <queue>
|
|
|
9 |
|
|
|
10 |
#include "polarize.h"
|
631 |
janba |
11 |
#include <CGLA/Vec2d.h>
|
|
|
12 |
#include <LinAlg/LapackFunc.h>
|
568 |
jab |
13 |
#include <HMesh/triangulate.h>
|
631 |
janba |
14 |
#include <HMesh/obj_save.h>
|
568 |
jab |
15 |
#include <HMesh/curvature.h>
|
|
|
16 |
#include <HMesh/quadric_simplify.h>
|
|
|
17 |
#include <HMesh/mesh_optimization.h>
|
|
|
18 |
#include <HMesh/smooth.h>
|
|
|
19 |
|
572 |
jab |
20 |
#include <complex>
|
|
|
21 |
|
568 |
jab |
22 |
using namespace CGLA;
|
|
|
23 |
using namespace std;
|
|
|
24 |
using namespace HMesh;
|
|
|
25 |
|
631 |
janba |
26 |
|
|
|
27 |
|
|
|
28 |
inline bool same_level(float a, float b) {return abs(a-b) < 0.00001;}
|
|
|
29 |
|
|
|
30 |
|
|
|
31 |
struct LevelSetInfo
|
|
|
32 |
{
|
|
|
33 |
int id;
|
|
|
34 |
int no_vertices;
|
|
|
35 |
Vec3d avg_pos;
|
|
|
36 |
double rad;
|
|
|
37 |
double length;
|
|
|
38 |
int components;
|
|
|
39 |
HalfEdgeID h;
|
|
|
40 |
double fun_value;
|
|
|
41 |
|
|
|
42 |
void print()
|
|
|
43 |
{
|
|
|
44 |
cout
|
|
|
45 |
<< " id : " << id
|
|
|
46 |
<< " no vertices : " << no_vertices
|
|
|
47 |
<< " avg pos : " << avg_pos
|
|
|
48 |
<< " rad : " << rad
|
|
|
49 |
<< " length : " << length
|
|
|
50 |
<< " # : " << components
|
|
|
51 |
<< " F : " << fun_value << endl;
|
|
|
52 |
}
|
|
|
53 |
};
|
|
|
54 |
|
|
|
55 |
void compute_edge_weights(Manifold& m, HalfEdgeAttributeVector<double>& edge_weights, FaceAttributeVector<int>& included)
|
|
|
56 |
{
|
|
|
57 |
edge_weights = HalfEdgeAttributeVector<double>(m.allocated_halfedges(), 0);
|
|
|
58 |
for(FaceIDIterator f = m.faces_begin(); f != m.faces_end(); ++f)
|
|
|
59 |
if(included[*f])
|
|
|
60 |
{
|
|
|
61 |
for(Walker wv = m.walker(*f); !wv.full_circle(); wv = wv.circulate_face_ccw())
|
|
|
62 |
{
|
|
|
63 |
HalfEdgeID h = wv.halfedge();
|
|
|
64 |
Vec3d p1(m.pos(wv.vertex()));
|
|
|
65 |
Vec3d p2(m.pos(wv.next().vertex()));
|
|
|
66 |
Vec3d p0(m.pos(wv.opp().vertex()));
|
|
|
67 |
double ang = acos(min(1.0, max(-1.0, dot(normalize(p1-p0), normalize(p2-p0)))));
|
|
|
68 |
double ang_opp = acos(min(1.0, max(-1.0, dot(normalize(p2-p1), normalize(p0-p1)))));
|
|
|
69 |
double l = (p1-p0).length();
|
|
|
70 |
edge_weights[h] += tan(ang/2) / l;
|
|
|
71 |
edge_weights[wv.opp().halfedge()] += tan(ang_opp/2) / l;
|
|
|
72 |
}
|
|
|
73 |
}
|
|
|
74 |
}
|
|
|
75 |
void smooth_fun(Manifold& m,
|
|
|
76 |
VertexAttributeVector<int>& nailed,
|
|
|
77 |
VertexAttributeVector<double>& fun)
|
|
|
78 |
{
|
|
|
79 |
HalfEdgeAttributeVector<double> edge_weights;
|
|
|
80 |
FaceAttributeVector<int> included(m.allocated_faces(),1);
|
|
|
81 |
compute_edge_weights(m,edge_weights, included);
|
|
|
82 |
VertexAttributeVector<double> new_fun(m.no_vertices());
|
|
|
83 |
for(int i = 0; i < 1000; ++i)
|
|
|
84 |
{
|
|
|
85 |
for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
|
|
|
86 |
if(!nailed[*v])
|
|
|
87 |
{
|
|
|
88 |
double w_sum = 0;
|
|
|
89 |
new_fun[*v] = 0;
|
|
|
90 |
for(Walker wv = m.walker(*v); !wv.full_circle(); wv = wv.circulate_vertex_ccw())
|
|
|
91 |
{
|
|
|
92 |
double w = edge_weights[wv.halfedge()];
|
|
|
93 |
new_fun[*v] += w * fun[wv.vertex()];
|
|
|
94 |
w_sum += w;
|
|
|
95 |
}
|
|
|
96 |
new_fun[*v] /= w_sum;
|
|
|
97 |
}
|
|
|
98 |
else
|
|
|
99 |
new_fun[*v] = fun[*v];
|
|
|
100 |
fun = new_fun;
|
|
|
101 |
}
|
|
|
102 |
}
|
|
|
103 |
|
|
|
104 |
void segment_manifold(Manifold& m, HalfEdgeAttributeVector<int>& ls_id,
|
|
|
105 |
FaceAttributeVector<int>& segmentation,
|
|
|
106 |
vector<vector<int>>& boundaries)
|
|
|
107 |
{
|
|
|
108 |
segmentation = FaceAttributeVector<int>(m.no_faces(), -1);
|
|
|
109 |
int SEG_NO = 0;
|
|
|
110 |
for(auto f = m.faces_begin(); f != m.faces_end(); ++f)
|
|
|
111 |
{
|
|
|
112 |
if (segmentation[*f] == -1)
|
|
|
113 |
{
|
|
|
114 |
queue<FaceID> q;
|
|
|
115 |
q.push(*f);
|
|
|
116 |
vector<int> bound(0);
|
|
|
117 |
while (!q.empty())
|
|
|
118 |
{
|
|
|
119 |
FaceID face = q.front();
|
|
|
120 |
q.pop();
|
|
|
121 |
segmentation[face] = SEG_NO;
|
|
|
122 |
for(Walker w = m.walker(face); !w.full_circle(); w = w.next())
|
|
|
123 |
{
|
|
|
124 |
if(ls_id[w.halfedge()] == -1)
|
|
|
125 |
{
|
|
|
126 |
FaceID fopp = w.opp().face();
|
|
|
127 |
if(segmentation[fopp] == -1) {
|
|
|
128 |
q.push(fopp);
|
|
|
129 |
}
|
|
|
130 |
}
|
|
|
131 |
else {
|
|
|
132 |
bound.push_back(ls_id[w.halfedge()]);
|
|
|
133 |
}
|
|
|
134 |
|
|
|
135 |
}
|
|
|
136 |
}
|
|
|
137 |
sort(begin(bound), end(bound));
|
|
|
138 |
auto new_end = unique(begin(bound), end(bound));
|
|
|
139 |
boundaries.push_back(vector<int>(begin(bound),new_end));
|
|
|
140 |
cout << "Boundaries of seg# " << SEG_NO << " : ";
|
|
|
141 |
for(auto be:boundaries[SEG_NO])
|
|
|
142 |
cout << be << " ";
|
|
|
143 |
cout << endl;
|
|
|
144 |
SEG_NO += 1;
|
|
|
145 |
}
|
|
|
146 |
|
|
|
147 |
}
|
|
|
148 |
}
|
|
|
149 |
|
|
|
150 |
|
568 |
jab |
151 |
void shortest_edge_triangulate_face(Manifold& m, FaceID f0, VertexAttributeVector<int>& level_set_id_vertex)
|
|
|
152 |
{
|
|
|
153 |
queue<FaceID> face_queue;
|
|
|
154 |
|
|
|
155 |
face_queue.push(f0);
|
|
|
156 |
|
|
|
157 |
while(!face_queue.empty())
|
|
|
158 |
{
|
|
|
159 |
FaceID f = face_queue.front();
|
|
|
160 |
face_queue.pop();
|
|
|
161 |
|
|
|
162 |
// Create a vector of vertices.
|
|
|
163 |
vector<VertexID> verts;
|
587 |
jab |
164 |
for(Walker w = m.walker(f); !w.full_circle(); w = w.circulate_face_ccw())
|
568 |
jab |
165 |
{
|
|
|
166 |
FaceID fa = w.face();
|
|
|
167 |
FaceID fb = f;
|
|
|
168 |
assert(fa==fb);
|
|
|
169 |
verts.push_back(w.vertex());
|
|
|
170 |
}
|
|
|
171 |
// If there are just three we are done.
|
|
|
172 |
if(verts.size() == 3) continue;
|
|
|
173 |
|
|
|
174 |
// Find vertex pairs that may be connected.
|
|
|
175 |
vector<pair<int,int> > vpairs;
|
|
|
176 |
const int N = verts.size();
|
|
|
177 |
for(int i = 0; i < N - 2; ++i){
|
|
|
178 |
for(int j = i + 2; j < N; ++j){
|
631 |
janba |
179 |
if(verts[i] != verts[j] &&
|
568 |
jab |
180 |
!connected(m, verts[i], verts[j]) &&
|
|
|
181 |
(level_set_id_vertex[verts[i]] == 0 || level_set_id_vertex[verts[i]] != level_set_id_vertex[verts[j]])
|
|
|
182 |
)
|
|
|
183 |
vpairs.push_back(pair<int,int>(i, j));
|
|
|
184 |
}
|
|
|
185 |
}
|
|
|
186 |
if(vpairs.empty()){
|
631 |
janba |
187 |
cout << "Warning: could not triangulate a face."
|
568 |
jab |
188 |
<< "Probably a vertex appears more than one time in other vertex's one-ring" << endl;
|
|
|
189 |
continue;
|
|
|
190 |
}
|
|
|
191 |
|
|
|
192 |
/* For all vertex pairs, find the edge lengths. Combine the
|
|
|
193 |
vertices forming the shortest edge. */
|
|
|
194 |
|
|
|
195 |
float min_len=FLT_MAX;
|
|
|
196 |
int min_k = -1;
|
|
|
197 |
for(size_t k = 0; k < vpairs.size(); ++k){
|
|
|
198 |
int i = vpairs[k].first;
|
|
|
199 |
int j = vpairs[k].second;
|
|
|
200 |
float len = sqr_length(m.pos(verts[i]) - m.pos(verts[j]));
|
|
|
201 |
|
|
|
202 |
if(len<min_len){
|
|
|
203 |
min_len = len;
|
|
|
204 |
min_k = k;
|
|
|
205 |
}
|
|
|
206 |
}
|
|
|
207 |
assert(min_k != -1);
|
|
|
208 |
|
|
|
209 |
{
|
|
|
210 |
// Split faces along edge whose midpoint is closest to isovalue
|
|
|
211 |
int i = vpairs[min_k].first;
|
|
|
212 |
int j = vpairs[min_k].second;
|
|
|
213 |
FaceID f_new = m.split_face_by_edge(f, verts[i], verts[j]);
|
|
|
214 |
|
|
|
215 |
if(no_edges(m, f)>3)
|
|
|
216 |
face_queue.push(f);
|
|
|
217 |
if(no_edges(m, f_new)>3)
|
|
|
218 |
face_queue.push(f_new);
|
|
|
219 |
}
|
|
|
220 |
|
|
|
221 |
}
|
|
|
222 |
}
|
|
|
223 |
|
|
|
224 |
|
|
|
225 |
void shortest_edge_split_face(Manifold& m, FaceID f0, VertexAttributeVector<int>& level_set_id_vertex)
|
|
|
226 |
{
|
|
|
227 |
queue<FaceID> face_queue;
|
|
|
228 |
|
|
|
229 |
face_queue.push(f0);
|
|
|
230 |
|
|
|
231 |
while(!face_queue.empty())
|
|
|
232 |
{
|
|
|
233 |
FaceID f = face_queue.front();
|
|
|
234 |
face_queue.pop();
|
|
|
235 |
|
|
|
236 |
// Create a vector of vertices.
|
|
|
237 |
vector<VertexID> verts;
|
587 |
jab |
238 |
for(Walker w = m.walker(f); !w.full_circle(); w = w.circulate_face_ccw())
|
568 |
jab |
239 |
{
|
|
|
240 |
verts.push_back(w.vertex());
|
|
|
241 |
}
|
|
|
242 |
|
|
|
243 |
// Find vertex pairs that may be connected.
|
|
|
244 |
vector<pair<int,int> > vpairs;
|
|
|
245 |
const int N = verts.size();
|
|
|
246 |
for(int i = 0; i < N ; ++i){
|
|
|
247 |
for(int j = 3; j < N-2; ++j){
|
|
|
248 |
int jj = (j+i)%N;
|
|
|
249 |
if(!connected(m, verts[i], verts[jj]) &&
|
|
|
250 |
(level_set_id_vertex[verts[i]] != level_set_id_vertex[verts[jj]]) &&
|
572 |
jab |
251 |
(level_set_id_vertex[verts[(i+1)%N]] == level_set_id_vertex[verts[i]]) &&
|
|
|
252 |
(level_set_id_vertex[verts[(i+N-1)%N]] == level_set_id_vertex[verts[i]]) &&
|
|
|
253 |
(level_set_id_vertex[verts[(jj+1)%N]] == level_set_id_vertex[verts[jj]]) &&
|
|
|
254 |
(level_set_id_vertex[verts[(jj+N-1)%N]] == level_set_id_vertex[verts[jj]]))
|
568 |
jab |
255 |
vpairs.push_back(pair<int,int>(i, jj));
|
|
|
256 |
}
|
|
|
257 |
}
|
|
|
258 |
if(vpairs.empty()) continue;
|
|
|
259 |
|
|
|
260 |
|
|
|
261 |
/* For all vertex pairs, find the edge lengths. Combine the
|
|
|
262 |
vertices forming the shortest edge. */
|
|
|
263 |
|
|
|
264 |
float min_len=FLT_MAX;
|
|
|
265 |
int min_k = -1;
|
|
|
266 |
for(size_t k = 0; k < vpairs.size(); ++k){
|
|
|
267 |
int i = vpairs[k].first;
|
|
|
268 |
int j = vpairs[k].second;
|
|
|
269 |
float len = sqr_length(m.pos(verts[i]) - m.pos(verts[j]));
|
|
|
270 |
|
|
|
271 |
if(len<min_len){
|
|
|
272 |
min_len = len;
|
|
|
273 |
min_k = k;
|
|
|
274 |
}
|
|
|
275 |
}
|
|
|
276 |
assert(min_k != -1);
|
|
|
277 |
|
|
|
278 |
{
|
|
|
279 |
// Split faces along edge whose midpoint is closest to isovalue
|
|
|
280 |
int i = vpairs[min_k].first;
|
|
|
281 |
int j = vpairs[min_k].second;
|
|
|
282 |
FaceID f_new = m.split_face_by_edge(f, verts[i], verts[j]);
|
|
|
283 |
if(no_edges(m, f)>5)
|
|
|
284 |
face_queue.push(f);
|
|
|
285 |
if(no_edges(m, f_new)>5)
|
|
|
286 |
face_queue.push(f_new);
|
|
|
287 |
}
|
|
|
288 |
|
|
|
289 |
}
|
|
|
290 |
}
|
|
|
291 |
|
|
|
292 |
|
|
|
293 |
|
|
|
294 |
struct EdgeQElem {
|
|
|
295 |
float priority;
|
|
|
296 |
HalfEdgeID he;
|
|
|
297 |
EdgeQElem(float _priority, HalfEdgeID _he): priority(_priority), he(_he) {}
|
|
|
298 |
};
|
|
|
299 |
|
|
|
300 |
bool operator<(const EdgeQElem& l, const EdgeQElem& r)
|
|
|
301 |
{
|
|
|
302 |
return l.priority < r.priority;
|
|
|
303 |
}
|
|
|
304 |
|
|
|
305 |
class FunctionalDifference: public EnergyFun
|
|
|
306 |
{
|
|
|
307 |
VertexAttributeVector<float>& fun;
|
|
|
308 |
VertexAttributeVector<int>& status;
|
|
|
309 |
public:
|
|
|
310 |
FunctionalDifference(VertexAttributeVector<float>& _fun, VertexAttributeVector<int>& _status): fun(_fun), status(_status) {}
|
631 |
janba |
311 |
virtual double delta_energy(const Manifold& m, HalfEdgeID h) const
|
568 |
jab |
312 |
{
|
587 |
jab |
313 |
Walker w = m.walker(h);
|
568 |
jab |
314 |
if(status[w.vertex()] == 1 && status[w.opp().vertex()]==1)
|
|
|
315 |
return DBL_MAX;
|
|
|
316 |
return sqr_length(m.pos(w.next().vertex())-m.pos(w.opp().next().vertex()))/(1e-6+abs(fun[w.next().vertex()]-fun[w.opp().next().vertex()])) - sqr_length(m.pos(w.vertex())-m.pos(w.opp().vertex()))/(1e-6+abs(fun[w.vertex()]-fun[w.opp().vertex()]));
|
|
|
317 |
}
|
|
|
318 |
};
|
|
|
319 |
|
572 |
jab |
320 |
class TriangleQualityValence: public EnergyFun
|
|
|
321 |
{
|
|
|
322 |
VertexAttributeVector<int>& idv;
|
|
|
323 |
MinAngleEnergy mae;
|
|
|
324 |
ValencyEnergy vae;
|
|
|
325 |
public:
|
|
|
326 |
TriangleQualityValence(VertexAttributeVector<int>& _idv): idv(_idv), mae(-1) {}
|
631 |
janba |
327 |
virtual double delta_energy(const Manifold& m, HalfEdgeID h) const
|
572 |
jab |
328 |
{
|
587 |
jab |
329 |
Walker w = m.walker(h);
|
631 |
janba |
330 |
if(idv[w.next().vertex()] == idv[w.opp().next().vertex()] ||
|
572 |
jab |
331 |
idv[w.vertex()] == idv[w.opp().vertex()])
|
|
|
332 |
return DBL_MAX;
|
|
|
333 |
|
|
|
334 |
VertexID v1 = w.opp().vertex();
|
|
|
335 |
VertexID v2 = w.vertex();
|
|
|
336 |
VertexID vo1 = w.next().vertex();
|
|
|
337 |
VertexID vo2 = w.opp().next().vertex();
|
|
|
338 |
|
|
|
339 |
int val1 = valency(m, v1);
|
|
|
340 |
int val2 = valency(m, v2);
|
|
|
341 |
int valo1 = valency(m, vo1);
|
|
|
342 |
int valo2 = valency(m, vo2);
|
|
|
343 |
|
|
|
344 |
// The optimal valency is four for a boundary vertex
|
|
|
345 |
// and six elsewhere.
|
|
|
346 |
int t1 = boundary(m, v1) ? 4 : 6;
|
|
|
347 |
int t2 = boundary(m, v2) ? 4 : 6;
|
|
|
348 |
int to1 = boundary(m, vo1) ? 4 : 6;
|
|
|
349 |
int to2 = boundary(m, vo2) ? 4 : 6;
|
|
|
350 |
|
631 |
janba |
351 |
int before =
|
572 |
jab |
352 |
max(max(sqr(val1-t1),sqr(val2-t2)), max(sqr(valo1-to1), sqr(valo2-to2)));
|
631 |
janba |
353 |
int after =
|
572 |
jab |
354 |
max(max(sqr(valo1+1-to1),sqr(val1-1-t1)), max(sqr(val2-1-t2),sqr(valo2+1-to2)));
|
|
|
355 |
|
|
|
356 |
return static_cast<double>(after-before);
|
|
|
357 |
|
|
|
358 |
// return vae.delta_energy(m,h);
|
|
|
359 |
float la = length(m.pos(w.next().vertex())-m.pos(w.opp().next().vertex()));
|
|
|
360 |
float lb = length(m.pos(w.vertex())-m.pos(w.opp().vertex()));
|
|
|
361 |
return la-lb;
|
|
|
362 |
return mae.delta_energy(m,h);
|
|
|
363 |
}
|
|
|
364 |
};
|
|
|
365 |
|
568 |
jab |
366 |
class TriangleQuality: public EnergyFun
|
|
|
367 |
{
|
|
|
368 |
VertexAttributeVector<int>& idv;
|
|
|
369 |
MinAngleEnergy mae;
|
|
|
370 |
ValencyEnergy vae;
|
|
|
371 |
public:
|
|
|
372 |
TriangleQuality(VertexAttributeVector<int>& _idv): idv(_idv), mae(-1) {}
|
631 |
janba |
373 |
virtual double delta_energy(const Manifold& m, HalfEdgeID h) const
|
568 |
jab |
374 |
{
|
587 |
jab |
375 |
Walker w = m.walker(h);
|
631 |
janba |
376 |
if(idv[w.next().vertex()] == idv[w.opp().next().vertex()] ||
|
568 |
jab |
377 |
idv[w.vertex()] == idv[w.opp().vertex()])
|
|
|
378 |
return DBL_MAX;
|
|
|
379 |
return mae.delta_energy(m,h);
|
|
|
380 |
}
|
|
|
381 |
};
|
|
|
382 |
|
587 |
jab |
383 |
Vec3d grad(HMesh::Manifold& m, HMesh::VertexAttributeVector<double>& fun, HMesh::FaceID f)
|
572 |
jab |
384 |
{
|
|
|
385 |
if(no_edges(m,f) != 3)
|
587 |
jab |
386 |
return Vec3d(0.0);
|
572 |
jab |
387 |
|
|
|
388 |
|
587 |
jab |
389 |
Vec3d n = normal(m, f);
|
572 |
jab |
390 |
|
587 |
jab |
391 |
Vec3d gsum(0.0);
|
|
|
392 |
for(Walker w = m.walker(f); !w.full_circle(); w = w.next())
|
572 |
jab |
393 |
{
|
631 |
janba |
394 |
VertexID avid = w.opp().vertex();
|
|
|
395 |
VertexID bvid = w.vertex();
|
|
|
396 |
VertexID cvid = w.next().vertex();
|
|
|
397 |
Vec3d gdir = normalize(cross(n, m.pos(bvid) - m.pos(avid)));
|
|
|
398 |
double l = dot(m.pos(cvid)-m.pos(avid), gdir);
|
|
|
399 |
gdir *= fun[cvid]/l;
|
572 |
jab |
400 |
gsum += gdir;
|
|
|
401 |
}
|
|
|
402 |
return gsum;
|
|
|
403 |
}
|
568 |
jab |
404 |
|
631 |
janba |
405 |
double solve_for_orthogonal_gradients(HMesh::Manifold& m, HMesh::VertexAttributeVector<double>& fun,
|
|
|
406 |
HalfEdgeID h, double beta, double gamma)
|
572 |
jab |
407 |
{
|
631 |
janba |
408 |
Vec3d n = normal(m, m.walker(h).face());
|
|
|
409 |
|
|
|
410 |
Vec3d uvw[3];
|
|
|
411 |
Vec3d abc;
|
|
|
412 |
Walker w = m.walker(h);
|
|
|
413 |
VertexID vid[] = {w.next().vertex(), w.opp().vertex(),w.vertex()};
|
572 |
jab |
414 |
|
631 |
janba |
415 |
for(int i=0; !w.full_circle(); w = w.next(),++ i)
|
572 |
jab |
416 |
{
|
631 |
janba |
417 |
uvw[i] = normalize(cross(n, m.pos(vid[(i+1)%3]) - m.pos(vid[(i+2)%3])));
|
|
|
418 |
uvw[i] /= dot(m.pos(vid[i])-m.pos(vid[(i+1)%3]), uvw[i]);
|
|
|
419 |
abc[i] = fun[vid[i]];
|
572 |
jab |
420 |
}
|
631 |
janba |
421 |
Vec3d A(dot(uvw[0],uvw[0]),dot(uvw[0],uvw[1]),dot(uvw[0],uvw[2]));
|
|
|
422 |
Vec3d B(dot(uvw[1],uvw[0]),dot(uvw[1],uvw[1]),dot(uvw[1],uvw[2]));
|
|
|
423 |
Vec3d C(dot(uvw[2],uvw[0]),dot(uvw[2],uvw[1]),dot(uvw[2],uvw[2]));
|
|
|
424 |
|
|
|
425 |
return - (beta * dot(B, abc) + gamma * dot(C, abc))/dot(A, abc);
|
572 |
jab |
426 |
}
|
|
|
427 |
|
568 |
jab |
428 |
|
631 |
janba |
429 |
void recompute_circle_param(Manifold& m, VertexID v, VertexAttributeVector<double>& fun, VertexAttributeVector<Vec2d>& circle_pos, double f_origin)
|
568 |
jab |
430 |
{
|
631 |
janba |
431 |
Vec2d c_new(0);
|
|
|
432 |
for(auto w = m.walker(v); !w.full_circle(); w = w.circulate_vertex_ccw())
|
|
|
433 |
{
|
|
|
434 |
Walker w_base = w.next();
|
|
|
435 |
Vec2d X = circle_pos[w_base.opp().vertex()];
|
|
|
436 |
Vec2d Y(-X[1], X[0]);
|
|
|
437 |
Vec2d vec = circle_pos[w_base.vertex()];
|
|
|
438 |
double angle = atan2(max(-1.0,min(1.0,dot(vec,Y))),
|
|
|
439 |
max(-1.0,min(1.0,dot(vec,X))));
|
|
|
440 |
double new_angle = solve_for_orthogonal_gradients(m, fun, w_base.halfedge(), 0, angle);
|
|
|
441 |
new_angle = max(-M_PI/4, min(M_PI/4,new_angle));
|
|
|
442 |
c_new += cos(new_angle)*X + sin(new_angle)*Y;
|
568 |
jab |
443 |
}
|
631 |
janba |
444 |
circle_pos[v] = normalize(c_new);
|
568 |
jab |
445 |
}
|
|
|
446 |
|
631 |
janba |
447 |
void polarize_mesh(Manifold& m, VertexAttributeVector<double>& fun, double vmin, double vmax, const int divisions, VertexAttributeVector<Vec2d>& parametrization)
|
568 |
jab |
448 |
{
|
572 |
jab |
449 |
vmax -= 0.01 * (vmax-vmin);
|
568 |
jab |
450 |
float interval = (vmax-vmin)/divisions;
|
|
|
451 |
|
586 |
jab |
452 |
VertexAttributeVector<int> status(m.allocated_vertices(), 0);
|
568 |
jab |
453 |
|
|
|
454 |
|
|
|
455 |
// ----------------------------------------
|
|
|
456 |
cout << "Tracing level set curves" << endl;
|
|
|
457 |
|
|
|
458 |
vector<HalfEdgeID> hidvec;
|
|
|
459 |
for(HalfEdgeIDIterator hid = m.halfedges_begin(); hid != m.halfedges_end(); ++hid)
|
|
|
460 |
{
|
587 |
jab |
461 |
Walker w = m.walker(*hid);
|
568 |
jab |
462 |
if(fun[w.vertex()] > fun[w.opp().vertex()])
|
|
|
463 |
hidvec.push_back(*hid);
|
|
|
464 |
}
|
|
|
465 |
|
607 |
jrf |
466 |
for(size_t i = 0; i<hidvec.size(); ++i)
|
568 |
jab |
467 |
{
|
587 |
jab |
468 |
Walker w = m.walker(hidvec[i]);
|
568 |
jab |
469 |
|
|
|
470 |
float b = (fun[w.vertex()]- vmin)/interval;
|
|
|
471 |
float a = (fun[w.opp().vertex()] - vmin)/interval;
|
|
|
472 |
float floor_b = floor(b);
|
|
|
473 |
float floor_a = floor(a);
|
|
|
474 |
|
587 |
jab |
475 |
Vec3d pb = m.pos(w.vertex());
|
568 |
jab |
476 |
for(int j=floor_b; j>floor_a; --j)
|
|
|
477 |
{
|
|
|
478 |
float t = (j-a) / (b-a);
|
587 |
jab |
479 |
Vec3d p = t * pb + (1.0-t) * m.pos(w.opp().vertex());
|
568 |
jab |
480 |
VertexID v_new = m.split_edge(w.halfedge());
|
|
|
481 |
w = w.prev();
|
|
|
482 |
status[v_new] = 1;
|
|
|
483 |
fun[v_new] = j * interval + vmin;
|
|
|
484 |
m.pos(v_new) = p;
|
|
|
485 |
}
|
|
|
486 |
}
|
|
|
487 |
|
|
|
488 |
bool did_work;
|
|
|
489 |
do
|
|
|
490 |
{
|
|
|
491 |
did_work = false;
|
|
|
492 |
|
|
|
493 |
for(FaceIDIterator fid = m.faces_begin(); fid != m.faces_end(); ++fid)
|
587 |
jab |
494 |
for(Walker w = m.walker(*fid);!w.full_circle(); w = w.next())
|
568 |
jab |
495 |
if(status[w.vertex()] == 1 && !(status[w.next().vertex()]==1 && same_level(fun[w.vertex()],fun[w.next().vertex()]))
|
|
|
496 |
&& !(status[w.prev().vertex()]==1 && same_level(fun[w.vertex()],fun[w.prev().vertex()])))
|
|
|
497 |
{
|
587 |
jab |
498 |
Walker w0 = w;
|
568 |
jab |
499 |
w = w.next().next();
|
|
|
500 |
do
|
|
|
501 |
{
|
|
|
502 |
if(status[w.vertex()] == 1 && w.next().halfedge() != w0.halfedge() &&
|
|
|
503 |
same_level(fun[w0.vertex()],fun[w.vertex()]))
|
|
|
504 |
{
|
|
|
505 |
m.split_face_by_edge(*fid, w0.vertex(), w.vertex());
|
|
|
506 |
did_work = true;
|
|
|
507 |
break;
|
|
|
508 |
}
|
|
|
509 |
w = w.next();
|
|
|
510 |
}
|
|
|
511 |
while(!w.full_circle());
|
|
|
512 |
break;
|
|
|
513 |
}
|
|
|
514 |
}
|
|
|
515 |
while(did_work);
|
|
|
516 |
|
631 |
janba |
517 |
shortest_edge_triangulate(m);
|
572 |
jab |
518 |
|
568 |
jab |
519 |
// ----------------------------
|
|
|
520 |
cout << "Numbering the level sets" << endl;
|
631 |
janba |
521 |
VertexAttributeVector<int> nailed(m.no_vertices(),0);
|
|
|
522 |
vector<LevelSetInfo> level_set_info;
|
|
|
523 |
HalfEdgeAttributeVector<int> level_set_id(m.allocated_halfedges(), -1);
|
|
|
524 |
VertexAttributeVector<int> level_set_id_vertex(m.allocated_vertices(), -1);
|
|
|
525 |
VertexAttributeVector<Vec2d> circle_pos;
|
|
|
526 |
for(auto vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
|
|
|
527 |
circle_pos[*vid] = Vec2d(0,0);
|
|
|
528 |
int no_id=0;
|
568 |
jab |
529 |
for(HalfEdgeIDIterator hid = m.halfedges_begin(); hid != m.halfedges_end(); ++hid)
|
|
|
530 |
{
|
587 |
jab |
531 |
Walker w = m.walker(*hid);
|
568 |
jab |
532 |
if(status[w.vertex()] == 1 && status[w.opp().vertex()] == 1 &&
|
|
|
533 |
same_level(fun[w.vertex()], fun[w.opp().vertex()]) &&
|
631 |
janba |
534 |
level_set_id[w.halfedge()] == -1)
|
568 |
jab |
535 |
{
|
631 |
janba |
536 |
LevelSetInfo lsi;
|
|
|
537 |
lsi.id = no_id;
|
|
|
538 |
lsi.fun_value = fun[w.vertex()];
|
|
|
539 |
lsi.components = 1;
|
|
|
540 |
lsi.no_vertices = 0;
|
572 |
jab |
541 |
float level_set_length = 0;
|
568 |
jab |
542 |
while(level_set_id[w.halfedge()] != no_id)
|
|
|
543 |
{
|
572 |
jab |
544 |
level_set_length += length(m,w.halfedge());
|
568 |
jab |
545 |
level_set_id[w.halfedge()] = no_id;
|
|
|
546 |
level_set_id[w.opp().halfedge()] = no_id;
|
|
|
547 |
level_set_id_vertex[w.vertex()] = no_id;
|
|
|
548 |
w = w.next();
|
|
|
549 |
while(status[w.vertex()] != 1 || !same_level(fun[w.vertex()], fun[w.opp().vertex()]))
|
|
|
550 |
w = w.circulate_vertex_cw();
|
631 |
janba |
551 |
lsi.no_vertices += 1;
|
|
|
552 |
|
|
|
553 |
}
|
|
|
554 |
lsi.h = w.halfedge();
|
|
|
555 |
lsi.length = level_set_length;
|
|
|
556 |
double param = 0;
|
|
|
557 |
|
|
|
558 |
do
|
572 |
jab |
559 |
{
|
631 |
janba |
560 |
double angle = 2.0 * M_PI * param / lsi.length;
|
|
|
561 |
circle_pos[w.opp().vertex()] = Vec2d(cos(angle), sin(angle));
|
|
|
562 |
nailed[w.opp().vertex()] = 1;
|
|
|
563 |
param += length(m, w.halfedge());
|
|
|
564 |
w = w.next();
|
|
|
565 |
while(status[w.vertex()] != 1 || !same_level(fun[w.vertex()], fun[w.opp().vertex()]))
|
|
|
566 |
w = w.circulate_vertex_cw();
|
572 |
jab |
567 |
}
|
631 |
janba |
568 |
while(w.halfedge() != lsi.h);
|
|
|
569 |
level_set_info.push_back(lsi);
|
|
|
570 |
level_set_info.back().print();
|
572 |
jab |
571 |
++no_id;
|
631 |
janba |
572 |
assert(level_set_info.size()==no_id);
|
568 |
jab |
573 |
}
|
|
|
574 |
}
|
|
|
575 |
|
631 |
janba |
576 |
cout << "ids" << no_id << " " << level_set_info.size() << endl;
|
|
|
577 |
for(int i=0;i<level_set_info.size(); ++i)
|
|
|
578 |
for(int j=0;j<level_set_info.size(); ++j)
|
|
|
579 |
if(i != j && same_level(level_set_info[i].fun_value, level_set_info[j].fun_value))
|
|
|
580 |
level_set_info[i].components += 1;
|
572 |
jab |
581 |
|
631 |
janba |
582 |
HalfEdgeID min_length_h;
|
|
|
583 |
double min_length_fun;
|
|
|
584 |
double min_length=FLT_MAX;
|
|
|
585 |
int min_length_id = -1;
|
|
|
586 |
for(int i=0;i<level_set_info.size(); ++i)
|
|
|
587 |
{
|
|
|
588 |
LevelSetInfo& lsi = level_set_info[i];
|
|
|
589 |
if(lsi.components==1 && lsi.length<min_length)
|
|
|
590 |
{
|
|
|
591 |
min_length_h = lsi.h;
|
|
|
592 |
min_length_fun = lsi.fun_value;
|
|
|
593 |
min_length = lsi.length;
|
|
|
594 |
min_length_id = lsi.id;
|
|
|
595 |
}
|
|
|
596 |
}
|
572 |
jab |
597 |
|
631 |
janba |
598 |
smooth_fun(m, nailed, fun);
|
572 |
jab |
599 |
|
631 |
janba |
600 |
FaceAttributeVector<int> segmentation;
|
|
|
601 |
vector<vector<int>> boundaries;
|
|
|
602 |
segment_manifold(m, level_set_id, segmentation, boundaries);
|
572 |
jab |
603 |
|
631 |
janba |
604 |
VertexAttributeVector<Vec3d> cylinder_pos;
|
|
|
605 |
for(auto vid = m.vertices_begin();vid != m.vertices_end(); ++vid)
|
|
|
606 |
if (nailed[*vid])//level_set_id_vertex[*vid] == min_length_id)
|
|
|
607 |
cylinder_pos[*vid] = Vec3d(circle_pos[*vid][0], circle_pos[*vid][1],min_length_fun);
|
|
|
608 |
else
|
|
|
609 |
cylinder_pos[*vid] = Vec3d(0,0,fun[*vid]);
|
|
|
610 |
|
|
|
611 |
HalfEdgeAttributeVector<double> edge_weights(m.allocated_halfedges(), 0);
|
|
|
612 |
FaceAttributeVector<int> included(m.allocated_faces(), 1);
|
|
|
613 |
for(auto fid = m.faces_begin(); fid != m.faces_end(); ++fid)
|
572 |
jab |
614 |
{
|
631 |
janba |
615 |
if(boundaries[segmentation[*fid]].size() == 1)
|
|
|
616 |
included[*fid] = 0;
|
|
|
617 |
}
|
|
|
618 |
compute_edge_weights(m,edge_weights,included);
|
|
|
619 |
VertexAttributeVector<Vec3d> new_cylinder_pos(m.no_vertices());
|
|
|
620 |
for(int i = 0; i < 1500; ++i)
|
|
|
621 |
{
|
|
|
622 |
for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
|
|
|
623 |
if(!nailed[*v])//level_set_id_vertex[*v] != min_length_id)
|
572 |
jab |
624 |
{
|
631 |
janba |
625 |
// recompute_circle_param(m, *v, fun, circle_pos, min_length_fun);
|
|
|
626 |
double w_sum = 0;
|
|
|
627 |
new_cylinder_pos[*v] = Vec3d(0);
|
|
|
628 |
for(Walker wv = m.walker(*v); !wv.full_circle(); wv = wv.circulate_vertex_ccw())
|
|
|
629 |
{
|
|
|
630 |
double w = edge_weights[wv.halfedge()];
|
|
|
631 |
new_cylinder_pos[*v] += w * cylinder_pos[wv.vertex()];
|
|
|
632 |
w_sum += w;
|
|
|
633 |
}
|
|
|
634 |
if(w_sum> 0.0)
|
|
|
635 |
new_cylinder_pos[*v] /= w_sum;
|
|
|
636 |
Vec2d v2d(new_cylinder_pos[*v][0], new_cylinder_pos[*v][1]);
|
|
|
637 |
double l =length(v2d);
|
|
|
638 |
if(l>0.1) {
|
|
|
639 |
new_cylinder_pos[*v][0] /= l;
|
|
|
640 |
new_cylinder_pos[*v][1] /= l;
|
|
|
641 |
}
|
|
|
642 |
if(level_set_id_vertex[*v] != -1)
|
|
|
643 |
new_cylinder_pos[*v][2] = fun[*v];
|
572 |
jab |
644 |
}
|
631 |
janba |
645 |
else
|
|
|
646 |
new_cylinder_pos[*v] = cylinder_pos[*v];
|
|
|
647 |
for(auto v = m.vertices_begin();v != m.vertices_end(); ++v)
|
|
|
648 |
cylinder_pos[*v] = 0.9*cylinder_pos[*v]+ 0.1*new_cylinder_pos[*v];
|
572 |
jab |
649 |
}
|
631 |
janba |
650 |
for(auto vid = m.vertices_begin();vid != m.vertices_end(); ++vid)
|
|
|
651 |
parametrization[*vid] = Vec2d(cylinder_pos[*vid][0],cylinder_pos[*vid][1]);
|
|
|
652 |
return;
|
|
|
653 |
|
|
|
654 |
// for(auto vid = m.vertices_begin();vid != m.vertices_end(); ++vid)
|
|
|
655 |
// m.pos(*vid) = cylinder_pos[*vid];// Vec2d(cylinder_pos[*vid][0],cylinder_pos[*vid][1]);
|
|
|
656 |
|
572 |
jab |
657 |
|
631 |
janba |
658 |
// vector<pair<double,VertexID>> verts;
|
|
|
659 |
// for(auto vid = m.vertices_begin();vid != m.vertices_end(); ++vid)
|
|
|
660 |
// if(!same_level(min_length_fun, fun[*vid]))
|
|
|
661 |
// verts.push_back(pair<double,VertexID>(abs(fun[*vid]-min_length_fun),*vid));
|
|
|
662 |
// sort(verts.begin(), verts.end());
|
|
|
663 |
//
|
|
|
664 |
// for(auto p:verts)
|
|
|
665 |
// {
|
|
|
666 |
// VertexID vid = p.second;
|
|
|
667 |
// recompute_circle_param(m, vid, fun, circle_pos, min_length_fun);
|
|
|
668 |
// }
|
|
|
669 |
// parametrization = circle_pos;
|
|
|
670 |
// return;
|
572 |
jab |
671 |
|
631 |
janba |
672 |
|
|
|
673 |
// // nail max length level set to circle.
|
|
|
674 |
// Walker w = m.walker(min_length_h);
|
|
|
675 |
// priority_queue<pair<double, HalfEdgeID>> hq;
|
|
|
676 |
// float param = 0;
|
|
|
677 |
// do
|
|
|
678 |
// {
|
|
|
679 |
// hq.push(pair<double,HalfEdgeID>(-abs(fun[w.next().vertex()]-min_length_fun),w.halfedge()));
|
|
|
680 |
// hq.push(pair<double,HalfEdgeID>(-abs(fun[w.opp().next().vertex()]-min_length_fun),w.opp().halfedge()));
|
|
|
681 |
//
|
|
|
682 |
// nailed[w.opp().vertex()] = 1;
|
|
|
683 |
// w = w.next();
|
|
|
684 |
// while(level_set_id[w.halfedge()] != min_length_id)
|
|
|
685 |
// w = w.circulate_vertex_cw();
|
|
|
686 |
// }
|
|
|
687 |
// while(w.halfedge() != min_length_h);
|
|
|
688 |
|
|
|
689 |
// parametrize(m, nailed, circle_pos, parametrization, fun, min_length_fun);
|
|
|
690 |
// propagate_values(m, nailed, circle_pos, parametrization, level_set_id_vertex, level_set_info, fun, min_length_fun);
|
|
|
691 |
|
|
|
692 |
//// for(int i=0;i<level_set_info.size(); ++i)
|
|
|
693 |
//// level_set_info[i].print();
|
|
|
694 |
//
|
|
|
695 |
// VertexAttributeVector<Vec3d> circle_center_attrib(m.no_vertices(),Vec3d(0,0,0));
|
|
|
696 |
// for(auto vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
|
|
|
697 |
// {
|
|
|
698 |
// if(level_set_id_vertex[*vid]>-1)
|
|
|
699 |
// {
|
|
|
700 |
// LevelSetInfo& lsi = level_set_info[level_set_id_vertex[*vid]];
|
|
|
701 |
// circle_center_attrib[*vid] = lsi.avg_pos;
|
|
|
702 |
// nailed[*vid] = 1;
|
|
|
703 |
// }
|
|
|
704 |
// }
|
|
|
705 |
//// propagate(m, nailed, circle_center_attrib);
|
|
|
706 |
// Manifold m2 = m;
|
|
|
707 |
// for(auto vid = m2.vertices_begin(); vid != m2.vertices_end(); ++vid)
|
|
|
708 |
// {
|
|
|
709 |
// m2.pos(*vid) = circle_pos[*vid];
|
|
|
710 |
// m2.pos(*vid)[2] = 0.01 * fun[*vid];
|
|
|
711 |
// }
|
|
|
712 |
// obj_save("blob.obj", m2);
|
|
|
713 |
|
|
|
714 |
// for(auto vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
|
|
|
715 |
// {
|
|
|
716 |
// Vec3d p =circle_pos[*vid];//-circle_center_attrib[*vid];
|
|
|
717 |
// parametrization[*vid] = Vec2d(p[0],p[1]);
|
|
|
718 |
// }
|
|
|
719 |
|
|
|
720 |
|
568 |
jab |
721 |
// ----------------------------
|
|
|
722 |
cout << "Remove vertices not on level set curves" << endl;
|
572 |
jab |
723 |
|
568 |
jab |
724 |
vector<VertexID> vid_vec;
|
|
|
725 |
for(VertexIDIterator vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
|
|
|
726 |
if(status[*vid]==0)
|
|
|
727 |
vid_vec.push_back(*vid);
|
|
|
728 |
|
|
|
729 |
random_shuffle(vid_vec.begin(), vid_vec.end());
|
607 |
jrf |
730 |
for (size_t i=0; i<vid_vec.size(); ++i) {
|
568 |
jab |
731 |
FaceID f = m.merge_one_ring(vid_vec[i]);
|
|
|
732 |
if(f != InvalidFaceID)
|
|
|
733 |
shortest_edge_triangulate_face(m, f, level_set_id_vertex);
|
|
|
734 |
else
|
631 |
janba |
735 |
cout << "vertex not removed " << valency(m, vid_vec[i]) << endl;
|
568 |
jab |
736 |
}
|
572 |
jab |
737 |
|
568 |
jab |
738 |
for(FaceIDIterator fid = m.faces_begin(); fid != m.faces_end(); ++fid)
|
|
|
739 |
if(no_edges(m, *fid) > 3)
|
|
|
740 |
shortest_edge_triangulate_face(m, *fid, level_set_id_vertex);
|
|
|
741 |
|
572 |
jab |
742 |
|
631 |
janba |
743 |
// VertexAttributeVector<Vec3d> recalled_positions;
|
|
|
744 |
// for(VertexIDIterator vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
|
|
|
745 |
// recalled_positions[*vid] = m.pos(*vid);
|
|
|
746 |
//
|
|
|
747 |
//
|
572 |
jab |
748 |
TriangleQuality tq_energy(level_set_id_vertex);
|
|
|
749 |
priority_queue_optimization(m, tq_energy);
|
|
|
750 |
|
|
|
751 |
|
|
|
752 |
|
568 |
jab |
753 |
}
|
|
|
754 |
|
572 |
jab |
755 |
void make_height_fun(const HMesh::Manifold& m, HMesh::VertexAttributeVector<double>& fun,
|
|
|
756 |
double& vmin, double& vmax)
|
568 |
jab |
757 |
{
|
|
|
758 |
VertexIDIterator vid = m.vertices_begin();
|
|
|
759 |
vmin = vmax = m.pos(*vid)[2];
|
|
|
760 |
for(; vid != m.vertices_end(); ++vid)
|
|
|
761 |
{
|
631 |
janba |
762 |
double v = dot(m.pos(*vid),Vec3d(0.0,1,0.00));
|
568 |
jab |
763 |
fun[*vid] = v;
|
|
|
764 |
vmin = min(v, vmin);
|
|
|
765 |
vmax = max(v, vmax);
|
|
|
766 |
}
|
|
|
767 |
}
|