1
14
15
22
23 #define VERDICT_EXPORTS
24
25 #include "moab/verdict.h"
26 #include "VerdictVector.hpp"
27 #include "verdict_defines.hpp"
28 #include "V_GaussIntegration.hpp"
29 #include <memory.h>
30
31
32 double verdict_quad_size = 0;
33
34
37 int get_weight( double& m11, double& m21, double& m12, double& m22 )
38 {
39
40 m11 = 1;
41 m21 = 0;
42 m12 = 0;
43 m22 = 1;
44
45 double scale = sqrt( verdict_quad_size / ( m11 * m22 - m21 * m12 ) );
46
47 m11 *= scale;
48 m21 *= scale;
49 m12 *= scale;
50 m22 *= scale;
51
52 return 1;
53 }
54
55
56 C_FUNC_DEF void v_set_quad_size( double size )
57 {
58 verdict_quad_size = size;
59 }
60
61
62 VerdictBoolean is_collapsed_quad( double coordinates[][3] )
63 {
64 if( coordinates[3][0] == coordinates[2][0] && coordinates[3][1] == coordinates[2][1] &&
65 coordinates[3][2] == coordinates[2][2] )
66 return VERDICT_TRUE;
67
68 else
69 return VERDICT_FALSE;
70 }
71
72 void make_quad_edges( VerdictVector edges[4], double coordinates[][3] )
73 {
74
75 edges[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
76 coordinates[1][2] - coordinates[0][2] );
77 edges[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
78 coordinates[2][2] - coordinates[1][2] );
79 edges[2].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
80 coordinates[3][2] - coordinates[2][2] );
81 edges[3].set( coordinates[0][0] - coordinates[3][0], coordinates[0][1] - coordinates[3][1],
82 coordinates[0][2] - coordinates[3][2] );
83 }
84
85 void signed_corner_areas( double areas[4], double coordinates[][3] )
86 {
87 VerdictVector edges[4];
88 make_quad_edges( edges, coordinates );
89
90 VerdictVector corner_normals[4];
91 corner_normals[0] = edges[3] * edges[0];
92 corner_normals[1] = edges[0] * edges[1];
93 corner_normals[2] = edges[1] * edges[2];
94 corner_normals[3] = edges[2] * edges[3];
95
96
97 VerdictVector principal_axes[2];
98 principal_axes[0] = edges[0] - edges[2];
99 principal_axes[1] = edges[1] - edges[3];
100
101
102 VerdictVector unit_center_normal;
103 unit_center_normal = principal_axes[0] * principal_axes[1];
104 unit_center_normal.normalize();
105
106 areas[0] = unit_center_normal % corner_normals[0];
107 areas[1] = unit_center_normal % corner_normals[1];
108 areas[2] = unit_center_normal % corner_normals[2];
109 areas[3] = unit_center_normal % corner_normals[3];
110 }
111
112
121 void localize_quad_coordinates( VerdictVector nodes[4] )
122 {
123 int i;
124 VerdictVector global[4] = { nodes[0], nodes[1], nodes[2], nodes[3] };
125
126 VerdictVector center = ( global[0] + global[1] + global[2] + global[3] ) / 4.0;
127 for( i = 0; i < 4; i++ )
128 global[i] -= center;
129
130 VerdictVector vector_diff;
131 VerdictVector vector_sum;
132 VerdictVector ref_point( 0.0, 0.0, 0.0 );
133 VerdictVector tmp_vector, normal( 0.0, 0.0, 0.0 );
134 VerdictVector vector1, vector2;
135
136 for( i = 0; i < 4; i++ )
137 {
138 vector1 = global[i];
139 vector2 = global[( i + 1 ) % 4];
140 vector_diff = vector2 - vector1;
141 ref_point += vector1;
142 vector_sum = vector1 + vector2;
143
144 tmp_vector.set( vector_diff.y() * vector_sum.z(), vector_diff.z() * vector_sum.x(),
145 vector_diff.x() * vector_sum.y() );
146 normal += tmp_vector;
147 }
148
149 normal.normalize();
150 normal *= -1.0;
151
152 VerdictVector local_x_axis = global[1] - global[0];
153 local_x_axis.normalize();
154
155 VerdictVector local_y_axis = normal * local_x_axis;
156 local_y_axis.normalize();
157
158 for( i = 0; i < 4; i++ )
159 {
160 nodes[i].x( global[i] % local_x_axis );
161 nodes[i].y( global[i] % local_y_axis );
162 nodes[i].z( global[i] % normal );
163 }
164 }
165
166
170 void localize_quad_for_ef( VerdictVector node_pos[4] )
171 {
172
173 VerdictVector centroid( node_pos[0] );
174 centroid += node_pos[1];
175 centroid += node_pos[2];
176 centroid += node_pos[3];
177
178 centroid /= 4.0;
179
180 node_pos[0] -= centroid;
181 node_pos[1] -= centroid;
182 node_pos[2] -= centroid;
183 node_pos[3] -= centroid;
184
185 VerdictVector rotate = node_pos[1] + node_pos[2] - node_pos[3] - node_pos[0];
186 rotate.normalize();
187
188 double cosine = rotate.x();
189 double sine = rotate.y();
190
191 double xnew;
192
193 for( int i = 0; i < 4; i++ )
194 {
195 xnew = cosine * node_pos[i].x() + sine * node_pos[i].y();
196 node_pos[i].y( -sine * node_pos[i].x() + cosine * node_pos[i].y() );
197 node_pos[i].x( xnew );
198 }
199 }
200
201
204 VerdictVector quad_normal( double coordinates[][3] )
205 {
206
207 VerdictVector edge0, edge1;
208
209 edge0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
210 coordinates[1][2] - coordinates[0][2] );
211
212 edge1.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
213 coordinates[3][2] - coordinates[0][2] );
214
215 VerdictVector norm0 = edge0 * edge1;
216 norm0.normalize();
217
218
219
220
221 edge0.set( coordinates[2][0] - coordinates[3][0], coordinates[2][1] - coordinates[3][1],
222 coordinates[2][2] - coordinates[3][2] );
223
224 edge1.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
225 coordinates[2][2] - coordinates[1][2] );
226
227 VerdictVector norm2 = edge0 * edge1;
228 norm2.normalize();
229
230
231
232 if( ( norm0 % norm2 ) > 0.0 )
233 {
234 norm0 += norm2;
235 norm0 *= 0.5;
236 return norm0;
237 }
238
239
240
241 edge0.set( coordinates[1][0] - coordinates[2][0], coordinates[1][1] - coordinates[2][1],
242 coordinates[1][2] - coordinates[2][2] );
243
244 edge1.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
245 coordinates[1][2] - coordinates[0][2] );
246
247 VerdictVector norm1 = edge0 * edge1;
248 norm1.normalize();
249
250 if( ( norm0 % norm1 ) > 0.0 )
251 {
252 norm0 += norm1;
253 norm0 *= 0.5;
254 return norm0;
255 }
256 else
257 {
258 norm2 += norm1;
259 norm2 *= 0.5;
260 return norm2;
261 }
262 }
263
264
271 C_FUNC_DEF double v_quad_edge_ratio( int , double coordinates[][3] )
272 {
273 VerdictVector edges[4];
274 make_quad_edges( edges, coordinates );
275
276 double a2 = edges[0].length_squared();
277 double b2 = edges[1].length_squared();
278 double c2 = edges[2].length_squared();
279 double d2 = edges[3].length_squared();
280
281 double mab, Mab, mcd, Mcd, m2, M2;
282 if( a2 < b2 )
283 {
284 mab = a2;
285 Mab = b2;
286 }
287 else
288 {
289 mab = b2;
290 Mab = a2;
291 }
292 if( c2 < d2 )
293 {
294 mcd = c2;
295 Mcd = d2;
296 }
297 else
298 {
299 mcd = d2;
300 Mcd = c2;
301 }
302 m2 = mab < mcd ? mab : mcd;
303 M2 = Mab > Mcd ? Mab : Mcd;
304
305 if( m2 < VERDICT_DBL_MIN )
306 return (double)VERDICT_DBL_MAX;
307 else
308 {
309 double edge_ratio = sqrt( M2 / m2 );
310
311 if( edge_ratio > 0 ) return (double)VERDICT_MIN( edge_ratio, VERDICT_DBL_MAX );
312 return (double)VERDICT_MAX( edge_ratio, -VERDICT_DBL_MAX );
313 }
314 }
315
316
321 C_FUNC_DEF double v_quad_max_edge_ratio( int , double coordinates[][3] )
322 {
323 VerdictVector quad_nodes[4];
324 quad_nodes[0].set( coordinates[0][0], coordinates[0][1], coordinates[0][2] );
325 quad_nodes[1].set( coordinates[1][0], coordinates[1][1], coordinates[1][2] );
326 quad_nodes[2].set( coordinates[2][0], coordinates[2][1], coordinates[2][2] );
327 quad_nodes[3].set( coordinates[3][0], coordinates[3][1], coordinates[3][2] );
328
329 VerdictVector principal_axes[2];
330 principal_axes[0] = quad_nodes[1] + quad_nodes[2] - quad_nodes[0] - quad_nodes[3];
331 principal_axes[1] = quad_nodes[2] + quad_nodes[3] - quad_nodes[0] - quad_nodes[1];
332
333 double len1 = principal_axes[0].length();
334 double len2 = principal_axes[1].length();
335
336 if( len1 < VERDICT_DBL_MIN || len2 < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
337
338 double max_edge_ratio = VERDICT_MAX( len1 / len2, len2 / len1 );
339
340 if( max_edge_ratio > 0 ) return (double)VERDICT_MIN( max_edge_ratio, VERDICT_DBL_MAX );
341 return (double)VERDICT_MAX( max_edge_ratio, -VERDICT_DBL_MAX );
342 }
343
344
351 C_FUNC_DEF double v_quad_aspect_ratio( int , double coordinates[][3] )
352 {
353
354 VerdictVector edges[4];
355 make_quad_edges( edges, coordinates );
356
357 double a1 = edges[0].length();
358 double b1 = edges[1].length();
359 double c1 = edges[2].length();
360 double d1 = edges[3].length();
361
362 double ma = a1 > b1 ? a1 : b1;
363 double mb = c1 > d1 ? c1 : d1;
364 double hm = ma > mb ? ma : mb;
365
366 VerdictVector ab = edges[0] * edges[1];
367 VerdictVector cd = edges[2] * edges[3];
368 double denominator = ab.length() + cd.length();
369
370 if( denominator < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
371
372 double aspect_ratio = .5 * hm * ( a1 + b1 + c1 + d1 ) / denominator;
373
374 if( aspect_ratio > 0 ) return (double)VERDICT_MIN( aspect_ratio, VERDICT_DBL_MAX );
375 return (double)VERDICT_MAX( aspect_ratio, -VERDICT_DBL_MAX );
376 }
377
378
386 C_FUNC_DEF double v_quad_radius_ratio( int , double coordinates[][3] )
387 {
388 static const double normal_coeff = 1. / ( 2. * sqrt( 2. ) );
389
390 VerdictVector edges[4];
391 make_quad_edges( edges, coordinates );
392
393 double a2 = edges[0].length_squared();
394 double b2 = edges[1].length_squared();
395 double c2 = edges[2].length_squared();
396 double d2 = edges[3].length_squared();
397
398 VerdictVector diag;
399 diag.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
400 coordinates[2][2] - coordinates[0][2] );
401 double m2 = diag.length_squared();
402
403 diag.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
404 coordinates[3][2] - coordinates[1][2] );
405 double n2 = diag.length_squared();
406
407 double t0 = a2 > b2 ? a2 : b2;
408 double t1 = c2 > d2 ? c2 : d2;
409 double t2 = m2 > n2 ? m2 : n2;
410 double h2 = t0 > t1 ? t0 : t1;
411 h2 = h2 > t2 ? h2 : t2;
412
413 VerdictVector ab = edges[0] * edges[1];
414 VerdictVector bc = edges[1] * edges[2];
415 VerdictVector cd = edges[2] * edges[3];
416 VerdictVector da = edges[3] * edges[0];
417
418 t0 = da.length();
419 t1 = ab.length();
420 t2 = bc.length();
421 double t3 = cd.length();
422
423 t0 = t0 < t1 ? t0 : t1;
424 t2 = t2 < t3 ? t2 : t3;
425 t0 = t0 < t2 ? t0 : t2;
426
427 if( t0 < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
428
429 double radius_ratio = normal_coeff * sqrt( ( a2 + b2 + c2 + d2 ) * h2 ) / t0;
430
431 if( radius_ratio > 0 ) return (double)VERDICT_MIN( radius_ratio, VERDICT_DBL_MAX );
432 return (double)VERDICT_MAX( radius_ratio, -VERDICT_DBL_MAX );
433 }
434
435
442 C_FUNC_DEF double v_quad_med_aspect_frobenius( int , double coordinates[][3] )
443 {
444
445 VerdictVector edges[4];
446 make_quad_edges( edges, coordinates );
447
448 double a2 = edges[0].length_squared();
449 double b2 = edges[1].length_squared();
450 double c2 = edges[2].length_squared();
451 double d2 = edges[3].length_squared();
452
453 VerdictVector ab = edges[0] * edges[1];
454 VerdictVector bc = edges[1] * edges[2];
455 VerdictVector cd = edges[2] * edges[3];
456 VerdictVector da = edges[3] * edges[0];
457
458 double ab1 = ab.length();
459 double bc1 = bc.length();
460 double cd1 = cd.length();
461 double da1 = da.length();
462
463 if( ab1 < VERDICT_DBL_MIN || bc1 < VERDICT_DBL_MIN || cd1 < VERDICT_DBL_MIN || da1 < VERDICT_DBL_MIN )
464 return (double)VERDICT_DBL_MAX;
465
466 double qsum = ( a2 + b2 ) / ab1;
467 qsum += ( b2 + c2 ) / bc1;
468 qsum += ( c2 + d2 ) / cd1;
469 qsum += ( d2 + a2 ) / da1;
470
471 double med_aspect_frobenius = .125 * qsum;
472
473 if( med_aspect_frobenius > 0 ) return (double)VERDICT_MIN( med_aspect_frobenius, VERDICT_DBL_MAX );
474 return (double)VERDICT_MAX( med_aspect_frobenius, -VERDICT_DBL_MAX );
475 }
476
477
484 C_FUNC_DEF double v_quad_max_aspect_frobenius( int , double coordinates[][3] )
485 {
486
487 VerdictVector edges[4];
488 make_quad_edges( edges, coordinates );
489
490 double a2 = edges[0].length_squared();
491 double b2 = edges[1].length_squared();
492 double c2 = edges[2].length_squared();
493 double d2 = edges[3].length_squared();
494
495 VerdictVector ab = edges[0] * edges[1];
496 VerdictVector bc = edges[1] * edges[2];
497 VerdictVector cd = edges[2] * edges[3];
498 VerdictVector da = edges[3] * edges[0];
499
500 double ab1 = ab.length();
501 double bc1 = bc.length();
502 double cd1 = cd.length();
503 double da1 = da.length();
504
505 if( ab1 < VERDICT_DBL_MIN || bc1 < VERDICT_DBL_MIN || cd1 < VERDICT_DBL_MIN || da1 < VERDICT_DBL_MIN )
506 return (double)VERDICT_DBL_MAX;
507
508 double qmax = ( a2 + b2 ) / ab1;
509
510 double qcur = ( b2 + c2 ) / bc1;
511 qmax = qmax > qcur ? qmax : qcur;
512
513 qcur = ( c2 + d2 ) / cd1;
514 qmax = qmax > qcur ? qmax : qcur;
515
516 qcur = ( d2 + a2 ) / da1;
517 qmax = qmax > qcur ? qmax : qcur;
518
519 double max_aspect_frobenius = .5 * qmax;
520
521 if( max_aspect_frobenius > 0 ) return (double)VERDICT_MIN( max_aspect_frobenius, VERDICT_DBL_MAX );
522 return (double)VERDICT_MAX( max_aspect_frobenius, -VERDICT_DBL_MAX );
523 }
524
525
530 C_FUNC_DEF double v_quad_skew( int , double coordinates[][3] )
531 {
532 VerdictVector node_pos[4];
533 for( int i = 0; i < 4; i++ )
534 node_pos[i].set( coordinates[i][0], coordinates[i][1], coordinates[i][2] );
535
536 VerdictVector principle_axes[2];
537 principle_axes[0] = node_pos[1] + node_pos[2] - node_pos[3] - node_pos[0];
538 principle_axes[1] = node_pos[2] + node_pos[3] - node_pos[0] - node_pos[1];
539
540 if( principle_axes[0].normalize() < VERDICT_DBL_MIN ) return 0.0;
541 if( principle_axes[1].normalize() < VERDICT_DBL_MIN ) return 0.0;
542
543 double skew = fabs( principle_axes[0] % principle_axes[1] );
544
545 return (double)VERDICT_MIN( skew, VERDICT_DBL_MAX );
546 }
547
548
553 C_FUNC_DEF double v_quad_taper( int , double coordinates[][3] )
554 {
555 VerdictVector node_pos[4];
556 for( int i = 0; i < 4; i++ )
557 node_pos[i].set( coordinates[i][0], coordinates[i][1], coordinates[i][2] );
558
559 VerdictVector principle_axes[2];
560 principle_axes[0] = node_pos[1] + node_pos[2] - node_pos[3] - node_pos[0];
561 principle_axes[1] = node_pos[2] + node_pos[3] - node_pos[0] - node_pos[1];
562
563 VerdictVector cross_derivative = node_pos[0] + node_pos[2] - node_pos[1] - node_pos[3];
564
565 double lengths[2];
566 lengths[0] = principle_axes[0].length();
567 lengths[1] = principle_axes[1].length();
568
569
570 lengths[0] = VERDICT_MIN( lengths[0], lengths[1] );
571
572 if( lengths[0] < VERDICT_DBL_MIN ) return VERDICT_DBL_MAX;
573
574 double taper = cross_derivative.length() / lengths[0];
575 return (double)VERDICT_MIN( taper, VERDICT_DBL_MAX );
576 }
577
578
583 C_FUNC_DEF double v_quad_warpage( int , double coordinates[][3] )
584 {
585
586 VerdictVector edges[4];
587 make_quad_edges( edges, coordinates );
588
589 VerdictVector corner_normals[4];
590 corner_normals[0] = edges[3] * edges[0];
591 corner_normals[1] = edges[0] * edges[1];
592 corner_normals[2] = edges[1] * edges[2];
593 corner_normals[3] = edges[2] * edges[3];
594
595 if( corner_normals[0].normalize() < VERDICT_DBL_MIN || corner_normals[1].normalize() < VERDICT_DBL_MIN ||
596 corner_normals[2].normalize() < VERDICT_DBL_MIN || corner_normals[3].normalize() < VERDICT_DBL_MIN )
597 return (double)VERDICT_DBL_MIN;
598
599 double warpage =
600 pow( VERDICT_MIN( corner_normals[0] % corner_normals[2], corner_normals[1] % corner_normals[3] ), 3 );
601
602 if( warpage > 0 ) return (double)VERDICT_MIN( warpage, VERDICT_DBL_MAX );
603 return (double)VERDICT_MAX( warpage, -VERDICT_DBL_MAX );
604 }
605
606
611 C_FUNC_DEF double v_quad_area( int , double coordinates[][3] )
612 {
613
614 double corner_areas[4];
615 signed_corner_areas( corner_areas, coordinates );
616
617 double area = 0.25 * ( corner_areas[0] + corner_areas[1] + corner_areas[2] + corner_areas[3] );
618
619 if( area > 0 ) return (double)VERDICT_MIN( area, VERDICT_DBL_MAX );
620 return (double)VERDICT_MAX( area, -VERDICT_DBL_MAX );
621 }
622
623
628 C_FUNC_DEF double v_quad_stretch( int , double coordinates[][3] )
629 {
630 VerdictVector edges[4], temp;
631 make_quad_edges( edges, coordinates );
632
633 double lengths_squared[4];
634 lengths_squared[0] = edges[0].length_squared();
635 lengths_squared[1] = edges[1].length_squared();
636 lengths_squared[2] = edges[2].length_squared();
637 lengths_squared[3] = edges[3].length_squared();
638
639 temp.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
640 coordinates[2][2] - coordinates[0][2] );
641 double diag02 = temp.length_squared();
642
643 temp.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
644 coordinates[3][2] - coordinates[1][2] );
645 double diag13 = temp.length_squared();
646
647 static const double QUAD_STRETCH_FACTOR = sqrt( 2.0 );
648
649
650 diag02 = VERDICT_MAX( diag02, diag13 );
651
652 if( diag02 < VERDICT_DBL_MIN )
653 return (double)VERDICT_DBL_MAX;
654 else
655 {
656 double stretch =
657 (double)( QUAD_STRETCH_FACTOR * sqrt( VERDICT_MIN( VERDICT_MIN( lengths_squared[0], lengths_squared[1] ),
658 VERDICT_MIN( lengths_squared[2], lengths_squared[3] ) ) /
659 diag02 ) );
660
661 return (double)VERDICT_MIN( stretch, VERDICT_DBL_MAX );
662 }
663 }
664
665
670 C_FUNC_DEF double v_quad_maximum_angle( int , double coordinates[][3] )
671 {
672
673
674
675 if( is_collapsed_quad( coordinates ) == VERDICT_TRUE ) return v_tri_maximum_angle( 3, coordinates );
676
677 double angle;
678 double max_angle = 0.0;
679
680 VerdictVector edges[4];
681 edges[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
682 coordinates[1][2] - coordinates[0][2] );
683 edges[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
684 coordinates[2][2] - coordinates[1][2] );
685 edges[2].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
686 coordinates[3][2] - coordinates[2][2] );
687 edges[3].set( coordinates[0][0] - coordinates[3][0], coordinates[0][1] - coordinates[3][1],
688 coordinates[0][2] - coordinates[3][2] );
689
690
691
692 double length[4];
693 length[0] = edges[0].length();
694 length[1] = edges[1].length();
695 length[2] = edges[2].length();
696 length[3] = edges[3].length();
697
698 if( length[0] <= VERDICT_DBL_MIN || length[1] <= VERDICT_DBL_MIN || length[2] <= VERDICT_DBL_MIN ||
699 length[3] <= VERDICT_DBL_MIN )
700 return 0.0;
701
702 angle = acos( -( edges[0] % edges[1] ) / ( length[0] * length[1] ) );
703 max_angle = VERDICT_MAX( angle, max_angle );
704
705 angle = acos( -( edges[1] % edges[2] ) / ( length[1] * length[2] ) );
706 max_angle = VERDICT_MAX( angle, max_angle );
707
708 angle = acos( -( edges[2] % edges[3] ) / ( length[2] * length[3] ) );
709 max_angle = VERDICT_MAX( angle, max_angle );
710
711 angle = acos( -( edges[3] % edges[0] ) / ( length[3] * length[0] ) );
712 max_angle = VERDICT_MAX( angle, max_angle );
713
714 max_angle = max_angle * 180.0 / VERDICT_PI;
715
716
717 double areas[4];
718 signed_corner_areas( areas, coordinates );
719
720 if( areas[0] < 0 || areas[1] < 0 || areas[2] < 0 || areas[3] < 0 )
721 {
722 max_angle = 360 - max_angle;
723 }
724
725 if( max_angle > 0 ) return (double)VERDICT_MIN( max_angle, VERDICT_DBL_MAX );
726 return (double)VERDICT_MAX( max_angle, -VERDICT_DBL_MAX );
727 }
728
729
734 C_FUNC_DEF double v_quad_minimum_angle( int , double coordinates[][3] )
735 {
736
737
738 if( is_collapsed_quad( coordinates ) == VERDICT_TRUE ) return v_tri_minimum_angle( 3, coordinates );
739
740 double angle;
741 double min_angle = 360.0;
742
743 VerdictVector edges[4];
744 edges[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
745 coordinates[1][2] - coordinates[0][2] );
746 edges[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
747 coordinates[2][2] - coordinates[1][2] );
748 edges[2].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
749 coordinates[3][2] - coordinates[2][2] );
750 edges[3].set( coordinates[0][0] - coordinates[3][0], coordinates[0][1] - coordinates[3][1],
751 coordinates[0][2] - coordinates[3][2] );
752
753
754
755 double length[4];
756 length[0] = edges[0].length();
757 length[1] = edges[1].length();
758 length[2] = edges[2].length();
759 length[3] = edges[3].length();
760
761 if( length[0] <= VERDICT_DBL_MIN || length[1] <= VERDICT_DBL_MIN || length[2] <= VERDICT_DBL_MIN ||
762 length[3] <= VERDICT_DBL_MIN )
763 return 360.0;
764
765 angle = acos( -( edges[0] % edges[1] ) / ( length[0] * length[1] ) );
766 min_angle = VERDICT_MIN( angle, min_angle );
767
768 angle = acos( -( edges[1] % edges[2] ) / ( length[1] * length[2] ) );
769 min_angle = VERDICT_MIN( angle, min_angle );
770
771 angle = acos( -( edges[2] % edges[3] ) / ( length[2] * length[3] ) );
772 min_angle = VERDICT_MIN( angle, min_angle );
773
774 angle = acos( -( edges[3] % edges[0] ) / ( length[3] * length[0] ) );
775 min_angle = VERDICT_MIN( angle, min_angle );
776
777 min_angle = min_angle * 180.0 / VERDICT_PI;
778
779 if( min_angle > 0 ) return (double)VERDICT_MIN( min_angle, VERDICT_DBL_MAX );
780 return (double)VERDICT_MAX( min_angle, -VERDICT_DBL_MAX );
781 }
782
783
788 C_FUNC_DEF double v_quad_oddy( int , double coordinates[][3] )
789 {
790
791 double max_oddy = 0.;
792
793 VerdictVector first, second, node_pos[4];
794
795 double g, g11, g12, g22, cur_oddy;
796 int i;
797
798 for( i = 0; i < 4; i++ )
799 node_pos[i].set( coordinates[i][0], coordinates[i][1], coordinates[i][2] );
800
801 for( i = 0; i < 4; i++ )
802 {
803 first = node_pos[i] - node_pos[( i + 1 ) % 4];
804 second = node_pos[i] - node_pos[( i + 3 ) % 4];
805
806 g11 = first % first;
807 g12 = first % second;
808 g22 = second % second;
809 g = g11 * g22 - g12 * g12;
810
811 if( g < VERDICT_DBL_MIN )
812 cur_oddy = VERDICT_DBL_MAX;
813 else
814 cur_oddy = ( ( g11 - g22 ) * ( g11 - g22 ) + 4. * g12 * g12 ) / 2. / g;
815
816 max_oddy = VERDICT_MAX( max_oddy, cur_oddy );
817 }
818
819 if( max_oddy > 0 ) return (double)VERDICT_MIN( max_oddy, VERDICT_DBL_MAX );
820 return (double)VERDICT_MAX( max_oddy, -VERDICT_DBL_MAX );
821 }
822
823
828 C_FUNC_DEF double v_quad_condition( int , double coordinates[][3] )
829 {
830
831 if( is_collapsed_quad( coordinates ) == VERDICT_TRUE ) return v_tri_condition( 3, coordinates );
832
833 double areas[4];
834 signed_corner_areas( areas, coordinates );
835
836 double max_condition = 0.;
837
838 VerdictVector xxi, xet;
839
840 double condition;
841
842 for( int i = 0; i < 4; i++ )
843 {
844
845 xxi.set( coordinates[i][0] - coordinates[( i + 1 ) % 4][0], coordinates[i][1] - coordinates[( i + 1 ) % 4][1],
846 coordinates[i][2] - coordinates[( i + 1 ) % 4][2] );
847
848 xet.set( coordinates[i][0] - coordinates[( i + 3 ) % 4][0], coordinates[i][1] - coordinates[( i + 3 ) % 4][1],
849 coordinates[i][2] - coordinates[( i + 3 ) % 4][2] );
850
851 if( areas[i] < VERDICT_DBL_MIN )
852 condition = VERDICT_DBL_MAX;
853 else
854 condition = ( xxi % xxi + xet % xet ) / areas[i];
855
856 max_condition = VERDICT_MAX( max_condition, condition );
857 }
858
859 max_condition /= 2;
860
861 if( max_condition > 0 ) return (double)VERDICT_MIN( max_condition, VERDICT_DBL_MAX );
862 return (double)VERDICT_MAX( max_condition, -VERDICT_DBL_MAX );
863 }
864
865
870 C_FUNC_DEF double v_quad_jacobian( int , double coordinates[][3] )
871 {
872
873 if( is_collapsed_quad( coordinates ) == VERDICT_TRUE ) return (double)( v_tri_area( 3, coordinates ) * 2.0 );
874
875 double areas[4];
876 signed_corner_areas( areas, coordinates );
877
878 double jacobian = VERDICT_MIN( VERDICT_MIN( areas[0], areas[1] ), VERDICT_MIN( areas[2], areas[3] ) );
879 if( jacobian > 0 ) return (double)VERDICT_MIN( jacobian, VERDICT_DBL_MAX );
880 return (double)VERDICT_MAX( jacobian, -VERDICT_DBL_MAX );
881 }
882
883
888 C_FUNC_DEF double v_quad_scaled_jacobian( int , double coordinates[][3] )
889 {
890 if( is_collapsed_quad( coordinates ) == VERDICT_TRUE ) return v_tri_scaled_jacobian( 3, coordinates );
891
892 double corner_areas[4], min_scaled_jac = VERDICT_DBL_MAX, scaled_jac;
893 signed_corner_areas( corner_areas, coordinates );
894
895 VerdictVector edges[4];
896 make_quad_edges( edges, coordinates );
897
898 double length[4];
899 length[0] = edges[0].length();
900 length[1] = edges[1].length();
901 length[2] = edges[2].length();
902 length[3] = edges[3].length();
903
904 if( length[0] < VERDICT_DBL_MIN || length[1] < VERDICT_DBL_MIN || length[2] < VERDICT_DBL_MIN ||
905 length[3] < VERDICT_DBL_MIN )
906 return 0.0;
907
908 scaled_jac = corner_areas[0] / ( length[0] * length[3] );
909 min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac );
910
911 scaled_jac = corner_areas[1] / ( length[1] * length[0] );
912 min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac );
913
914 scaled_jac = corner_areas[2] / ( length[2] * length[1] );
915 min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac );
916
917 scaled_jac = corner_areas[3] / ( length[3] * length[2] );
918 min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac );
919
920 if( min_scaled_jac > 0 ) return (double)VERDICT_MIN( min_scaled_jac, VERDICT_DBL_MAX );
921 return (double)VERDICT_MAX( min_scaled_jac, -VERDICT_DBL_MAX );
922 }
923
924
929 C_FUNC_DEF double v_quad_shear( int , double coordinates[][3] )
930 {
931 double scaled_jacobian = v_quad_scaled_jacobian( 4, coordinates );
932
933 if( scaled_jacobian <= VERDICT_DBL_MIN )
934 return 0.0;
935 else
936 return (double)VERDICT_MIN( scaled_jacobian, VERDICT_DBL_MAX );
937 }
938
939
944 C_FUNC_DEF double v_quad_shape( int , double coordinates[][3] )
945 {
946
947 double corner_areas[4], min_shape = VERDICT_DBL_MAX, shape;
948 signed_corner_areas( corner_areas, coordinates );
949
950 VerdictVector edges[4];
951 make_quad_edges( edges, coordinates );
952
953 double length_squared[4];
954 length_squared[0] = edges[0].length_squared();
955 length_squared[1] = edges[1].length_squared();
956 length_squared[2] = edges[2].length_squared();
957 length_squared[3] = edges[3].length_squared();
958
959 if( length_squared[0] <= VERDICT_DBL_MIN || length_squared[1] <= VERDICT_DBL_MIN ||
960 length_squared[2] <= VERDICT_DBL_MIN || length_squared[3] <= VERDICT_DBL_MIN )
961 return 0.0;
962
963 shape = corner_areas[0] / ( length_squared[0] + length_squared[3] );
964 min_shape = VERDICT_MIN( shape, min_shape );
965
966 shape = corner_areas[1] / ( length_squared[1] + length_squared[0] );
967 min_shape = VERDICT_MIN( shape, min_shape );
968
969 shape = corner_areas[2] / ( length_squared[2] + length_squared[1] );
970 min_shape = VERDICT_MIN( shape, min_shape );
971
972 shape = corner_areas[3] / ( length_squared[3] + length_squared[2] );
973 min_shape = VERDICT_MIN( shape, min_shape );
974
975 min_shape *= 2;
976
977 if( min_shape < VERDICT_DBL_MIN ) min_shape = 0;
978
979 if( min_shape > 0 ) return (double)VERDICT_MIN( min_shape, VERDICT_DBL_MAX );
980 return (double)VERDICT_MAX( min_shape, -VERDICT_DBL_MAX );
981 }
982
983
988 C_FUNC_DEF double v_quad_relative_size_squared( int , double coordinates[][3] )
989 {
990
991 double quad_area = v_quad_area( 4, coordinates );
992 double rel_size = 0;
993
994 v_set_quad_size( quad_area );
995 double w11, w21, w12, w22;
996 get_weight( w11, w21, w12, w22 );
997 double avg_area = determinant( w11, w21, w12, w22 );
998
999 if( avg_area > VERDICT_DBL_MIN )
1000 {
1001
1002 w11 = quad_area / avg_area;
1003
1004 if( w11 > VERDICT_DBL_MIN )
1005 {
1006 rel_size = VERDICT_MIN( w11, 1 / w11 );
1007 rel_size *= rel_size;
1008 }
1009 }
1010
1011 if( rel_size > 0 ) return (double)VERDICT_MIN( rel_size, VERDICT_DBL_MAX );
1012 return (double)VERDICT_MAX( rel_size, -VERDICT_DBL_MAX );
1013 }
1014
1015
1020 C_FUNC_DEF double v_quad_shape_and_size( int num_nodes, double coordinates[][3] )
1021 {
1022 double shape, size;
1023 size = v_quad_relative_size_squared( num_nodes, coordinates );
1024 shape = v_quad_shape( num_nodes, coordinates );
1025
1026 double shape_and_size = shape * size;
1027
1028 if( shape_and_size > 0 ) return (double)VERDICT_MIN( shape_and_size, VERDICT_DBL_MAX );
1029 return (double)VERDICT_MAX( shape_and_size, -VERDICT_DBL_MAX );
1030 }
1031
1032
1037 C_FUNC_DEF double v_quad_shear_and_size( int num_nodes, double coordinates[][3] )
1038 {
1039 double shear, size;
1040 shear = v_quad_shear( num_nodes, coordinates );
1041 size = v_quad_relative_size_squared( num_nodes, coordinates );
1042
1043 double shear_and_size = shear * size;
1044
1045 if( shear_and_size > 0 ) return (double)VERDICT_MIN( shear_and_size, VERDICT_DBL_MAX );
1046 return (double)VERDICT_MAX( shear_and_size, -VERDICT_DBL_MAX );
1047 }
1048
1049
1052 C_FUNC_DEF double v_quad_distortion( int num_nodes, double coordinates[][3] )
1053 {
1054
1055
1056
1057
1058
1059
1060 double element_area = 0.0, distrt, thickness_gauss;
1061 double cur_jacobian = 0., sign_jacobian, jacobian;
1062 VerdictVector aa, bb, cc, normal_at_point, xin;
1063
1064
1065 int number_of_gauss_points = 0;
1066 if( num_nodes == 4 )
1067 {
1068 number_of_gauss_points = 2;
1069 }
1070 else if( num_nodes == 8 )
1071 {
1072 number_of_gauss_points = 3;
1073 }
1074
1075 int total_number_of_gauss_points = number_of_gauss_points * number_of_gauss_points;
1076
1077 VerdictVector face_normal = quad_normal( coordinates );
1078
1079 double distortion = VERDICT_DBL_MAX;
1080
1081 VerdictVector first, second;
1082
1083 int i;
1084
1085 if( is_collapsed_quad( coordinates ) == VERDICT_TRUE )
1086 {
1087 for( i = 0; i < 3; i++ )
1088 {
1089
1090 first.set( coordinates[i][0] - coordinates[( i + 1 ) % 3][0],
1091 coordinates[i][1] - coordinates[( i + 1 ) % 3][1],
1092 coordinates[i][2] - coordinates[( i + 1 ) % 3][2] );
1093
1094 second.set( coordinates[i][0] - coordinates[( i + 2 ) % 3][0],
1095 coordinates[i][1] - coordinates[( i + 2 ) % 3][1],
1096 coordinates[i][2] - coordinates[( i + 2 ) % 3][2] );
1097
1098 sign_jacobian = ( face_normal % ( first * second ) ) > 0 ? 1. : -1.;
1099 cur_jacobian = sign_jacobian * ( first * second ).length();
1100 distortion = VERDICT_MIN( distortion, cur_jacobian );
1101 }
1102 element_area = ( first * second ).length() / 2.0;
1103 distortion /= element_area;
1104 }
1105 else
1106 {
1107 double shape_function[maxTotalNumberGaussPoints][maxNumberNodes];
1108 double dndy1[maxTotalNumberGaussPoints][maxNumberNodes];
1109 double dndy2[maxTotalNumberGaussPoints][maxNumberNodes];
1110 double weight[maxTotalNumberGaussPoints];
1111
1112
1113 GaussIntegration::initialize( number_of_gauss_points, num_nodes );
1114 GaussIntegration::calculate_shape_function_2d_quad();
1115 GaussIntegration::get_shape_func( shape_function[0], dndy1[0], dndy2[0], weight );
1116
1117
1118 int ife, ja;
1119 for( ife = 0; ife < total_number_of_gauss_points; ife++ )
1120 {
1121 aa.set( 0.0, 0.0, 0.0 );
1122 bb.set( 0.0, 0.0, 0.0 );
1123
1124 for( ja = 0; ja < num_nodes; ja++ )
1125 {
1126 xin.set( coordinates[ja][0], coordinates[ja][1], coordinates[ja][2] );
1127 aa += dndy1[ife][ja] * xin;
1128 bb += dndy2[ife][ja] * xin;
1129 }
1130 normal_at_point = aa * bb;
1131 jacobian = normal_at_point.length();
1132 element_area += weight[ife] * jacobian;
1133 }
1134
1135 double dndy1_at_node[maxNumberNodes][maxNumberNodes];
1136 double dndy2_at_node[maxNumberNodes][maxNumberNodes];
1137
1138 GaussIntegration::calculate_derivative_at_nodes( dndy1_at_node, dndy2_at_node );
1139
1140 VerdictVector normal_at_nodes[9];
1141
1142
1143 int jai;
1144 for( ja = 0; ja < num_nodes; ja++ )
1145 {
1146 aa.set( 0.0, 0.0, 0.0 );
1147 bb.set( 0.0, 0.0, 0.0 );
1148 for( jai = 0; jai < num_nodes; jai++ )
1149 {
1150 xin.set( coordinates[jai][0], coordinates[jai][1], coordinates[jai][2] );
1151 aa += dndy1_at_node[ja][jai] * xin;
1152 bb += dndy2_at_node[ja][jai] * xin;
1153 }
1154 normal_at_nodes[ja] = aa * bb;
1155 normal_at_nodes[ja].normalize();
1156 }
1157
1158
1159 bool flat_element = true;
1160 double dot_product;
1161
1162 for( ja = 0; ja < num_nodes; ja++ )
1163 {
1164 dot_product = normal_at_nodes[0] % normal_at_nodes[ja];
1165 if( fabs( dot_product ) < 0.99 )
1166 {
1167 flat_element = false;
1168 break;
1169 }
1170 }
1171
1172
1173 double thickness;
1174
1175 thickness = 0.001 * sqrt( element_area );
1176
1177
1178 double zl = 0.5773502691896;
1179 if( flat_element ) zl = 0.0;
1180
1181 int no_gauss_pts_z = ( flat_element ) ? 1 : 2;
1182 double thickness_z;
1183 int igz;
1184
1185 for( ife = 0; ife < total_number_of_gauss_points; ife++ )
1186 {
1187
1188 for( igz = 0; igz < no_gauss_pts_z; igz++ )
1189 {
1190 zl = -zl;
1191 thickness_z = zl * thickness / 2.0;
1192
1193 aa.set( 0.0, 0.0, 0.0 );
1194 bb.set( 0.0, 0.0, 0.0 );
1195 cc.set( 0.0, 0.0, 0.0 );
1196
1197 for( ja = 0; ja < num_nodes; ja++ )
1198 {
1199 xin.set( coordinates[ja][0], coordinates[ja][1], coordinates[ja][2] );
1200 xin += thickness_z * normal_at_nodes[ja];
1201 aa += dndy1[ife][ja] * xin;
1202 bb += dndy2[ife][ja] * xin;
1203 thickness_gauss = shape_function[ife][ja] * thickness / 2.0;
1204 cc += thickness_gauss * normal_at_nodes[ja];
1205 }
1206
1207 normal_at_point = aa * bb;
1208
1209 distrt = cc % normal_at_point;
1210 if( distrt < distortion ) distortion = distrt;
1211 }
1212 }
1213
1214
1215 for( ja = 0; ja < num_nodes; ja++ )
1216 {
1217 for( igz = 0; igz < no_gauss_pts_z; igz++ )
1218 {
1219 zl = -zl;
1220 thickness_z = zl * thickness / 2.0;
1221
1222 aa.set( 0.0, 0.0, 0.0 );
1223 bb.set( 0.0, 0.0, 0.0 );
1224 cc.set( 0.0, 0.0, 0.0 );
1225
1226 for( jai = 0; jai < num_nodes; jai++ )
1227 {
1228 xin.set( coordinates[jai][0], coordinates[jai][1], coordinates[jai][2] );
1229 xin += thickness_z * normal_at_nodes[ja];
1230 aa += dndy1_at_node[ja][jai] * xin;
1231 bb += dndy2_at_node[ja][jai] * xin;
1232 if( jai == ja )
1233 thickness_gauss = thickness / 2.0;
1234 else
1235 thickness_gauss = 0.;
1236 cc += thickness_gauss * normal_at_nodes[jai];
1237 }
1238 }
1239 normal_at_point = aa * bb;
1240 sign_jacobian = ( face_normal % normal_at_point ) > 0 ? 1. : -1.;
1241 distrt = sign_jacobian * ( cc % normal_at_point );
1242
1243 if( distrt < distortion ) distortion = distrt;
1244 }
1245
1246 if( element_area * thickness != 0 )
1247 distortion *= 8. / ( element_area * thickness );
1248 else
1249 distortion *= 8.;
1250 }
1251
1252 return (double)distortion;
1253 }
1254
1255
1258 C_FUNC_DEF void v_quad_quality( int num_nodes,
1259 double coordinates[][3],
1260 unsigned int metrics_request_flag,
1261 QuadMetricVals* metric_vals )
1262 {
1263
1264 memset( metric_vals, 0, sizeof( QuadMetricVals ) );
1265
1266
1267
1268
1280
1281
1282 VerdictVector edges[4];
1283 make_quad_edges( edges, coordinates );
1284
1285 double areas[4];
1286 signed_corner_areas( areas, coordinates );
1287
1288 double lengths[4];
1289 lengths[0] = edges[0].length();
1290 lengths[1] = edges[1].length();
1291 lengths[2] = edges[2].length();
1292 lengths[3] = edges[3].length();
1293
1294 VerdictBoolean is_collapsed = is_collapsed_quad( coordinates );
1295
1296
1297 if( is_collapsed == VERDICT_TRUE && metrics_request_flag & ( V_QUAD_MINIMUM_ANGLE | V_QUAD_MAXIMUM_ANGLE |
1298 V_QUAD_JACOBIAN | V_QUAD_SCALED_JACOBIAN ) )
1299 {
1300 if( metrics_request_flag & V_QUAD_MINIMUM_ANGLE )
1301 metric_vals->minimum_angle = v_tri_minimum_angle( 3, coordinates );
1302 if( metrics_request_flag & V_QUAD_MAXIMUM_ANGLE )
1303 metric_vals->maximum_angle = v_tri_maximum_angle( 3, coordinates );
1304 if( metrics_request_flag & V_QUAD_JACOBIAN )
1305 metric_vals->jacobian = (double)( v_tri_area( 3, coordinates ) * 2.0 );
1306 if( metrics_request_flag & V_QUAD_SCALED_JACOBIAN )
1307 metric_vals->jacobian = (double)( v_tri_scaled_jacobian( 3, coordinates ) * 2.0 );
1308 }
1309
1310
1311 if( metrics_request_flag & ( V_QUAD_MINIMUM_ANGLE | V_QUAD_MAXIMUM_ANGLE ) && is_collapsed == VERDICT_FALSE )
1312 {
1313
1314 double angles[4];
1315 angles[0] = acos( -( edges[0] % edges[1] ) / ( lengths[0] * lengths[1] ) );
1316 angles[1] = acos( -( edges[1] % edges[2] ) / ( lengths[1] * lengths[2] ) );
1317 angles[2] = acos( -( edges[2] % edges[3] ) / ( lengths[2] * lengths[3] ) );
1318 angles[3] = acos( -( edges[3] % edges[0] ) / ( lengths[3] * lengths[0] ) );
1319
1320 if( lengths[0] <= VERDICT_DBL_MIN || lengths[1] <= VERDICT_DBL_MIN || lengths[2] <= VERDICT_DBL_MIN ||
1321 lengths[3] <= VERDICT_DBL_MIN )
1322 {
1323 metric_vals->minimum_angle = 360.0;
1324 metric_vals->maximum_angle = 0.0;
1325 }
1326 else
1327 {
1328
1329 if( metrics_request_flag & V_QUAD_MINIMUM_ANGLE )
1330 {
1331 metric_vals->minimum_angle = VERDICT_DBL_MAX;
1332 for( int i = 0; i < 4; i++ )
1333 metric_vals->minimum_angle = VERDICT_MIN( angles[i], metric_vals->minimum_angle );
1334 metric_vals->minimum_angle *= 180.0 / VERDICT_PI;
1335 }
1336
1337 if( metrics_request_flag & V_QUAD_MAXIMUM_ANGLE )
1338 {
1339 metric_vals->maximum_angle = 0.0;
1340 for( int i = 0; i < 4; i++ )
1341 metric_vals->maximum_angle = VERDICT_MAX( angles[i], metric_vals->maximum_angle );
1342 metric_vals->maximum_angle *= 180.0 / VERDICT_PI;
1343
1344 if( areas[0] < 0 || areas[1] < 0 || areas[2] < 0 || areas[3] < 0 )
1345 metric_vals->maximum_angle = 360 - metric_vals->maximum_angle;
1346 }
1347 }
1348 }
1349
1350
1351 if( metrics_request_flag & ( V_QUAD_MAX_EDGE_RATIO | V_QUAD_SKEW | V_QUAD_TAPER ) )
1352 {
1353
1354 VerdictVector principal_axes[2];
1355 principal_axes[0] = edges[0] - edges[2];
1356 principal_axes[1] = edges[1] - edges[3];
1357
1358 if( metrics_request_flag & ( V_QUAD_MAX_EDGE_RATIO | V_QUAD_SKEW | V_QUAD_TAPER ) )
1359 {
1360 double len1 = principal_axes[0].length();
1361 double len2 = principal_axes[1].length();
1362
1363
1364 if( metrics_request_flag & V_QUAD_MAX_EDGE_RATIO )
1365 {
1366 if( len1 < VERDICT_DBL_MIN || len2 < VERDICT_DBL_MIN )
1367 metric_vals->max_edge_ratio = VERDICT_DBL_MAX;
1368 else
1369 metric_vals->max_edge_ratio = VERDICT_MAX( len1 / len2, len2 / len1 );
1370 }
1371
1372
1373 if( metrics_request_flag & V_QUAD_TAPER )
1374 {
1375 double min_length = VERDICT_MIN( len1, len2 );
1376
1377 VerdictVector cross_derivative = edges[1] + edges[3];
1378
1379 if( min_length < VERDICT_DBL_MIN )
1380 metric_vals->taper = VERDICT_DBL_MAX;
1381 else
1382 metric_vals->taper = cross_derivative.length() / min_length;
1383 }
1384
1385
1386 if( metrics_request_flag & V_QUAD_SKEW )
1387 {
1388 if( principal_axes[0].normalize() < VERDICT_DBL_MIN || principal_axes[1].normalize() < VERDICT_DBL_MIN )
1389 metric_vals->skew = 0.0;
1390 else
1391 metric_vals->skew = fabs( principal_axes[0] % principal_axes[1] );
1392 }
1393 }
1394 }
1395
1396
1397 if( metrics_request_flag & ( V_QUAD_AREA | V_QUAD_RELATIVE_SIZE_SQUARED ) )
1398 {
1399 metric_vals->area = 0.25 * ( areas[0] + areas[1] + areas[2] + areas[3] );
1400 }
1401
1402
1403 if( metrics_request_flag & ( V_QUAD_RELATIVE_SIZE_SQUARED | V_QUAD_SHAPE_AND_SIZE | V_QUAD_SHEAR_AND_SIZE ) )
1404 {
1405 double quad_area = v_quad_area( 4, coordinates );
1406 v_set_quad_size( quad_area );
1407 double w11, w21, w12, w22;
1408 get_weight( w11, w21, w12, w22 );
1409 double avg_area = determinant( w11, w21, w12, w22 );
1410
1411 if( avg_area < VERDICT_DBL_MIN )
1412 metric_vals->relative_size_squared = 0.0;
1413 else
1414 metric_vals->relative_size_squared =
1415 pow( VERDICT_MIN( metric_vals->area / avg_area, avg_area / metric_vals->area ), 2 );
1416 }
1417
1418
1419 if( metrics_request_flag & V_QUAD_JACOBIAN )
1420 {
1421 metric_vals->jacobian = VERDICT_MIN( VERDICT_MIN( areas[0], areas[1] ), VERDICT_MIN( areas[2], areas[3] ) );
1422 }
1423
1424 if( metrics_request_flag & ( V_QUAD_SCALED_JACOBIAN | V_QUAD_SHEAR | V_QUAD_SHEAR_AND_SIZE ) )
1425 {
1426 double scaled_jac, min_scaled_jac = VERDICT_DBL_MAX;
1427
1428 if( lengths[0] < VERDICT_DBL_MIN || lengths[1] < VERDICT_DBL_MIN || lengths[2] < VERDICT_DBL_MIN ||
1429 lengths[3] < VERDICT_DBL_MIN )
1430 {
1431 metric_vals->scaled_jacobian = 0.0;
1432 metric_vals->shear = 0.0;
1433 }
1434 else
1435 {
1436 scaled_jac = areas[0] / ( lengths[0] * lengths[3] );
1437 min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac );
1438
1439 scaled_jac = areas[1] / ( lengths[1] * lengths[0] );
1440 min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac );
1441
1442 scaled_jac = areas[2] / ( lengths[2] * lengths[1] );
1443 min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac );
1444
1445 scaled_jac = areas[3] / ( lengths[3] * lengths[2] );
1446 min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac );
1447
1448 metric_vals->scaled_jacobian = min_scaled_jac;
1449
1450
1451 if( min_scaled_jac <= VERDICT_DBL_MIN )
1452 metric_vals->shear = 0.0;
1453 else
1454 metric_vals->shear = min_scaled_jac;
1455 }
1456 }
1457
1458 if( metrics_request_flag & ( V_QUAD_WARPAGE | V_QUAD_ODDY ) )
1459 {
1460 VerdictVector corner_normals[4];
1461 corner_normals[0] = edges[3] * edges[0];
1462 corner_normals[1] = edges[0] * edges[1];
1463 corner_normals[2] = edges[1] * edges[2];
1464 corner_normals[3] = edges[2] * edges[3];
1465
1466 if( metrics_request_flag & V_QUAD_ODDY )
1467 {
1468 double oddy, max_oddy = 0.0;
1469
1470 double diff, dot_prod;
1471
1472 double length_squared[4];
1473 length_squared[0] = corner_normals[0].length_squared();
1474 length_squared[1] = corner_normals[1].length_squared();
1475 length_squared[2] = corner_normals[2].length_squared();
1476 length_squared[3] = corner_normals[3].length_squared();
1477
1478 if( length_squared[0] < VERDICT_DBL_MIN || length_squared[1] < VERDICT_DBL_MIN ||
1479 length_squared[2] < VERDICT_DBL_MIN || length_squared[3] < VERDICT_DBL_MIN )
1480 metric_vals->oddy = VERDICT_DBL_MAX;
1481 else
1482 {
1483 diff = ( lengths[0] * lengths[0] ) - ( lengths[1] * lengths[1] );
1484 dot_prod = edges[0] % edges[1];
1485 oddy = ( ( diff * diff ) + 4 * dot_prod * dot_prod ) / ( 2 * length_squared[1] );
1486 max_oddy = VERDICT_MAX( oddy, max_oddy );
1487
1488 diff = ( lengths[1] * lengths[1] ) - ( lengths[2] * lengths[2] );
1489 dot_prod = edges[1] % edges[2];
1490 oddy = ( ( diff * diff ) + 4 * dot_prod * dot_prod ) / ( 2 * length_squared[2] );
1491 max_oddy = VERDICT_MAX( oddy, max_oddy );
1492
1493 diff = ( lengths[2] * lengths[2] ) - ( lengths[3] * lengths[3] );
1494 dot_prod = edges[2] % edges[3];
1495 oddy = ( ( diff * diff ) + 4 * dot_prod * dot_prod ) / ( 2 * length_squared[3] );
1496 max_oddy = VERDICT_MAX( oddy, max_oddy );
1497
1498 diff = ( lengths[3] * lengths[3] ) - ( lengths[0] * lengths[0] );
1499 dot_prod = edges[3] % edges[0];
1500 oddy = ( ( diff * diff ) + 4 * dot_prod * dot_prod ) / ( 2 * length_squared[0] );
1501 max_oddy = VERDICT_MAX( oddy, max_oddy );
1502
1503 metric_vals->oddy = max_oddy;
1504 }
1505 }
1506
1507 if( metrics_request_flag & V_QUAD_WARPAGE )
1508 {
1509 if( corner_normals[0].normalize() < VERDICT_DBL_MIN || corner_normals[1].normalize() < VERDICT_DBL_MIN ||
1510 corner_normals[2].normalize() < VERDICT_DBL_MIN || corner_normals[3].normalize() < VERDICT_DBL_MIN )
1511 metric_vals->warpage = VERDICT_DBL_MAX;
1512 else
1513 {
1514 metric_vals->warpage =
1515 pow( VERDICT_MIN( corner_normals[0] % corner_normals[2], corner_normals[1] % corner_normals[3] ),
1516 3 );
1517 }
1518 }
1519 }
1520
1521 if( metrics_request_flag & V_QUAD_STRETCH )
1522 {
1523 VerdictVector temp;
1524
1525 temp.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
1526 coordinates[2][2] - coordinates[0][2] );
1527 double diag02 = temp.length_squared();
1528
1529 temp.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
1530 coordinates[3][2] - coordinates[1][2] );
1531 double diag13 = temp.length_squared();
1532
1533 static const double QUAD_STRETCH_FACTOR = sqrt( 2.0 );
1534
1535
1536 diag02 = VERDICT_MAX( diag02, diag13 );
1537
1538 if( diag02 < VERDICT_DBL_MIN )
1539 metric_vals->stretch = VERDICT_DBL_MAX;
1540 else
1541 metric_vals->stretch =
1542 QUAD_STRETCH_FACTOR *
1543 VERDICT_MIN( VERDICT_MIN( lengths[0], lengths[1] ), VERDICT_MIN( lengths[2], lengths[3] ) ) /
1544 sqrt( diag02 );
1545 }
1546
1547 if( metrics_request_flag & ( V_QUAD_CONDITION | V_QUAD_SHAPE | V_QUAD_SHAPE_AND_SIZE ) )
1548 {
1549 double lengths_squared[4];
1550 lengths_squared[0] = edges[0].length_squared();
1551 lengths_squared[1] = edges[1].length_squared();
1552 lengths_squared[2] = edges[2].length_squared();
1553 lengths_squared[3] = edges[3].length_squared();
1554
1555 if( areas[0] < VERDICT_DBL_MIN || areas[1] < VERDICT_DBL_MIN || areas[2] < VERDICT_DBL_MIN ||
1556 areas[3] < VERDICT_DBL_MIN )
1557 {
1558 metric_vals->condition = VERDICT_DBL_MAX;
1559 metric_vals->shape = 0.0;
1560 }
1561 else
1562 {
1563 double max_condition = 0.0, condition;
1564
1565 condition = ( lengths_squared[0] + lengths_squared[3] ) / areas[0];
1566 max_condition = VERDICT_MAX( max_condition, condition );
1567
1568 condition = ( lengths_squared[1] + lengths_squared[0] ) / areas[1];
1569 max_condition = VERDICT_MAX( max_condition, condition );
1570
1571 condition = ( lengths_squared[2] + lengths_squared[1] ) / areas[2];
1572 max_condition = VERDICT_MAX( max_condition, condition );
1573
1574 condition = ( lengths_squared[3] + lengths_squared[2] ) / areas[3];
1575 max_condition = VERDICT_MAX( max_condition, condition );
1576
1577 metric_vals->condition = 0.5 * max_condition;
1578 metric_vals->shape = 2 / max_condition;
1579 }
1580 }
1581
1582 if( metrics_request_flag & V_QUAD_AREA )
1583 {
1584 if( metric_vals->area > 0 ) metric_vals->area = (double)VERDICT_MIN( metric_vals->area, VERDICT_DBL_MAX );
1585 metric_vals->area = (double)VERDICT_MAX( metric_vals->area, -VERDICT_DBL_MAX );
1586 }
1587
1588 if( metrics_request_flag & V_QUAD_MAX_EDGE_RATIO )
1589 {
1590 if( metric_vals->max_edge_ratio > 0 )
1591 metric_vals->max_edge_ratio = (double)VERDICT_MIN( metric_vals->max_edge_ratio, VERDICT_DBL_MAX );
1592 metric_vals->max_edge_ratio = (double)VERDICT_MAX( metric_vals->max_edge_ratio, -VERDICT_DBL_MAX );
1593 }
1594
1595 if( metrics_request_flag & V_QUAD_CONDITION )
1596 {
1597 if( metric_vals->condition > 0 )
1598 metric_vals->condition = (double)VERDICT_MIN( metric_vals->condition, VERDICT_DBL_MAX );
1599 metric_vals->condition = (double)VERDICT_MAX( metric_vals->condition, -VERDICT_DBL_MAX );
1600 }
1601
1602
1603 if( metrics_request_flag & V_QUAD_DISTORTION )
1604 {
1605 metric_vals->distortion = v_quad_distortion( num_nodes, coordinates );
1606
1607 if( metric_vals->distortion > 0 )
1608 metric_vals->distortion = (double)VERDICT_MIN( metric_vals->distortion, VERDICT_DBL_MAX );
1609 metric_vals->distortion = (double)VERDICT_MAX( metric_vals->distortion, -VERDICT_DBL_MAX );
1610 }
1611
1612 if( metrics_request_flag & V_QUAD_JACOBIAN )
1613 {
1614 if( metric_vals->jacobian > 0 )
1615 metric_vals->jacobian = (double)VERDICT_MIN( metric_vals->jacobian, VERDICT_DBL_MAX );
1616 metric_vals->jacobian = (double)VERDICT_MAX( metric_vals->jacobian, -VERDICT_DBL_MAX );
1617 }
1618
1619 if( metrics_request_flag & V_QUAD_MAXIMUM_ANGLE )
1620 {
1621 if( metric_vals->maximum_angle > 0 )
1622 metric_vals->maximum_angle = (double)VERDICT_MIN( metric_vals->maximum_angle, VERDICT_DBL_MAX );
1623 metric_vals->maximum_angle = (double)VERDICT_MAX( metric_vals->maximum_angle, -VERDICT_DBL_MAX );
1624 }
1625
1626 if( metrics_request_flag & V_QUAD_MINIMUM_ANGLE )
1627 {
1628 if( metric_vals->minimum_angle > 0 )
1629 metric_vals->minimum_angle = (double)VERDICT_MIN( metric_vals->minimum_angle, VERDICT_DBL_MAX );
1630 metric_vals->minimum_angle = (double)VERDICT_MAX( metric_vals->minimum_angle, -VERDICT_DBL_MAX );
1631 }
1632
1633 if( metrics_request_flag & V_QUAD_ODDY )
1634 {
1635 if( metric_vals->oddy > 0 ) metric_vals->oddy = (double)VERDICT_MIN( metric_vals->oddy, VERDICT_DBL_MAX );
1636 metric_vals->oddy = (double)VERDICT_MAX( metric_vals->oddy, -VERDICT_DBL_MAX );
1637 }
1638
1639 if( metrics_request_flag & V_QUAD_RELATIVE_SIZE_SQUARED )
1640 {
1641 if( metric_vals->relative_size_squared > 0 )
1642 metric_vals->relative_size_squared =
1643 (double)VERDICT_MIN( metric_vals->relative_size_squared, VERDICT_DBL_MAX );
1644 metric_vals->relative_size_squared =
1645 (double)VERDICT_MAX( metric_vals->relative_size_squared, -VERDICT_DBL_MAX );
1646 }
1647
1648 if( metrics_request_flag & V_QUAD_SCALED_JACOBIAN )
1649 {
1650 if( metric_vals->scaled_jacobian > 0 )
1651 metric_vals->scaled_jacobian = (double)VERDICT_MIN( metric_vals->scaled_jacobian, VERDICT_DBL_MAX );
1652 metric_vals->scaled_jacobian = (double)VERDICT_MAX( metric_vals->scaled_jacobian, -VERDICT_DBL_MAX );
1653 }
1654
1655 if( metrics_request_flag & V_QUAD_SHEAR )
1656 {
1657 if( metric_vals->shear > 0 ) metric_vals->shear = (double)VERDICT_MIN( metric_vals->shear, VERDICT_DBL_MAX );
1658 metric_vals->shear = (double)VERDICT_MAX( metric_vals->shear, -VERDICT_DBL_MAX );
1659 }
1660
1661
1662
1663 if( metrics_request_flag & V_QUAD_SHEAR_AND_SIZE )
1664 {
1665 metric_vals->shear_and_size = metric_vals->shear * metric_vals->relative_size_squared;
1666
1667 if( metric_vals->shear_and_size > 0 )
1668 metric_vals->shear_and_size = (double)VERDICT_MIN( metric_vals->shear_and_size, VERDICT_DBL_MAX );
1669 metric_vals->shear_and_size = (double)VERDICT_MAX( metric_vals->shear_and_size, -VERDICT_DBL_MAX );
1670 }
1671
1672 if( metrics_request_flag & V_QUAD_SHAPE )
1673 {
1674 if( metric_vals->shape > 0 ) metric_vals->shape = (double)VERDICT_MIN( metric_vals->shape, VERDICT_DBL_MAX );
1675 metric_vals->shape = (double)VERDICT_MAX( metric_vals->shape, -VERDICT_DBL_MAX );
1676 }
1677
1678
1679
1680 if( metrics_request_flag & V_QUAD_SHAPE_AND_SIZE )
1681 {
1682 metric_vals->shape_and_size = metric_vals->shape * metric_vals->relative_size_squared;
1683
1684 if( metric_vals->shape_and_size > 0 )
1685 metric_vals->shape_and_size = (double)VERDICT_MIN( metric_vals->shape_and_size, VERDICT_DBL_MAX );
1686 metric_vals->shape_and_size = (double)VERDICT_MAX( metric_vals->shape_and_size, -VERDICT_DBL_MAX );
1687 }
1688
1689 if( metrics_request_flag & V_QUAD_SKEW )
1690 {
1691 if( metric_vals->skew > 0 ) metric_vals->skew = (double)VERDICT_MIN( metric_vals->skew, VERDICT_DBL_MAX );
1692 metric_vals->skew = (double)VERDICT_MAX( metric_vals->skew, -VERDICT_DBL_MAX );
1693 }
1694
1695 if( metrics_request_flag & V_QUAD_STRETCH )
1696 {
1697 if( metric_vals->stretch > 0 )
1698 metric_vals->stretch = (double)VERDICT_MIN( metric_vals->stretch, VERDICT_DBL_MAX );
1699 metric_vals->stretch = (double)VERDICT_MAX( metric_vals->stretch, -VERDICT_DBL_MAX );
1700 }
1701
1702 if( metrics_request_flag & V_QUAD_TAPER )
1703 {
1704 if( metric_vals->taper > 0 ) metric_vals->taper = (double)VERDICT_MIN( metric_vals->taper, VERDICT_DBL_MAX );
1705 metric_vals->taper = (double)VERDICT_MAX( metric_vals->taper, -VERDICT_DBL_MAX );
1706 }
1707
1708 if( metrics_request_flag & V_QUAD_WARPAGE )
1709 {
1710 if( metric_vals->warpage > 0 )
1711 metric_vals->warpage = (double)VERDICT_MIN( metric_vals->warpage, VERDICT_DBL_MAX );
1712 metric_vals->warpage = (double)VERDICT_MAX( metric_vals->warpage, -VERDICT_DBL_MAX );
1713 }
1714
1715 if( metrics_request_flag & V_QUAD_MED_ASPECT_FROBENIUS )
1716 metric_vals->med_aspect_frobenius = v_quad_med_aspect_frobenius( 4, coordinates );
1717 if( metrics_request_flag & V_QUAD_MAX_ASPECT_FROBENIUS )
1718 metric_vals->max_aspect_frobenius = v_quad_max_aspect_frobenius( 4, coordinates );
1719 if( metrics_request_flag & V_QUAD_EDGE_RATIO ) metric_vals->edge_ratio = v_quad_edge_ratio( 4, coordinates );
1720 if( metrics_request_flag & V_QUAD_ASPECT_RATIO ) metric_vals->aspect_ratio = v_quad_aspect_ratio( 4, coordinates );
1721 if( metrics_request_flag & V_QUAD_RADIUS_RATIO ) metric_vals->radius_ratio = v_quad_radius_ratio( 4, coordinates );
1722 }