16 #include "vectorizer.h"
28 extern int tri_indices[5][3];
29 extern int quad_indices[9][5];
31 extern int lin_np_quad[2];
35 Vectorizer::Vectorizer() : LinearizerBase(), component_x(0), value_type_x(0), component_y(0), value_type_y(0), curvature_epsilon(1e-3)
39 dashes_count = dashes_size = 0;
42 int Vectorizer::create_vertex(
double x,
double y,
double xvalue,
double yvalue)
45 #pragma omp critical(realloc_vertices)
54 int Vectorizer::get_vertex(
int p1,
int p2,
double x,
double y,
double xvalue,
double yvalue)
57 if(p1 > p2) std::swap(p1, p2);
58 int index = this->hash(p1, p2);
60 if(index < this->vertex_count)
63 while (i >= 0 && i < this->vertex_count)
65 if(this->
info[i][0] == p1 && this->
info[i][1] == p2)
75 #pragma omp critical(realloc_vertices)
81 this->
info[i][0] = p1;
82 this->
info[i][1] = p2;
88 void Vectorizer::process_triangle(MeshFunction<double>** fns,
int iv0,
int iv1,
int iv2,
int level,
89 double* xval,
double* yval,
double* phx,
double* phy,
int* idx,
bool curved)
93 if(level < LIN_MAX_LEVEL)
99 fns[0]->set_quad_order(1, xitem);
100 fns[1]->set_quad_order(1, yitem);
101 xval = fns[0]->get_values(component_x, value_type_x);
102 yval = fns[1]->get_values(component_y, value_type_y);
103 for (i = 0; i < lin_np_tri[1]; i++)
105 double m = (sqrt(sqr(xval[i]) + sqr(yval[i])));
106 #pragma omp critical(max)
107 if(finite(m) && fabs(m) > max)
111 idx = tri_indices[0];
115 RefMap* refmap = fns[0]->get_refmap();
116 phx = refmap->get_phys_x(1);
117 phy = refmap->get_phys_y(1);
122 for (i = 0; i < 4; i++)
124 midval[i][0] = (
verts[iv0][i] +
verts[iv1][i])*0.5;
125 midval[i][1] = (
verts[iv1][i] +
verts[iv2][i])*0.5;
126 midval[i][2] = (
verts[iv2][i] +
verts[iv0][i])*0.5;
134 split = (level < eps);
139 double err = fabs(sqrt(sqr(xval[idx[0]]) + sqr(yval[idx[0]])) - sqrt(sqr(midval[2][0]) + sqr(midval[3][0]))) +
140 fabs(sqrt(sqr(xval[idx[1]]) + sqr(yval[idx[1]])) - sqrt(sqr(midval[2][1]) + sqr(midval[3][1]))) +
141 fabs(sqrt(sqr(xval[idx[2]]) + sqr(yval[idx[2]])) - sqrt(sqr(midval[2][2]) + sqr(midval[3][2])));
142 split = !finite(err) || err > max*3*eps;
148 for (i = 0; i < 3; i++)
149 if(sqr(phx[idx[i]] - midval[0][i]) + sqr(phy[idx[i]] - midval[1][i]) > sqr(fns[0]->get_active_element()->get_diameter()*this->
get_curvature_epsilon()))
157 if(level == 0 && !split)
159 split = (fabs(sqrt(sqr(xval[8]) + sqr(yval[8])) - 0.5*(sqrt(sqr(midval[2][0]) + sqr(midval[3][0])) + sqrt(sqr(midval[2][1]) + sqr(midval[3][1])))) +
160 fabs(sqrt(sqr(xval[9]) + sqr(yval[9])) - 0.5*(sqrt(sqr(midval[2][1]) + sqr(midval[3][1])) + sqrt(sqr(midval[2][2]) + sqr(midval[3][2])))) +
161 fabs(sqrt(sqr(xval[4]) + sqr(yval[4])) - 0.5*(sqrt(sqr(midval[2][2]) + sqr(midval[3][2])) + sqrt(sqr(midval[2][0]) + sqr(midval[3][0]))))) > max*3*eps;
169 for (i = 0; i < 3; i++)
171 midval[0][i] = phx[idx[i]];
172 midval[1][i] = phy[idx[i]];
176 int mid0 = get_vertex(iv0, iv1, midval[0][0], midval[1][0], xval[idx[0]], yval[idx[0]]);
177 int mid1 = get_vertex(iv1, iv2, midval[0][1], midval[1][1], xval[idx[1]], yval[idx[1]]);
178 int mid2 = get_vertex(iv2, iv0, midval[0][2], midval[1][2], xval[idx[2]], yval[idx[2]]);
181 fns[0]->push_transform(0);
if(fns[1] != fns[0]) fns[1]->push_transform(0);
182 process_triangle(fns, iv0, mid0, mid2, level + 1, xval, yval, phx, phy, tri_indices[1], curved);
183 fns[0]->pop_transform();
if(fns[1] != fns[0]) fns[1]->pop_transform();
185 fns[0]->push_transform(1);
if(fns[1] != fns[0]) fns[1]->push_transform(1);
186 process_triangle(fns, mid0, iv1, mid1, level + 1, xval, yval, phx, phy, tri_indices[2], curved);
187 fns[0]->pop_transform();
if(fns[1] != fns[0]) fns[1]->pop_transform();
189 fns[0]->push_transform(2);
if(fns[1] != fns[0]) fns[1]->push_transform(2);
190 process_triangle(fns, mid2, mid1, iv2, level + 1, xval, yval, phx, phy, tri_indices[3], curved);
191 fns[0]->pop_transform();
if(fns[1] != fns[0]) fns[1]->pop_transform();
193 fns[0]->push_transform(3);
if(fns[1] != fns[0]) fns[1]->push_transform(3);
194 process_triangle(fns, mid1, mid2, mid0, level + 1, xval, yval, phx, phy, tri_indices[4], curved);
195 fns[0]->pop_transform();
if(fns[1] != fns[0]) fns[1]->pop_transform();
201 add_triangle(iv0, iv1, iv2, fns[0]->get_active_element()->marker);
204 void Vectorizer::process_quad(MeshFunction<double>** fns,
int iv0,
int iv1,
int iv2,
int iv3,
int level,
205 double* xval,
double* yval,
double* phx,
double* phy,
int* idx,
bool curved)
210 int a = (sqr(
verts[iv1][2]) + sqr(
verts[iv1][3]) > sqr(
verts[iv0][2]) + sqr(
verts[iv0][3])) ? iv0 : iv1;
211 int b = (sqr(
verts[iv2][2]) + sqr(
verts[iv2][3]) > sqr(
verts[iv3][2]) + sqr(
verts[iv3][3])) ? iv2 : iv3;
213 int flip = (a == iv1 || a == iv3) ? 1 : 0;
215 if(level < LIN_MAX_LEVEL)
221 fns[0]->set_quad_order(1, xitem);
222 fns[1]->set_quad_order(1, yitem);
223 xval = fns[0]->get_values(component_x, value_type_x);
224 yval = fns[1]->get_values(component_y, value_type_y);
225 for (i = 0; i < lin_np_quad[1]; i++)
227 double m = sqrt(sqr(xval[i]) + sqr(yval[i]));
228 if(finite(m) && fabs(m) > max)
229 #pragma omp critical(max)
230 if(finite(m) && fabs(m) > max)
235 if(fabs(max) < 1E-10)
238 idx = quad_indices[0];
242 RefMap* refmap = fns[0]->get_refmap();
243 phx = refmap->get_phys_x(1);
244 phy = refmap->get_phys_y(1);
249 for (i = 0; i < 4; i++)
251 midval[i][0] = (
verts[iv0][i] +
verts[iv1][i]) * 0.5;
252 midval[i][1] = (
verts[iv1][i] +
verts[iv2][i]) * 0.5;
253 midval[i][2] = (
verts[iv2][i] +
verts[iv3][i]) * 0.5;
254 midval[i][3] = (
verts[iv3][i] +
verts[iv0][i]) * 0.5;
255 midval[i][4] = (midval[i][0] + midval[i][2]) * 0.5;
263 split = (level < eps);
267 midval[2][4] = flip ? (
verts[iv0][2] +
verts[iv2][2]) * 0.5 : (
verts[iv1][2] +
verts[iv3][2]) * 0.5;
268 midval[3][4] = flip ? (
verts[iv0][3] +
verts[iv2][3]) * 0.5 : (
verts[iv1][3] +
verts[iv3][3]) * 0.5;
271 double err = fabs(sqrt(sqr(xval[idx[0]]) + sqr(yval[idx[0]])) - sqrt(sqr(midval[2][0]) + sqr(midval[3][0]))) +
272 fabs(sqrt(sqr(xval[idx[1]]) + sqr(yval[idx[1]])) - sqrt(sqr(midval[2][1]) + sqr(midval[3][1]))) +
273 fabs(sqrt(sqr(xval[idx[2]]) + sqr(yval[idx[2]])) - sqrt(sqr(midval[2][2]) + sqr(midval[3][2]))) +
274 fabs(sqrt(sqr(xval[idx[3]]) + sqr(yval[idx[3]])) - sqrt(sqr(midval[2][3]) + sqr(midval[3][3]))) +
275 fabs(sqrt(sqr(xval[idx[4]]) + sqr(yval[idx[4]])) - sqrt(sqr(midval[2][4]) + sqr(midval[3][4])));
276 split = !finite(err) || err > max*40*eps;
282 if(sqr(phx[idx[1]] - midval[0][1]) + sqr(phy[idx[1]] - midval[1][1]) > cm2 ||
283 sqr(phx[idx[3]] - midval[0][3]) + sqr(phy[idx[3]] - midval[1][3]) > cm2) split =
true;
285 if(sqr(phx[idx[0]] - midval[0][0]) + sqr(phy[idx[0]] - midval[1][0]) > cm2 ||
286 sqr(phx[idx[2]] - midval[0][2]) + sqr(phy[idx[2]] - midval[1][2]) > cm2) split =
true;
290 if(level == 0 && !split)
292 err = fabs(sqrt(sqr(xval[13]) + sqr(yval[13])) - 0.5*(sqrt(sqr(midval[2][0]) + sqr(midval[3][0])) + sqrt(sqr(midval[2][1]) + sqr(midval[3][1])))) +
293 fabs(sqrt(sqr(xval[17]) + sqr(yval[17])) - 0.5*(sqrt(sqr(midval[2][1]) + sqr(midval[3][1])) + sqrt(sqr(midval[2][2]) + sqr(midval[3][2])))) +
294 fabs(sqrt(sqr(xval[20]) + sqr(yval[20])) - 0.5*(sqrt(sqr(midval[2][2]) + sqr(midval[3][2])) + sqrt(sqr(midval[2][3]) + sqr(midval[3][3])))) +
295 fabs(sqrt(sqr(xval[9]) + sqr(yval[9])) - 0.5*(sqrt(sqr(midval[2][3]) + sqr(midval[3][3])) + sqrt(sqr(midval[2][0]) + sqr(midval[3][0]))));
296 split = !finite(err) || (err) > max*4*eps;
305 for (i = 0; i < 5; i++)
307 midval[0][i] = phx[idx[i]];
308 midval[1][i] = phy[idx[i]];
313 int mid0 = get_vertex(iv0, iv1, midval[0][0], midval[1][0], xval[idx[0]], yval[idx[0]]);
314 int mid1 = get_vertex(iv1, iv2, midval[0][1], midval[1][1], xval[idx[1]], yval[idx[1]]);
315 int mid2 = get_vertex(iv2, iv3, midval[0][2], midval[1][2], xval[idx[2]], yval[idx[2]]);
316 int mid3 = get_vertex(iv3, iv0, midval[0][3], midval[1][3], xval[idx[3]], yval[idx[3]]);
317 int mid4 = get_vertex(mid0, mid2, midval[0][4], midval[1][4], xval[idx[4]], yval[idx[4]]);
320 fns[0]->push_transform(0);
if(fns[1] != fns[0]) fns[1]->push_transform(0); process_quad(fns, iv0, mid0, mid4, mid3, level + 1, xval, yval, phx, phy, quad_indices[1], curved); fns[0]->pop_transform();
if(fns[1] != fns[0]) fns[1]->pop_transform();
321 fns[0]->push_transform(1);
if(fns[1] != fns[0]) fns[1]->push_transform(1); process_quad(fns, mid0, iv1, mid1, mid4, level + 1, xval, yval, phx, phy, quad_indices[2], curved); fns[0]->pop_transform();
if(fns[1] != fns[0]) fns[1]->pop_transform();
322 fns[0]->push_transform(2);
if(fns[1] != fns[0]) fns[1]->push_transform(2); process_quad(fns, mid4, mid1, iv2, mid2, level + 1, xval, yval, phx, phy, quad_indices[3], curved); fns[0]->pop_transform();
if(fns[1] != fns[0]) fns[1]->pop_transform();
323 fns[0]->push_transform(3);
if(fns[1] != fns[0]) fns[1]->push_transform(3); process_quad(fns, mid3, mid4, mid2, iv3, level + 1, xval, yval, phx, phy, quad_indices[4], curved); fns[0]->pop_transform();
if(fns[1] != fns[0]) fns[1]->pop_transform();
331 add_triangle(iv3, iv0, iv1, fns[0]->get_active_element()->marker);
332 add_triangle(iv1, iv2, iv3, fns[0]->get_active_element()->marker);
336 add_triangle(iv0, iv1, iv2, fns[0]->get_active_element()->marker);
337 add_triangle(iv2, iv3, iv0, fns[0]->get_active_element()->marker);
341 void Vectorizer::process_dash(
int iv1,
int iv2)
343 int mid = this->peek_vertex(iv1, iv2);
346 process_dash(iv1, mid);
347 process_dash(mid, iv2);
353 void Vectorizer::find_min_max()
356 this->min_val = 1e100;
357 this->max_val = -1e100;
358 for (
int i = 0; i < this->vertex_count; i++)
361 if(finite(mag) && mag < this->min_val) this->min_val = mag;
362 if(finite(mag) && mag > this->max_val) this->max_val = mag;
364 this->max_val = sqrt(this->max_val);
365 this->min_val = sqrt(this->min_val);
381 this->caughtException = NULL;
384 if(xsln == NULL || ysln == NULL)
385 throw Hermes::Exceptions::Exception(
"One of the solutions is NULL in Vectorizer:process_solution().");
391 this->xitem = xitem_orig;
392 this->yitem = yitem_orig;
400 this->vertex_size = std::max(100 * nn, std::max(this->vertex_size, 50000));
401 this->triangle_size = std::max(150 * nn, std::max(this->triangle_size, 75000));
411 verts = (double4*) malloc(
sizeof(double4) * vertex_size);
412 this->
tris = (int3*) realloc(this->
tris,
sizeof(int3) * this->triangle_size);
416 this->dashes = (int2*) realloc(this->dashes,
sizeof(int2) *
dashes_size);
417 info = (int4*) malloc(
sizeof(int4) * vertex_size);
421 hash_table = (
int*) malloc(
sizeof(
int) * vertex_size);
422 memset(
hash_table, 0xff,
sizeof(
int) * vertex_size);
425 Quad2D *old_quad_x, *old_quad_y;
429 Hermes::vector<const Mesh*> meshes;
430 meshes.push_back(xsln->get_mesh());
431 meshes.push_back(ysln->get_mesh());
435 for(
unsigned int i = 0; i <
Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads); i++)
438 fns[i][0] = xsln->clone();
439 fns[i][0]->set_refmap(
new RefMap);
441 fns[i][1] = ysln->clone();
442 fns[i][1]->set_refmap(
new RefMap);
447 for(
unsigned int i = 0; i <
Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads); i++)
450 trfs[i][0] = fns[i][0];
451 trfs[i][1] = fns[i][1];
479 Traverse trav_masterMax(
true);
480 unsigned int num_states = trav_masterMax.get_num_states(meshes);
482 trav_masterMax.begin(meshes.size(), &(meshes.front()));
484 Traverse* trav =
new Traverse[
Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads)];
486 for(
unsigned int i = 0; i <
Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads); i++)
488 trav[i].begin(meshes.size(), &(meshes.front()), trfs[i]);
489 trav[i].stack = trav_masterMax.stack;
495 int num_threads_used =
Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads);
496 #pragma omp parallel shared(trav_masterMax) private(state_i) num_threads(num_threads_used)
498 #pragma omp for schedule(dynamic, CHUNKSIZE)
499 for(state_i = 0; state_i < num_states; state_i++)
503 Traverse::State current_state;
504 #pragma omp critical(get_next_state)
505 current_state = trav[omp_get_thread_num()].get_next_state(&trav_masterMax.top, &trav_masterMax.id);
509 double* xval = fns[omp_get_thread_num()][0]->get_values(component_x, value_type_x);
510 double* yval = fns[omp_get_thread_num()][1]->get_values(component_y, value_type_y);
512 for (
unsigned int i = 0; i < current_state.e[0]->get_nvert(); i++)
516 #pragma omp critical(max)
517 if(fabs(sqrt(fx*fx + fy*fy)) > max)
518 max = fabs(sqrt(fx*fx + fy*fy));
521 catch(Hermes::Exceptions::Exception& e)
523 if(this->caughtException == NULL)
524 this->caughtException = e.clone();
528 if(this->caughtException == NULL)
529 this->caughtException =
new Hermes::Exceptions::Exception(e.what());
534 trav_masterMax.finish();
535 for(
unsigned int i = 0; i <
Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads); i++)
539 Traverse trav_master(
true);
540 num_states = trav_master.get_num_states(meshes);
542 trav_master.begin(meshes.size(), &(meshes.front()));
544 trav =
new Traverse[
Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads)];
546 for(
unsigned int i = 0; i <
Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads); i++)
548 trav[i].begin(meshes.size(), &(meshes.front()), trfs[i]);
549 trav[i].stack = trav_master.stack;
552 #pragma omp parallel shared(trav_master) private(state_i) num_threads(num_threads_used)
554 #pragma omp for schedule(dynamic, CHUNKSIZE)
555 for(state_i = 0; state_i < num_states; state_i++)
559 Traverse::State current_state;
561 #pragma omp critical (get_next_state)
562 current_state = trav[omp_get_thread_num()].get_next_state(&trav_master.top, &trav_master.id);
566 double* xval = fns[omp_get_thread_num()][0]->get_values(component_x, value_type_x);
567 double* yval = fns[omp_get_thread_num()][1]->get_values(component_y, value_type_y);
569 double* x = fns[omp_get_thread_num()][0]->get_refmap()->
get_phys_x(0);
570 double* y = fns[omp_get_thread_num()][0]->get_refmap()->
get_phys_y(0);
573 for (
unsigned int i = 0; i < current_state.e[0]->get_nvert(); i++)
578 iv[i] = this->get_vertex(-fns[omp_get_thread_num()][0]->get_active_element()->vn[i]->
id, -fns[omp_get_thread_num()][0]->get_active_element()->vn[i]->
id, x[i], y[i], fx, fy);
582 if(current_state.e[0]->is_triangle())
583 process_triangle(fns[omp_get_thread_num()], iv[0], iv[1], iv[2], 0, NULL, NULL, NULL, NULL, NULL, current_state.e[0]->is_curved());
585 process_quad(fns[omp_get_thread_num()], iv[0], iv[1], iv[2], iv[3], 0, NULL, NULL, NULL, NULL, NULL, current_state.e[0]->is_curved());
587 for (
unsigned int i = 0; i < current_state.e[0]->get_nvert(); i++)
588 process_edge(iv[i], iv[current_state.e[0]->next_vert(i)], current_state.e[0]->en[i]->marker);
590 catch(Hermes::Exceptions::Exception& e)
592 if(this->caughtException == NULL)
593 this->caughtException = e.clone();
597 if(this->caughtException == NULL)
598 this->caughtException =
new Hermes::Exceptions::Exception(e.what());
603 trav_master.finish();
604 for(
unsigned int i = 0; i <
Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads); i++)
607 for(
unsigned int j = 0; j < 2; j++)
617 for (
int i = 0; i < this->triangle_count; i++)
619 int iv0 =
tris[i][0], iv1 =
tris[i][1], iv2 =
tris[i][2];
621 int mid0 = peek_vertex(iv0, iv1);
622 int mid1 = peek_vertex(iv1, iv2);
623 int mid2 = peek_vertex(iv2, iv0);
624 if(mid0 >= 0 || mid1 >= 0 || mid2 >= 0)
627 regularize_triangle(iv0, iv1, iv2, mid0, mid1, mid2,
tri_markers[i]);
661 Vectorizer::~Vectorizer()
669 throw Exceptions::Exception(
"Cannot calculate AABB from NULL vertices");
674 int2* Vectorizer::get_dashes()
678 int Vectorizer::get_num_dashes()
683 double4* Vectorizer::get_vertices()
687 int Vectorizer::get_num_vertices()
689 return this->vertex_count;
692 int Vectorizer::add_vertex()
694 if(this->vertex_count >= this->vertex_size)
696 this->vertex_size *= 2;
697 verts = (double4*) realloc(
verts,
sizeof(double4) * vertex_size);
698 this->
info = (int4*) realloc(
info,
sizeof(int4) * vertex_size);
700 memset(this->
hash_table + this->vertex_size / 2, 0xff,
sizeof(
int) * this->vertex_size / 2);
702 return this->vertex_count++;
705 void Vectorizer::add_dash(
int iv1,
int iv2)
710 dashes = (int2*) realloc(dashes,
sizeof(int2) *
dashes_size);