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