| Bsoft 2.0.5 Bernard's software package

model_poly.cpp
Go to the documentation of this file.
1
9 #include "model_poly.h"
10 #include "model_transform.h"
11 #include "model_views.h"
12 #include "model_util.h"
13 #include "matrix_linear.h"
14 #include "model_links.h"
15 #include "model_compare.h"
16 #include "math_util.h"
17 #include "random_numbers.h"
18 #include "symmetry.h"
19 #include "Vector3.h"
20 #include "linked_list.h"
21 #include "utilities.h"
22
23 // Declaration of global variables
24 extern int verbose; // Level of output to the screen
25
39 int model_poly_faces(Bmodel* model)
40 {
41 int found, nlink(0);
42 double d0;
43 Vector3<double> v0;
44 Bcomponent* comp = NULL;
45 Bcomponent* comp1 = NULL;
46 Bcomponent* comp2 = NULL;
47 Blink* link = NULL;
48
49 for ( comp1 = model->comp; comp1; comp1 = comp1->next ) if ( comp1->sel ) {
50 for ( comp2 = comp1->next; comp2; comp2 = comp2->next ) if ( comp2->sel ) {
51 v0 = (comp1->loc + comp2->loc)/2;
52 d0 = v0.length2();
53 for ( found = 0, comp = model->comp; comp && !found; comp = comp->next )
54 if ( comp != comp1 && comp != comp2 )
55 if ( v0.scalar(comp->loc) > d0 ) found = 1;
56 if ( !found ) {
57 link = link_add(&link, comp1, comp2, 0, 0);
58 if ( !model->link ) model->link = link;
59 nlink++;
60 }
61 }
62 }
63
64 if ( verbose )
65 cout << "Number of links generated: " << nlink << endl << endl;
66
67 return 0;
68 }
69
70 /*
71 @brief Generates polygons based on a vertex network.
72 @param *comp current end vertex used to select next link.
73 @param ilink previously selected link index.
74 @param nlink number of linksso far in polygon.
75 @param *poly polygon structure.
76 @return int number of vertices in polygon.
77
78 A choice is made between the two non-originating connections by calculating
79 the angle between the vertex normal and the cross product of the originating
80 and non-originating bond. If this angle is smaller than 90 degrees, it is
81 selected to continue following. Each pair of bonds are flagged to not traverse
82 the same polygon more than once.
83
84 **/
85 int poly_get_connectivity(Bcomponent* comp, int ilink, int nlink, Bpolygon* poly)
86 {
87 if ( poly->closed ) return nlink;
88 if ( !comp->link[ilink] ) return nlink;
89
90 int i, j;
91 double a, mina = TWOPI;
92 Vector3<double> e1, e2, cp;
93 Bcomponent* compsel = NULL;
94
95 poly->comp[nlink] = comp;
96 nlink++;
97 poly->number = nlink;
98
99 // Exit when the polygon is too large
100 if ( nlink >= MAXLINK ) return nlink;
101
102 // Find the closest link in one direction
103 for ( i=0, j=-1; i<MAXLINK && comp->link[i]; i++ ) {
104 if ( i != ilink ) {
105 e1 = comp->link[ilink]->loc - comp->loc;
106 e2 = comp->link[i]->loc - comp->loc;
107 cp = comp->vec.cross(e1);
108 a = e1.angle(e2);
109 if ( e2.angle(cp) > M_PI_2 ) a = TWOPI - a;
110 if ( mina > a ) {
111 mina = a;
112 j = i;
113 }
114 }
115 }
116 if ( j < 0 ) return 0; // No new links found
117 if ( comp->flag[j] ) return 0; // Test flag value
118 comp->flag[j] = 1; // Set flag value
119
120 compsel = comp->link[j]; // One more comp in polygon
121 if ( compsel == poly->comp[0] ) { // End of polygon
122 poly->closed = 1;
123 } else {
124 for ( i=0; i<MAXLINK && compsel->link[i] != comp; i++ ) ;
125 if ( i<MAXLINK ) nlink = poly_get_connectivity(compsel, i, nlink, poly);
126 }
127
128 if ( verbose & VERB_DEBUG )
129 cout << tab << compsel->id;
130
131 return nlink;
132 }
133
145 int model_poly_generate(Bmodel* model)
146 {
147 int i, j, m, nmod, nmods, n, nc, npm = 20, np[20], npc[20], nv[1000000];
148 double a, maxang;
149 Vector3<double> vec1, vec2, com, rloc;
150 memset(np, 0, npm*sizeof(int));
151 memset(npc, 0, npm*sizeof(int));
152 memset(nv, 0, 1000000*sizeof(int));
153
154 Bmodel* mp;
155 Bcomponent* comp;
156 Bcomponent* comp2;
157 Bpolygon* poly = NULL;
158
159 if ( verbose & VERB_PROCESS )
160 cout << "Generating a polygon list" << endl << endl;
161
162 if ( verbose & VERB_FULL ) {
163 cout << "Vertex normals:" << endl;
164 cout << "ID\tLinks\tx\ty\tz" << endl;
165 }
166
167 // Calculate the vertex normals
168 for ( mp = model; mp; mp = mp->next ) if ( mp->sel ) {
169 com = model_center_of_mass(mp);
170 for ( comp = mp->comp; comp; comp = comp->next ) {
171 rloc = comp->loc - com;
172 for ( i=0; i<MAXLINK && comp->link[i]; i++ ) ;
173 comp->vec = 0;
174 if ( i > 1 ) {
175 maxang = TWOPI/(i - 1.0L);
176 for ( i=1; i<MAXLINK && comp->link[i]; i++ ) {
177 vec1 = comp->link[i]->loc - comp->loc;
178 for ( j=0; j<i; j++ ) {
179 vec2 = comp->link[j]->loc - comp->loc;
180 a = vec1.angle(vec2);
181 if ( a > 0.001 && a < maxang ) {
182 vec2 = comp->loc.normal(comp->link[i]->loc, comp->link[j]->loc);
183 if ( vec2.angle(rloc) > M_PI_2 ) vec2 = -vec2;
184 comp->vec += vec2;
185 }
186 }
187 }
188 }
189 if ( comp->vec == 0 ) comp->vec = rloc;
190 comp->vec.normalize();
191 if ( verbose & VERB_FULL )
192 cout << comp->id << tab << i << tab <<
193 comp->vec[0] << tab << comp->vec[1] << tab << comp->vec[2] << endl;
194 }
195 }
196
197 for ( mp = model; mp; mp = mp->next )
198 for ( comp = mp->comp; comp; comp = comp->next )
199 for ( i=0; i<MAXLINK; i++ ) comp->flag[i] = 0;
200
201 // Generate the polygon list
202 for ( mp = model; mp; mp = mp->next ) if ( mp->sel ) {
203 poly_list_kill(mp->poly);
204 mp->poly = NULL;
205 poly = (Bpolygon *) add_item((char **) &mp->poly, sizeof(Bpolygon));
206 for ( n=0, comp = mp->comp; comp; comp = comp->next ) {
207 for ( i=n=0; i<MAXLINK && comp->link[i]; i++ ) {
208 if ( verbose & VERB_DEBUG )
209 cout << "DEBUG model_poly_generate: " << comp->id << tab << i << endl;
210 n = poly_get_connectivity(comp, i, 0, poly);
211 if ( verbose & VERB_DEBUG )
212 cout << "\tn=" << n << endl;
213 if ( n > 2 && n < MAXLINK )
214 poly = (Bpolygon *) add_item((char **) &poly, sizeof(Bpolygon));
215 else
216 for ( j=0; j<MAXLINK; j++ ) poly->comp[j] = NULL;
217 }
218 }
219 // Prune the last item
220 if ( n < 3 ) {
221 if ( mp->poly->next ) {
222 for ( poly = mp->poly; poly->next->next; poly = poly->next ) ;
223 delete poly->next;
224 poly->next = NULL;
225 } else {
226 delete mp->poly;
227 mp->poly = NULL;
228 }
229 }
230 }
231
232 for ( mp = model; mp; mp = mp->next )
233 for ( comp = mp->comp; comp; comp = comp->next )
234 for ( i=0; i<MAXLINK; i++ ) comp->flag[i] = 0;
235
236 if ( verbose & VERB_FULL )
237 cout << "Polygon normals:\nID\tVert\tx\ty\tz" << endl;
238 for ( n=nc=0, mp = model; mp; mp = mp->next ) if ( mp->sel ) {
239 for ( poly = mp->poly; poly; poly = poly->next, n++ ) {
240 poly->sel = 1;
241 poly->normal = 0;
242 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
243 if ( i+1 < poly->number ) comp = poly->comp[i+1];
244 else comp = poly->comp[0];
245 if ( i+2 < poly->number ) comp2 = poly->comp[i+2];
246 else if ( i+1 < poly->number ) comp2 = poly->comp[0];
247 else comp2 = poly->comp[1];
248 poly->normal += comp->loc.normal(poly->comp[i]->loc, comp2->loc);
249 if ( poly->closed ) {
250 for ( j=0; j<MAXLINK && poly->comp[i]->link[j]; j++ )
251 if ( poly->comp[i]->link[j] == comp )
252 poly->comp[i]->flag[j] = poly->number;
253 }
254 }
255 poly->normal.normalize();
256 if ( poly->number < npm ) {
257 np[poly->number]++;
258 npc[poly->number] += poly->closed;
259 nc += poly->closed;
260 }
261 if ( verbose & VERB_FULL )
262 cout << n+1 << tab << poly->number << tab << poly->normal[0] << tab <<
263 poly->normal[1] << tab << poly->normal[2] << endl;
264 }
265 }
266
267 for ( nmod=nmods=0, mp = model; mp; mp = mp->next, nmod++ ) if ( mp->sel ) {
268 nmods++;
269 for ( comp = mp->comp; comp; comp = comp->next ) {
270 for ( i=m=1; i<MAXLINK && comp->link[i]; i++ ) {
271 m *= 10;
272 for ( j=0; j<i; j++ )
273 if ( comp->flag[j] > comp->flag[i] )
274 swap(comp->flag[i], comp->flag[j]);
275 }
276 for ( i=j=0; i<MAXLINK && comp->link[i]; i++ ) {
277 j += m*comp->flag[i];
278 m /= 10;
279 }
280 nv[j]++;
281 }
282 }
283
284 if ( verbose & VERB_PROCESS ) {
285 cout << "Models: " << nmod << " (" << nmods << ")" << endl;
286 if ( np[3] ) cout << "Triangles: " << np[3] << " (" << npc[3] << ")" << endl;
287 if ( np[4] ) cout << "Tetragons: " << np[4] << " (" << npc[4] << ")" << endl;
288 if ( np[5] ) cout << "Pentagons: " << np[5] << " (" << npc[5] << ")" << endl;
289 if ( np[6] ) cout << "Hexagons: " << np[6] << " (" << npc[6] << ")" << endl;
290 if ( np[7] ) cout << "Heptagons: " << np[7] << " (" << npc[7] << ")" << endl;
291 if ( np[8] ) cout << "Octagons: " << np[8] << " (" << npc[8] << ")" << endl;
292 if ( np[8] ) cout << "Nonagons: " << np[9] << " (" << npc[9] << ")" << endl;
293 if ( np[10] ) cout << "Decagons: " << np[10] << " (" << npc[10] << ")" << endl;
294 cout << "Polygons: " << n << " (" << nc << ")" << endl << endl;
295 cout << "Vertex types:\nIndex\tCount" << endl;
296 for ( i=0; i<1000000; i++ ) if ( nv[i] > 0 ) cout << i << tab << nv[i] << endl;
297 cout << endl;
298 }
299
300 return 0;
301 }
302
313 int model_vertex_types(Bmodel* model)
314 {
315 int i, j;
316 Bstring id;
317 Bmodel* mp;
318 Bcomponent* comp;
319 Bpolygon* poly;
320
321 if ( !model->poly ) model_poly_generate(model);
322
323 for ( mp = model; mp; mp = mp->next ) {
324 for ( poly = mp->poly; poly; poly = poly->next ) {
325 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
326 if ( i+1 < poly->number ) comp = poly->comp[i+1];
327 else comp = poly->comp[0];
328 for ( j=0; j<MAXLINK && poly->comp[i]->link[j] != comp; j++ ) ;
329 poly->comp[i]->flag[j] = poly->number;
330 }
331 }
332 comp_type_list_kill(mp->type);
333 mp->type = NULL;
334 for ( comp = mp->comp; comp; comp = comp->next ) {
335 // comp->type = 0;
336 // for ( i=0; i<MAXLINK && comp->link[i]; i++ )
337 // comp->type += Bstring(comp->flag[i], "%d");
338 // comp->type = comp->type.canonical(1);
339 // comp->type = model_add_type_by_id(mp, comp->type);
340 id = 0;
341 for ( i=0; i<MAXLINK && comp->link[i]; i++ )
342 id += Bstring(comp->flag[i], "%d");
343 id = id.canonical(1);
344 comp->type = model_add_type_by_id(mp, id);
345 }
346 }
347
348 return 0;
349 }
350
351 Bstring component_6digit_type(Bcomponent* comp)
352 {
353 int i, j, t;
354 double a;
355 Vector3<double> v;
356 Bstring id;
357
358 if ( !comp->link[2] ) return 0;
359
360 v = comp->link[0]->loc.normal(comp->link[1]->loc, comp->link[2]->loc);
361 a = comp->loc.angle(v);
362
363 if ( a < M_PI_2 ) {
364 j = 0;
365 t = 1;
366 } else {
367 j = 2;
368 t = -1;
369 }
370
371 // comp->type = 0;
372 // for ( i=0; comp->link[i]; i++, j+=t )
373 // comp->type += Bstring(comp->flag[j]/100, "%d") + Bstring(comp->flag[j]%10, "%d");
374 // comp->type = comp->type.canonical(2);
375 id = 0;
376 for ( i=0; i<MAXLINK && comp->link[i]; i++, j+=t )
377 id += Bstring(comp->flag[j]/100, "%d") + Bstring(comp->flag[j]%10, "%d");
378 id = id.canonical(2);
379
380 return id;
381 }
382
383
396 int model_extended_vertex_types(Bmodel* model)
397 {
398 int i, j, k;
399 Bmodel* mp;
400 Bcomponent* comp;
401 Bcomponent* comp2;
402 Bpolygon* poly;
403 Bstring id;
404
405 if ( !model->poly ) model_poly_generate(model);
406
407 for ( mp = model; mp; mp = mp->next ) if ( mp->sel ) {
408 for ( comp = mp->comp; comp; comp = comp->next )
409 for ( j=0; comp->link[j]; j++ ) comp->flag[j] = 0;
410 for ( poly = mp->poly; poly; poly = poly->next ) {
411 for ( i=0; poly->comp[i]; i++ ) {
412 if ( i+1 < poly->number ) comp = poly->comp[i+1];
413 else comp = poly->comp[0];
414 for ( j=0; poly->comp[i]->link[j] != comp; j++ ) ;
415 poly->comp[i]->flag[j] += 100*poly->number; // First digit = right polygon
416 for ( j=0; poly->comp[i] != comp->link[j]; j++ ) ;
417 comp->flag[j] += 10*poly->number; // Second digit = left polygon
418 }
419 }
420 for ( poly = mp->poly; poly; poly = poly->next ) {
421 for ( i=0; poly->comp[i]; i++ ) {
422 if ( i+1 < poly->number ) comp = poly->comp[i+1];
423 else comp = poly->comp[0];
424 if ( i+2 < poly->number ) comp2 = poly->comp[i+2];
425 else if ( i+1 < poly->number ) comp2 = poly->comp[0];
426 else comp2 = poly->comp[1];
427 for ( j=0; poly->comp[i]->link[j] != comp; j++ ) ;
428 for ( k=0; comp->link[k] == poly->comp[i] || comp->link[k] == comp2; k++ ) ;
429 poly->comp[i]->flag[j] += comp->flag[k]/100; // Third digit = opposed polygon
430 }
431 }
432 comp_type_list_kill(mp->type);
433 mp->type = NULL;
434 for ( comp = mp->comp; comp; comp = comp->next ) {
435 id = component_6digit_type(comp);
436 comp->type = model_add_type_by_id(mp, id);
437 component_hand(id);
438 }
439 }
440
441 return 0;
442 }
443
454 Bmodel* model_poly_dual(Bmodel* model, int order)
455 {
456 long i, n(0);
457 double side, rad, length(0);
458 Bstring id;
459 Bmodel* mp;
460 Bpolygon* poly = NULL;
461 Bcomponent* comp = NULL;
462 Bmodel* model_new = NULL;
463 Bmodel* mp_new = NULL;
464
465 Bstring ctstr[10];
466 ctstr[0] = "VER";
467 ctstr[1] = "MON";
468 ctstr[2] = "DI";
469 ctstr[3] = "TRI";
470 ctstr[4] = "TET";
471 ctstr[5] = "PEN";
472 ctstr[6] = "HEX";
473 ctstr[7] = "HEP";
474 ctstr[8] = "OCT";
475 ctstr[9] = "NON";
476
477 if ( verbose )
478 cout << "Generating a polyhedron dual" << endl << endl;
479
480 for ( mp = model; mp; mp = mp->next ) if ( mp->sel ) {
481 mp_new = (Bmodel *) add_item((char **) &mp_new, sizeof(Bmodel));
482 if ( !model_new ) model_new = mp_new;
483 mp_new->id = mp->id;
484 mp_new->type_id = mp->type_id;
485 mp_new->sel = 1;
486 comp = NULL;
487 for ( n=0, poly = mp->poly; poly; poly = poly->next )
488 if ( poly->closed && ( order < 3 || poly->number == order ) ) {
489 id = Bstring(++n, "%d");
490 comp = component_add(&comp, id);
491 if ( !mp_new->comp ) mp_new->comp = comp;
492 if ( poly->number > 2 && poly->number < 10 ) id = ctstr[poly->number];
493 else id = ctstr[0];
494 comp->type = model_add_type_by_id(mp_new, id);
495 /* switch ( poly->number ) {
496 case 3: comp->type = "TRI"; break;
497 case 4: comp->type = "TET"; break;
498 case 5: comp->type = "PEN"; break;
499 case 6: comp->type = "HEX"; break;
500 case 7: comp->type = "HEP"; break;
501 case 8: comp->type = "OCT"; break;
502 case 9: comp->type = "NON"; break;
503 default: comp->type = "VER";
504 }*/
505 for ( i=0, comp->loc=0; i<MAXLINK && poly->comp[i]; i++ )
506 comp->loc += poly->comp[i]->loc;
507 comp->loc /= i;
508 comp->radius = poly->comp[0]->radius;
509 // comp->type = model_add_type_by_id(mp_new, comp->type);
510 side = poly->comp[0]->loc.distance(poly->comp[poly->number-1]->loc);
511 rad = poly->comp[0]->loc.distance(comp->loc);
512 for ( i=1; poly->comp[i]; i++ ) {
513 side += poly->comp[i]->loc.distance(poly->comp[i-1]->loc);
514 rad += poly->comp[i]->loc.distance(comp->loc);
515 }
516 side /= i;
517 rad /= i;
518 length += sqrt(4*rad*rad - side*side);
519 }
520 }
521
522 length /= n;
523
524 // model_stats(model_new);
525
526 model_link_list_generate(model_new, 1.2*length);
527
528 model_poly_generate(model_new);
529
530 return model_new;
531 }
532
538 int model_poly_analyze(Bmodel* model)
539 {
540 if ( !model->poly ) model_poly_generate(model);
541
542 cout << "Analyzing a model:" << endl;
543
544 Bmodel* mp;
545 Bpolygon* poly;
546
547 int i, j, n;
548 int nn[10], np[10], nt[10];
549
550 cout << "Polygon neighbours:\nID\tVert\tTet\tPent\tHex\tHept" << endl;
551 for ( j=0; j<10; j++ ) np[j] = nt[j] = 0;
552 for ( n=0, mp = model; mp; mp = mp->next ) {
553 for ( poly = mp->poly; poly; poly = poly->next, n++ ) {
554 for ( j=0; j<10; j++ ) nn[j] = 0;
555 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
556 for ( j=0; j<MAXLINK && poly->comp[i]->link[j]; j++ )
557 nn[poly->comp[i]->flag[j]]++;
558 }
559 nn[i] -= i; // Delete self-references
560 if ( nn[i] < 0 ) nn[i] = 0;
561 for ( j=0; j<10; j++ ) nn[j] /= 2; // Compensate for double counting
562 if ( i == 4 ) nt[nn[5]]++;
563 if ( i == 5 ) np[nn[5]]++;
564 cout << n << tab << i << tab << nn[4] << tab << nn[5] << tab << nn[6] << tab << nn[7] << endl;
565 }
566 }
567
568 model_poly_links(model);
569
570 model_poly_angles(model);
571
572 model_poly_regularity(model);
573
574 model_poly_planarity(model);
575
576 // Vector3<double> pax = model_principal_axes(model, NULL);
577 model_principal_axes(model);
578 /*
579 double Ap, As, Vs, g=GOLDEN;
580 Vs = (M_PI*4.0/3.0)*pax.volume();
581 Ap = 4.0*M_PI*pow((pow((double)pax[0]*pax[1],g)+pow((double)pax[0]*pax[2],g)+pow((double)pax[1]*pax[2],g))/3.0, 1/g);
582 As = pow(M_PI, 1.0/3.0) * pow(6*Vs, 2.0/3.0);
583 cout << "Ellipsoid volume: " << Vs << " A3" << endl;
584 // cout << "Polyhedral volume: " << Vp << " A3" << endl;
585 cout << "Sphericity: " << As/Ap << endl;
586 cout << "Axes ratio: " << pax[0]/pax[2] << endl;
587 cout << "Oblateness: " << (pax[1] - pax[2])/(pax[0] - pax[2]) << endl << endl;
588 */
589 return 0;
590 }
591
597 int model_poly_links(Bmodel* model)
598 {
599 int n, nlink;
600 double d, da, ds, dat(0), dst(0);
601 Bmodel* mp;
602 Blink* link;
603
604 if ( verbose )
605 cout << "\nLink lengths:\nID\tAvg\tStd" << endl;
606 for ( n=0, mp = model; mp; mp = mp->next ) if ( mp->sel ) {
607 da = ds = 0;
608 for ( nlink=0, link = mp->link; link; link = link->next, n++, nlink++ ) {
609 d = link->comp[0]->loc.distance(link->comp[1]->loc);
610 link->fom = d*d;
611 da += d;
612 ds += link->fom;
613 }
614 if ( nlink ) {
615 dat += da;
616 dst += ds;
617 da /= nlink;
618 ds = sqrt(ds/nlink - da*da);
619 }
620 if ( verbose )
621 cout << mp->id << tab << da << tab << ds << endl;
622 }
623
624 if ( n ) {
625 dat /= n;
626 dst = dst/n - dat*dat;
627 if ( dst > 0 ) dst = sqrt(dst);
628 else dst = 0;
629 }
630
631 if ( verbose )
632 cout << endl << "Overall link length: " << dat << " (" << dst << ")" << endl << endl;
633
634 return n;
635 }
636
646 int model_poly_angles(Bmodel* model)
647 {
648 int i, n, nc, na[10], mna;
649 double a, a2, pavg, pstd, avg[10], std[10], mavg, mstd, aavg(0), astd(0);
650 Vector3<double> dcen, polycen;
651 Bmodel* mp;
652 Bpolygon* poly;
653 Bcomponent* comp;
654 Bcomponent* comp2;
655 Vector3<double> v1, v2;
656
657 for ( i=0; i<10; i++ ) {
658 na[i] = 0;
659 avg[i] = std[i] = 0;
660 }
661
662 if ( verbose )
663 cout << endl << "Angles:\nID\tVert\tAvg\tStd" << endl;
664 for ( n=0, mp = model; mp; mp = mp->next ) if ( mp->sel ) {
665 for ( comp = mp->comp; comp; comp = comp->next ) comp->fom = 0;
666 mavg = mstd = 0;
667 mna = 0;
668 for ( poly = mp->poly; poly; poly = poly->next, n++ ) {
669 for ( i=0, pavg=pstd=0; i<MAXLINK && poly->comp[i]; i++ ) {
670 if ( i+1 < poly->number ) comp = poly->comp[i+1];
671 else comp = poly->comp[0];
672 if ( i+2 < poly->number ) comp2 = poly->comp[i+2];
673 else if ( i+1 < poly->number ) comp2 = poly->comp[0];
674 else comp2 = poly->comp[1];
675 v1 = poly->comp[i]->loc - comp->loc;
676 v2 = comp2->loc - comp->loc;
677 a = v1.angle(v2);
678 a2 = a*a;
679 pavg += a;
680 pstd += a2;
681 avg[poly->number] += a;
682 std[poly->number] += a2;
683 na[poly->number]++;
684 mavg += a;
685 mstd += a2;
686 mna++;
687 a = M_PI*(1 - 2.0/poly->number) - a;
688 comp->fom += a*a;
689 }
690 pavg /= poly->number;
691 if ( pstd ) {
692 pstd = pstd/poly->number - pavg*pavg;
693 if ( pstd > 0 ) pstd = sqrt(pstd);
694 else pstd = 0;
695 }
696 }
697 aavg += mavg;
698 astd += mstd;
699 if ( mna ) {
700 mavg /= mna;
701 mstd = mstd/mna - mavg*mavg;
702 if ( mstd > 0 ) mstd = sqrt(mstd);
703 else mstd = 0;
704 }
705 for ( nc=0, comp = mp->comp; comp; comp = comp->next, nc++ ) comp->fom = sqrt(comp->fom/3);
706 mp->fom = mavg;
707 if ( verbose )
708 cout << mp->id << tab << nc << tab << mavg*180.0/M_PI << tab << mstd*180.0/M_PI << endl;
709 }
710
711 if ( verbose )
712 cout << endl << "Overall polygon angle average:\nOrder\tNumber\tAvg\tStd" << endl;
713 for ( i=n=0, pavg=pstd=0; i<10; i++ ) if ( na[i] ) {
714 pavg += avg[i];
715 pstd += std[i];
716 n += na[i];
717 avg[i] /= na[i];
718 if ( std[i] ) {
719 std[i] = std[i]/na[i] - avg[i]*avg[i];
720 if ( std[i] > 0 ) std[i] = sqrt(std[i]);
721 else std[i] = 0;
722 }
723 if ( verbose )
724 cout << i << tab << na[i] << tab << avg[i]*180.0/M_PI << tab << std[i]*180.0/M_PI << endl;
725 }
726 pavg /= n;
727 if ( pstd ) pstd = sqrt(pstd/n - pavg*pavg);
728 if ( verbose )
729 cout << "All\t" << n << tab << pavg*180.0/M_PI << tab << pstd*180.0/M_PI << endl << endl;
730
731 return n;
732 }
733
750 double model_poly_regularity(Bmodel* model)
751 {
752 int i, n, mn;
753 double d, davg, mavg, ds, dc, dr, dr_all(0);
754 double dstd, mstd, dstd_all(0), A, Ap(0), Vp(0);
755 Vector3<double> dcen, polycen;
756 Bmodel* mp;
757 Bpolygon* poly;
758
759 Vector3<double> com = model_center_of_mass(model);
760
761 if ( verbose )
762 cout << "Polygon regularity:" << endl;
763 if ( verbose & VERB_LABEL )
764 cout << "Model\tDist\tStd" << endl;
765 if ( verbose & VERB_PROCESS )
766 cout << "ID\tVert\tDist\tStd\tRdist\tSpar\tRad" << endl;
767 for ( n=0, mp = model; mp; mp = mp->next ) {
768 mn = 0;
769 mavg = mstd = 0;
770 for ( poly = mp->poly; poly; poly = poly->next, n++ ) {
771 polycen = 0;
772 dcen = 0;
773 davg = dstd = 0;
774 ds = dc = 0;
775 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
776 polycen += poly->comp[i]->loc; // Center of polygon
777 dcen += poly->comp[i]->loc - com;
778 if ( poly->comp[i+1] ) ds += poly->comp[i]->loc.distance(poly->comp[i+1]->loc);
779 else if ( poly->closed ) ds += poly->comp[i]->loc.distance(poly->comp[0]->loc);
780 }
781 polycen /= i;
782 dcen /= i;
783 dc = dcen.length();
784 ds /= i + poly->closed - 1;
785 A = i*(ds*ds/4)*sqrt((1+cos(TWOPI/i))/(1-cos(TWOPI/i))); // Polygon area
786 Ap += A;
787 Vp += A*dc/3; // Contribution to polyhedral volume
788 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
789 d = polycen.distance(poly->comp[i]->loc);
790 davg += d;
791 dstd += d*d;
792 }
793 mavg += davg;
794 mstd += dstd;
795 mn += i;
796 davg /= i;
797 dstd = dstd/i - davg*davg;
798 // dr = davg*sqrt(2*(1 - cos(TWOPI/i))); // Distance relative to the spar
799 dr = davg*2*sin(M_PI/i); // Distance relative to the spar
800 dr_all += dr;
801 if ( dstd > 0 ) {
802 dstd_all += dstd;
803 dstd = sqrt(dstd);
804 } else dstd = 0;
805 if ( verbose & VERB_PROCESS )
806 cout << n << tab << i << tab << davg << tab << dstd << tab << dr << tab << ds << tab << dc << endl;
807 }
808 if ( mn ) mavg /= mn;
809 if ( mstd ) mstd = sqrt(mstd/mn - mavg*mavg);
810 if ( verbose & VERB_LABEL )
811 cout << mp->id << tab << mavg << tab << mstd << endl;
812 }
813
814 dstd_all = sqrt(dstd_all/n);
815 dr_all /= n;
816 cout << "Regularity deviation: " << dstd_all << " A (" << n << ")" << endl;
817 cout << "Overall spar length: " << dr_all << " A" << endl;
818 cout << "Polyhedral volume: " << Vp << " A3" << endl << endl;
819
820 return dstd_all;
821 }
822
835 double model_poly_planarity(Bmodel* model)
836 {
837 int i, j, m, n;
838 double offset, d, dstd, dstd_all(0);
839 vector<double> b(3);
840 Matrix a(3,3);
841 Vector3<double> polycen, loc, normal;
842 Bmodel* mp;
843 Bpolygon* poly;
844
845 cout << "Polygon planarity:\nID\tVert\tStd" << endl;
846 dstd_all = 0;
847 for ( n=0, mp = model; mp; mp = mp->next ) {
848 for ( poly = mp->poly; poly; poly = poly->next, n++ ) {
849 for ( i=0; i<3; i++ ) b[i] = 0;
850 // for ( i=0; i<9; i++ ) a[i] = 0;
851 a.fill(0);
852 polycen = 0;
853 dstd = 0;
854 for ( m=0; m<MAXLINK && poly->comp[m]; m++ ) {
855 loc = poly->comp[m]->loc;
856 polycen += loc;
857 for ( i=0; i<3; i++ ) {
858 for ( j=0; j<=i; j++ )
859 a[j][i] += loc[i]*loc[j];
860 b[i] += loc[i];
861 }
862 }
863 polycen /= m;
864 for ( i=1; i<3; i++ )
865 for ( j=0; j<i; j++ )
866 a[i][j] = a[j][i];
867 offset = 0;
868 if ( a[0][0] == 0 ) {
869 normal = Vector3<double>(1, 0, 0);
870 } else if ( a[1][1] == 0 ) {
871 normal = Vector3<double>(0, 1, 0);
872 } else if ( a[2][2] == 0 ) {
873 normal = Vector3<double>(0, 0, 1);
874 } else {
875 a.LU_decomposition(b);
876 normal = Vector3<double>(b[0], b[1], b[2]);
877 normal.normalize();
878 offset = polycen.scalar(normal);
879 }
880 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
881 d = poly->comp[i]->loc.scalar(normal) - offset;
882 dstd += d*d;
883 }
884 dstd /= i;
885 dstd_all += dstd;
886 dstd = sqrt(dstd);
887 cout << n << tab << m << tab << dstd << endl;
888 }
889 }
890 dstd_all = sqrt(dstd_all/n);
891 cout << "Planarity deviation: " << dstd_all << " A (" << n << ")" << endl << endl;
892
893 return dstd_all;
894 }
895
915 double model_poly_energy(Bmodel* model, double angle_ref)
916 {
917 int i, j, m, n, nmod, ncomp;
918 double d, ds, dr;
919 double El, Ea, Er, Ep;
920 double Elt(0), Eat(0), Ert(0), Ept(0);
921 double offset;
922 vector<double> b(3);
923 Matrix a(3,3);
924 Vector3<double> polycen, loc, normal, v1, v2;
925 Bmodel* mp;
926 Bcomponent* comp;
927 Bcomponent* comp2;
928 Blink* link;
929 Bpolygon* poly;
930
931 if ( verbose )
932 cout << "Model ID\t#vert\tElink \tEangle \tEpolyreg\tEpolyplan" << endl;
933 for ( nmod = 0, mp = model; mp; mp = mp->next ) if ( mp->sel ) {
934 El = Ea = Er = Ep = 0;
935 for ( ncomp=0, comp = mp->comp; comp; comp = comp->next ) ncomp++;
936 for ( n=0, link = mp->link; link; link = link->next ) {
937 d = link->length - link->comp[0]->loc.distance(link->comp[1]->loc);
938 El += d*d;
939 n++;
940 }
941 if ( El ) El = sqrt(El/n);
942 for ( n=0, poly = mp->poly; poly; poly = poly->next ) {
943 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
944 if ( i+1 < poly->number ) comp = poly->comp[i+1];
945 else comp = poly->comp[0];
946 if ( i+2 < poly->number ) comp2 = poly->comp[i+2];
947 else if ( i+1 < poly->number ) comp2 = poly->comp[0];
948 else comp2 = poly->comp[1];
949 v1 = poly->comp[i]->loc - comp->loc;
950 v2 = comp2->loc - comp->loc;
951 if ( angle_ref > 0 ) d = angle_ref - v1.angle(v2);
952 else d = M_PI*(1 - 2.0/poly->number) - v1.angle(v2);
953 Ea += d*d;
954 n++;
955 }
956 }
957 if ( Ea ) Ea = sqrt(Ea/n);
958 for ( n=0, poly = mp->poly; poly; poly = poly->next ) {
959 polycen = 0;
960 ds = 0;
961 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
962 polycen += poly->comp[i]->loc; // Center of polygon
963 if ( poly->comp[i+1] ) ds += poly->comp[i]->loc.distance(poly->comp[i+1]->loc);
964 else if ( poly->closed ) ds += poly->comp[i]->loc.distance(poly->comp[0]->loc);
965 }
966 polycen /= i;
967 ds /= i + poly->closed - 1;
968 dr = ds/(2*sin(M_PI/i));
969 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
970 d = dr - polycen.distance(poly->comp[i]->loc);
971 Er += d*d;
972 n++;
973 }
974 }
975 if ( Er ) Er = sqrt(Er/n);
976 for ( n=0, poly = mp->poly; poly; poly = poly->next ) {
977 for ( i=0; i<3; i++ ) b[i] = 0;
978 // for ( i=0; i<9; i++ ) a[i] = 0;
979 a.fill(0);
980 polycen = 0;
981 for ( m=0; m<MAXLINK && poly->comp[m]; m++ ) {
982 loc = poly->comp[m]->loc;
983 polycen += loc;
984 for ( i=0; i<3; i++ ) {
985 for ( j=0; j<=i; j++ )
986 a[j][i] += loc[i]*loc[j];
987 b[i] += loc[i];
988 }
989 }
990 polycen /= m;
991 for ( i=1; i<3; i++ )
992 for ( j=0; j<i; j++ )
993 a[i][j] = a[j][i];
994 offset = 0;
995 if ( a[0][0] == 0 ) {
996 normal = Vector3<double>(1, 0, 0);
997 } else if ( a[1][1] == 0 ) {
998 normal = Vector3<double>(0, 1, 0);
999 } else if ( a[2][2] == 0 ) {
1000 normal = Vector3<double>(0, 0, 1);
1001 } else {
1002 a.LU_decomposition(b);
1003 normal = Vector3<double>(b[0], b[1], b[2]);
1004 normal.normalize();
1005 offset = polycen.scalar(normal);
1006 }
1007 for ( i=0; i<MAXLINK && poly->comp[i]; i++ ) {
1008 d = poly->comp[i]->loc.scalar(normal) - offset;
1009 Ep += d*d;
1010 n++;
1011 }
1012 }
1013 if ( Ep ) Ep = sqrt(Ep/n);
1014 if ( verbose )
1015 cout << mp->id << tab << ncomp << tab << El << tab << Ea << tab << Er << tab << Ep << endl;
1016 Elt += El;
1017 Eat += Ea;
1018 Ert += Er;
1019 Ept += Ep;
1020 nmod++;
1021 }
1022
1023 if ( nmod ) {
1024 Elt /= nmod;
1025 Eat /= nmod;
1026 Ert /= nmod;
1027 Ept /= nmod;
1028 }
1029
1030 if ( verbose )
1031 cout << "Average \t \t" << Elt << tab << Eat << tab << Ert << tab << Ept << endl << endl;
1032
1033 return 0;
1034 }
1035
1041 int model_poly_pentagon_adjacency(Bmodel* model)
1042 {
1043 if ( !model->poly ) model_poly_generate(model);
1044
1045 int i, n(0), n3, nn;
1046 Bmodel* mp;
1047 Bcomponent* comp;
1048 Blink* link;
1049 Bpolygon* poly;
1050
1051 if ( verbose )
1052 cout << "Pentagon adjacency:\nModel\tNp\tN3\tNN" << endl;
1053
1054 for ( mp = model; mp; mp = mp->next ) if ( mp->sel ) {
1055 for ( comp = mp->comp; comp; comp = comp->next ) comp->sel = 0;
1056 for ( poly = mp->poly; poly; poly = poly->next ) if ( poly->number == 5 ) {
1057 for ( i=0; i<MAXLINK && poly->comp[i]; i++ )
1058 poly->comp[i]->sel++;
1059 }
1060 for ( nn=0, link = mp->link; link; link = link->next )
1061 if ( link->comp[0]->sel > 2 && link->comp[1]->sel > 2 ) nn++;
1062 for ( n=n3=0, comp = mp->comp; comp; comp = comp->next ) {
1063 if ( comp->sel > 2 ) {
1064 n += comp->sel;
1065 n3++;
1066 } else if ( comp->sel == 2 ) n++;
1067 comp->sel = 1;
1068 }
1069 n /= 2;
1070 if ( verbose )
1071 cout << mp->id << tab << n << tab << n3 << tab << nn << endl;
1072 }
1073
1074 if ( verbose )
1075 cout << endl;
1076
1077 return n;
1078 }
1079
1080 #define NSMAX 100
1081
1095 Bstring model_poly_find_symmetry(Bmodel* model, double threshold)
1096 {
1097 Bstring sym_label("C1");
1098 if ( !model ) return sym_label;
1099
1100 if ( !model->poly ) model_poly_generate(model);
1101
1102 long i, j, n, ns(0), npf, order;
1103 double R;
1104 long* pf;
1105 Bcomponent* comp;
1106 Blink* link;
1107 Bpolygon* poly;
1108 Transform t;
1109 Vector3<double> polycen;
1110
1111 Bsymop* op = new Bsymop[NSMAX];
1112
1113 t.origin = model_center_of_mass(model);
1114 t.angle = M_PI;
1115
1116 double Gr = model_gyration_radius(model);
1117
1118 // Reflections
1119 if ( verbose & VERB_FULL )
1120 cout << "Link\tOrder\tSym\tR" << endl;
1121 for ( n=1, link = model->link; link; link = link->next, n++ ) {
1122 t.axis = link->comp[1]->loc - link->comp[0]->loc;
1123 R = model_reflect_and_compare(model, t.axis, t.origin);
1124 R /= Gr;
1125 if ( R < threshold ) {
1126 if ( verbose & VERB_FULL )
1127 cout << n << "\t1\t1\t" << R << endl;
1128 op[ns].axis = Vector3<double>(t.axis[0], t.axis[1], t.axis[2]);
1129 op[ns].order = 1;
1130 ns++;
1131 }
1132 t.axis = t.axis.cross(link->comp[0]->loc - t.origin);
1133 R = model_reflect_and_compare(model, t.axis, t.origin);
1134 R /= Gr;
1135 if ( R < threshold ) {
1136 if ( verbose & VERB_FULL )
1137 cout << n << "\t1\t1\t" << R << endl;
1138 op[ns].axis = Vector3<double>(t.axis[0], t.axis[1], t.axis[2]);
1139 op[ns].order = 1;
1140 ns++;
1141 }
1142 }
1143
1144 // Rotations
1145 for ( n=1, link = model->link; link; link = link->next, n++ ) {
1146 t.axis = (link->comp[0]->loc + link->comp[1]->loc)/2.0 - t.origin;
1147 R = model_rotate_and_compare(model, t);
1148 R /= Gr;
1149 if ( R < threshold ) {
1150 if ( verbose & VERB_FULL )
1151 cout << n << "\t2\t2\t" << R << endl;
1152 op[ns].axis = Vector3<double>(t.axis[0], t.axis[1], t.axis[2]);
1153 op[ns].order = 2;
1154 op[ns].angle = t.angle;
1155 ns++;
1156 }
1157 }
1158
1159 if ( verbose & VERB_FULL )
1160 cout << "Vertex\tOrder\tSym\tR" << endl;
1161 for ( n=1, comp = model->comp; comp; comp = comp->next, n++ ) {
1162 for ( i=0; i<MAXLINK && comp->link[i]; i++ ) ;
1163 if ( i < 1 ) {
1164 if ( verbose & VERB_FULL )
1165 cerr << "No links for component " << comp->id << endl;
1166 } else {
1167 t.axis = comp->loc - t.origin;
1168 t.angle = M_PI*2.0/i;
1169 pf = prime_factors(i, npf);
1170 order = 0;
1171 for ( j=0; j<npf; j++ ) {
1172 t.angle = M_PI*2.0/pf[j];
1173 R = model_rotate_and_compare(model, t);
1174 R /= Gr;
1175 if ( R < threshold ) {
1176 if ( verbose & VERB_FULL )
1177 cout << n << tab << i << tab << pf[j] << tab << R << endl;
1178 if ( order < pf[j] ) order = pf[j];
1179 }
1180 }
1181 if ( npf && ( pf[0] != i ) ) {
1182 t.angle = M_PI*2.0/i;
1183 R = model_rotate_and_compare(model, t);
1184 R /= Gr;
1185 if ( R < threshold ) {
1186 if ( verbose & VERB_FULL )
1187 cout << n << tab << i << tab << i << tab << R << endl;
1188 order = i;
1189 }
1190 }
1191 delete[] pf;
1192 if ( order ) {
1193 op[ns].axis = Vector3<double>(t.axis[0], t.axis[1], t.axis[2]);
1194 op[ns].order = order;
1195 op[ns].angle = M_PI*2.0/order;
1196 ns++;
1197 }
1198 }
1199 }
1200
1201 if ( verbose & VERB_FULL )
1202 cout << "Polygon\tOrder\tSym\tR" << endl;
1203 for ( n=1, poly = model->poly; poly; poly = poly->next, n++ ) {
1204 polycen = 0;
1205 for ( i=0; poly->comp[i]; i++ )
1206 polycen += poly->comp[i]->loc;
1207 polycen /= i;
1208 t.axis = polycen - t.origin;
1209 t.axis.normalize();
1210 pf = prime_factors(i, npf);
1211 order = 0;
1212 for ( j=0; j<npf; j++ ) {
1213 t.angle = M_PI*2.0/pf[j];
1214 R = model_rotate_and_compare(model, t);
1215 R /= Gr;
1216 if ( R < threshold ) {
1217 if ( verbose & VERB_FULL )
1218 cout << n << tab << i << tab << pf[j] << tab << R << endl;
1219 if ( order < pf[j] ) order = pf[j];
1220 }
1221 }
1222 if ( pf[0] != i ) {
1223 t.angle = M_PI*2.0/i;
1224 R = model_rotate_and_compare(model, t);
1225 R /= Gr;
1226 if ( R < threshold ) {
1227 if ( verbose & VERB_FULL )
1228 cout << n << tab << i << tab << i << tab << R << endl;
1229 order = i;
1230 }
1231 }
1232 delete[] pf;
1233 if ( order ) {
1234 op[ns].axis = Vector3<double>(t.axis[0], t.axis[1], t.axis[2]);
1235 op[ns].order = order;
1236 op[ns].angle = M_PI*2.0/order;
1237 ns++;
1238 }
1239 }
1240
1241 if ( verbose & VERB_FULL )
1242 cout << endl;
1243
1244 for ( i=0; i<ns; i++ ) op[i].axis.normalize();
1245
1246 double a, maxang = M_PI/18.0;
1247 int na(0), nord[NSMAX];
1248 memset(nord, 0, NSMAX*sizeof(int));
1249
1250 // Eliminate redundant axes
1251 for ( i=1; i<ns; i++ ) {
1252 for ( j=0; j<i; j++ ) {
1253 if ( op[i].order == op[j].order ) {
1254 a = fabs(op[i].axis.angle(op[j].axis));
1255 if ( a < maxang ) op[i].order = 0;
1256 else if ( fabs(M_PI - a) < maxang ) op[i].order = 0;
1257 }
1258 }
1259 }
1260
1261 for ( i=0; i<ns; i++ ) if ( op[i].order ) nord[op[i].order]++;
1262
1263 if ( verbose & VERB_FULL ) {
1264 cout << "Order\tx\ty\tz" << endl;
1265 for ( i=0; i<ns; i++ ) if ( op[i].order )
1266 cout << op[i].order << tab << op[i].axis[0] << tab << op[i].axis[1] << tab << op[i].axis[2] << endl;
1267 cout << endl;
1268 }
1269
1270 if ( verbose & VERB_FULL ) {
1271 cout << "Order\tAxes" << endl;
1272 for ( i=1; i<NSMAX; i++ )
1273 if ( nord[i] ) cout << i << tab << nord[i] << endl;
1274 cout << endl;
1275 }
1276
1277 for ( i=1; i<NSMAX; i++ )
1278 if ( nord[i] ) na += nord[i];
1279
1280 Vector3<double> vecz(0,0,1), vecx(1,0,0);
1281
1282 if ( nord[5] > 3 && nord[3] > 5 && nord[2] > 7 ) {
1283 sym_label = "I";
1284 if ( nord[1] ) sym_label = "Ih";
1285 for ( i=0; i<ns && op[i].order != 2; i++ ) ;
1286 if ( op[i].order == 2 ) {
1287 vecz = op[i].axis;
1288 for ( j=0; j<ns; j++ ) if ( op[j].order == 5 )
1289 if ( op[i].axis.angle(op[j].axis) < M_PI/5.0 )
1290 vecx = vecz.cross(op[j].axis);
1291 }
1292 } else if ( nord[4] > 1 && nord[3] > 2 && nord[2] > 3 ) {
1293 sym_label = "O";
1294 if ( nord[1] ) sym_label = "Oh";
1295 for ( i=0; i<ns && op[i].order != 4; i++ ) ;
1296 if ( op[i].order == 4 ) {
1297 vecz = op[i].axis;
1298 for ( j=0; j<ns; j++ ) if ( op[j].order == 4 )
1299 if ( fabs(M_PI_2 - op[i].axis.angle(op[j].axis)) < maxang )
1300 vecx = op[j].axis;
1301 }
1302 } else if ( nord[3] > 2 && nord[2] > 1 ) {
1303 sym_label = "T";
1304 for ( i=0; i<ns && op[i].order != 2; i++ ) ;
1305 if ( op[i].order == 2 ) {
1306 vecz = op[i].axis;
1307 for ( j=0; j<ns; j++ ) if ( op[j].order == 2 )
1308 if ( fabs(M_PI_2 - op[i].axis.angle(op[j].axis)) < maxang )
1309 vecx = op[j].axis;
1310 }
1311 if ( nord[1] ) {
1312 for ( j=0; j<ns; j++ ) if ( op[j].order == 1 )
1313 if ( fabs(M_PI_2 - vecz.angle(op[j].axis)) < maxang )
1314 sym_label = "Td";
1315 for ( j=0; j<ns; j++ ) if ( op[j].order == 1 ) {
1316 a = fabs(vecz.angle(op[j].axis));
1317 if ( a < maxang || fabs(M_PI - a) < maxang )
1318 sym_label = "Th";
1319 }
1320 }
1321 } else if ( nord[2] > 1 ) {
1322 for ( order=0, i=2; i<NSMAX; i++ ) if ( nord[i] ) order = i;
1323 sym_label = Bstring(order, "D%d");
1324 // D2 is special because it can be oriented 3 different ways
1325 if ( order == 2 && nord[1] ) {
1326 for ( j=0; j<ns && op[j].order != 1; j++ ) ;
1327 for ( i=0; i<ns; i++ ) if ( op[i].order == 2 )
1328 if ( fabs(op[i].axis.angle(op[j].axis)) < maxang ||
1329 fabs(M_PI_2 - op[i].axis.angle(op[j].axis)) < maxang )
1330 break;
1331 } else {
1332 for ( i=0; i<ns && op[i].order != order; i++ ) ;
1333 }
1334 if ( op[i].order == order ) {
1335 vecz = op[i].axis;
1336 for ( j=0; j<ns; j++ ) if ( op[j].order == 2 )
1337 if ( fabs(M_PI_2 - op[i].axis.angle(op[j].axis)) < maxang )
1338 vecx = op[j].axis;
1339 }
1340 if ( nord[1] ) {
1341 for ( j=0; j<ns; j++ ) if ( op[j].order == 1 )
1342 if ( fabs(M_PI_2 - vecz.angle(op[j].axis)) < maxang )
1343 sym_label = Bstring(order, "D%dd");
1344 for ( j=0; j<ns; j++ ) if ( op[j].order == 1 ) {
1345 a = fabs(vecz.angle(op[j].axis));
1346 if ( a < maxang || fabs(M_PI - a) < maxang )
1347 sym_label = Bstring(order, "D%dh");
1348 }
1349 }
1350 } else {
1351 sym_label = "C1";
1352 for ( order=0, i=1; i<NSMAX; i++ ) if ( nord[i] ) order = i;
1353 if ( order ) {
1354 if ( order == 1 ) sym_label = "Cs";
1355 else sym_label = Bstring(order, "C%d");
1356 for ( i=0; i<ns && op[i].order != order; i++ ) ;
1357 if ( op[i].order ) {
1358 vecx = op[i].axis.cross(vecz);
1359 vecz = op[i].axis;
1360 vecx.normalize();
1361 // Use any reflection planes to further define orientation
1362 if ( order>1 && nord[1] ) {
1363 for ( j=0; j<ns; j++ ) if ( op[j].order == 1 ) {
1364 if ( fabs(M_PI_2 - vecz.angle(op[j].axis)) < maxang ) {
1365 vecx = op[j].axis;
1366 sym_label = Bstring(order, "C%dv");
1367 }
1368 }
1369 for ( j=0; j<ns; j++ ) if ( op[j].order == 1 ) {
1370 a = fabs(vecz.angle(op[j].axis));
1371 if ( a < maxang || fabs(M_PI - a) < maxang )
1372 sym_label = Bstring(order, "C%dh");
1373 }
1374 }
1375 }
1376 }
1377 }
1378
1379 t.axis = Vector3<double>(vecz[1], -vecz[0], 0);
1380 t.axis.normalize();
1381 t.angle = acos(vecz[2]);
1382 Matrix3 mat = Matrix3(t.axis, t.angle);
1383 // cout << mat << endl;
1384 t = Transform(mat);
1385 vecx = mat * vecx;
1386 t.axis = Vector3<double>(0, 0, 1);
1387 t.angle = atan2(-vecx[1], vecx[0]);
1388 mat = Matrix3(t.axis, t.angle) * mat;
1389 t = Transform(mat);
1390
1391 delete[] op;
1392
1393 model->symmetry = sym_label;
1394
1395 model->hand = 1;
1396 if ( model->symmetry.contains("s") || model->symmetry.contains("v") ||
1397 model->symmetry.contains("d") || model->symmetry.contains("h") )
1398 model->hand = 0;
1399 else model_poly_hand(model);
1400
1401 if ( verbose & VERB_PROCESS ) {
1402 cout << "Point group: " << sym_label << endl;
1403 cout << "Hand: " << model->hand << endl;
1404 cout << "Z-axis: " << vecz << endl;
1405 cout << "X-axis: " << vecx << endl << endl;
1406 }
1407
1408 model_rotate(model, t);
1409
1410 return sym_label;
1411 }
1412
1427 int model_poly_hand(Bmodel* model)
1428 {
1429 if ( model->symmetry.length() < 1 )
1430 model_poly_find_symmetry(model, 0.1);
1431
1432 model->hand = 0;
1433
1434 if ( model->symmetry.contains("s") || model->symmetry.contains("v") ||
1435 model->symmetry.contains("d") || model->symmetry.contains("h") )
1436 return model->hand;
1437
1438 int i, j, k, ncomp;
1439 Bcomponent* comp;
1440
1441 for ( ncomp = 0, comp = model->comp; comp; comp = comp->next ) ncomp++;
1442
1443 if ( ncomp < 2 ) return 0;
1444
1445 Matrix a = model_adjacency_matrix(model);
1446
1447 vector<double> d = a.jacobi_rotation();
1448 a.eigen_sort(d);
1449
1450 Matrix a2 = model_adjacency_matrix(model);
1451
1452 double R;
1453 Vector3<double> v1, v2;
1454 Vector3<double>* coor = new Vector3<double>[ncomp];
1455
1456 for ( i=0, comp = model->comp; comp; comp = comp->next, i++ ) {
1457 coor[i] = comp->loc;
1458 coor[i].normalize();
1459 }
1460
1461 for ( i=j=0, v1=v2=0; i<ncomp; i++, j+=ncomp ) {
1462 v1 += coor[i]*(a[i][0]*a[i][1]);
1463 for ( k=0; k<ncomp; k++ )
1464 if ( a2[i][k] )
1465 v2 += coor[i].cross(coor[k])*(a[i][0]*a[k][1]);
1466 }
1467 R = v1.scalar(v2);
1468
1469 if ( R > 0 ) model->hand = 1;
1470 else model->hand = -1;
1471
1472 delete[] coor;
1473
1474 return model->hand;
1475 }
1476
1495 int model_poly_compare(Bmodel* model, Bmodel* refmodel)
1496 {
1497 int i, j, nref, n, d, nmod(0), ntot(0);
1498 Bmodel* mp;
1499 Bmodel* mp_ref;
1500 Bmodel* mp_pick;
1501
1502 // Get all the reference eigenvalue arrays
1503 for ( nref=0, mp_ref = refmodel; mp_ref; mp_ref = mp_ref->next )
1504 if ( mp_ref->sel ) nref++;
1505
1506 if ( verbose )
1507 cout << "Comparing models with " << nref << " references" << nref << endl << endl;
1508
1509 // int* nr = new int[nref];
1510 // double** vr = new double*[nref];
1511 vector<int> nr(nref);
1512 vector<vector<double>> vr(nref);
1513
1514 for ( i = 0, mp_ref = refmodel; mp_ref; mp_ref = mp_ref->next ) if ( mp_ref->sel ) {
1515 nr[i] = count_list((char *)mp_ref->comp);
1516 vr[i] = model_poly_eigenvalues(mp_ref, 0);
1517 mp_ref->fom = 0;
1518 i++;
1519 }
1520
1521 for ( mp = model; mp; mp = mp->next ) if ( mp->sel ) {
1522 mp_pick = NULL;
1523 n = count_list((char *)mp->comp);
1524 if ( n ) {
1525 model_poly_find_symmetry(mp, 0.1);
1526 vector<double> v = model_poly_eigenvalues(mp, 0);
1527 for ( i = 0, mp_ref = refmodel; mp_ref && mp_pick == NULL; mp_ref = mp_ref->next ) if ( mp_ref->sel ) {
1528 if ( n == nr[i] ) {
1529 for ( j = 0, d = 0; j<n; j++ )
1530 if ( fabs(v[j] - vr[i][j]) > 1e-6 ) d++;
1531 if ( d < 1 ) {
1532 mp_pick = mp_ref;
1533 if ( verbose & VERB_FULL )
1534 cout << "Test: " << mp->id << tab << mp_ref->id << tab <<
1535 mp->symmetry << tab << mp_ref->symmetry << endl;
1536 }
1537 }
1538 i++;
1539 }
1540 }
1541 if ( mp_pick ) {
1542 cout << mp->id << tab << n << tab << mp->symmetry << tab << mp->hand << tab <<
1543 mp_pick->id << tab << mp_pick->symmetry << endl;
1544 mp->type_id = mp_pick->id;
1545 mp_pick->fom += 1;
1546 mp->fom = 1;
1547 nmod++;
1548 } else {
1549 cout << mp->id << tab << n << tab << mp->symmetry << "\t-\t-" << endl;
1550 mp->fom = 0;
1551 }
1552 ntot++;
1553 }
1554
1555 for ( mp = model; mp; mp = mp->next ) if ( mp->sel ) mp->sel = (int) mp->fom;
1556
1557 cout << "Models identified: " << nmod << "/" << ntot << " (" << nmod*100.0/ntot << ")" << endl << endl;
1558
1559 // for ( i = 0; i<nref; i++ ) delete[] vr[i];
1560 // delete[] nr;
1561 // delete[] vr;
1562
1563 return 0;
1564 }
1565
1580 vector<double> model_poly_eigenvalues(Bmodel* model, int show)
1581 {
1582 int i, j, k, ncomp;
1583 vector<double> d;
1584 Bcomponent* comp;
1585
1586 for ( ncomp = 0, comp = model->comp; comp; comp = comp->next ) ncomp++;
1587
1588 if ( ncomp < 1 ) return d;
1589
1590 Matrix a = model_adjacency_matrix(model);
1591
1592 d = a.jacobi_rotation();
1593 a.eigen_sort(d);
1594
1595 if ( verbose & VERB_DEBUG ) {
1596 for ( k=i=0; i<ncomp; i++ ) {
1597 cout << i << ": ";
1598 for ( j=0; j<ncomp; j++, k++ )
1599 cout << " " << a[i][j];
1600 cout << ": " << d[i] << endl;
1601 }
1602 }
1603
1604 if ( ( verbose & (VERB_PROCESS|VERB_FULL) ) && show ) {
1605 cout << "Eigenvalues:";
1606 for ( i=0; i<ncomp; i++ ) cout << tab << d[i];
1607 cout << endl;
1608 }
1609
1610 return d;
1611 }
1612
1613 // Recursively looks for all linked components with the same selection setting
1614 int comp_count_connected(Bcomponent* comp)
1615 {
1616 int i, n = 1;
1617 int s = comp->sel;
1618 comp->sel = 0;
1619
1620 for ( i=0; i<MAXLINK && comp->link[i]; i++ ) if ( comp->link[i]->sel == s )
1621 n += comp_count_connected(comp->link[i]);
1622
1623 return n;
1624 }
1625
1626 int model_number_connected_clusters(Bmodel* model)
1627 {
1628 int i, c(0);
1629 Bcomponent* comp;
1630
1631 // if ( verbose & VERB_FULL )
1632 cout << "Connected clusters:" << endl;
1633 for ( comp = model->comp; comp; comp = comp->next ) if ( comp->sel ) {
1634 i = comp_count_connected(comp);
1635 c++;
1636 // if ( verbose & VERB_FULL )
1637 cout << c << tab << i << endl;
1638 }
1639
1640 return c;
1641 }
1642
1659 vector<double> model_poly_sphere_coor(Bmodel* model)
1660 {
1661 int i, j, k, m, ncomp;
1662 double len, s[3] = {1,1,1};
1663 Bcomponent* comp;
1664 Blink* link;
1665
1666 for ( ncomp = 0, comp = model->comp; comp; comp = comp->next ) ncomp++;
1667
1668 Matrix a = model_adjacency_matrix(model);
1669
1670 vector<double> d = a.jacobi_rotation();
1671 a.eigen_sort(d);
1672
1673 int p[3] = {1,2,3};
1674
1675 if ( ncomp > 50 ) {
1676 for ( i=1, m=0; i<ncomp && m<3; i++ ) {
1677 for ( j=0, comp = model->comp; j<ncomp && comp; j++, comp = comp->next ) {
1678 if ( a[j][i] > 0 ) comp->sel = 1;
1679 else comp->sel = -1;
1680 }
1681 k = model_number_connected_clusters(model);
1682 if ( k == 2 ) p[m++] = i;
1683 if ( verbose & VERB_FULL )
1684 cout << "Eigenvector " << i << ": clusters =" << k << endl;
1685 }
1686 }
1687
1688 if ( verbose & VERB_FULL ) {
1689 cout << "Eigenvectors used:";
1690 for ( i=0; i<3; i++ ) cout << tab << p[i];
1691 cout << endl;
1692 }
1693
1694 for ( i=0; i<3; i++ ) s[i] = 1/sqrt(d[0] - d[p[i]]);
1695
1696 for ( i=0, comp = model->comp; comp; comp = comp->next, i++ )
1697 comp->loc = Vector3<double>(s[0]*a[i][p[0]], s[1]*a[i][p[1]], s[2]*a[i][p[2]]);
1698
1699 for ( i=0, len=0, link = model->link; link; link = link->next, i++ )
1700 len += link->comp[0]->loc.distance(link->comp[1]->loc);
1701
1702 len = i/len;
1703
1704 for ( comp = model->comp; comp; comp = comp->next )
1705 comp->loc *= len;
1706
1707 return d;
1708 }
1709
comp_count_connected
int comp_count_connected(Bcomponent *comp)
Definition: model_poly.cpp:1614
Matrix::jacobi_rotation
vector< double > jacobi_rotation()
Computes all eigenvalues and eigenvectors of a real symmetric matrix.
Definition: matrix.cpp:421
MAXLINK
#define MAXLINK
Definition: rwmodel.h:14
Bcomponent::id
Bstring id
Definition: rwmodel.h:53
M_PI_2
#define M_PI_2
Definition: utilities.h:62
Vector3::cross
Vector3 cross(const Vector3 &v)
Definition: Vector3.h:250
Vector3::normal
Vector3 normal(Vector3 &v1, Vector3 &v2)
Definition: Vector3.h:267
Bcomponent::type
Bcomptype * type
Definition: rwmodel.h:54
Vector3::normalize
double normalize()
Definition: Vector3.h:236
Blink
Definition: rwmodel.h:82
Bmodel::id
Bstring id
Definition: rwmodel.h:121
model_views.h
Library routines used for analysing model component views.
Bmodel::poly
Bpolygon * poly
Definition: rwmodel.h:134
Vector3::length
double length()
Definition: Vector3.h:222
model_reflect_and_compare
double model_reflect_and_compare(Bmodel *model, Vector3< double > normal, Vector3< double > origin)
Copies and reflects the model and compares it with the original.
Definition: model_transform.cpp:192
Matrix::fill
void fill(double v)
Definition: Matrix.h:186
model_poly_angles
int model_poly_angles(Bmodel *model)
Calculates all the polygon angles.
Definition: model_poly.cpp:646
symmetry.h
Header file for general symmetry functions.
model_poly_eigenvalues
vector< double > model_poly_eigenvalues(Bmodel *model, int show)
Generates the eigenvalues of the adjacency matrix for a model.
Definition: model_poly.cpp:1580
utilities.h
Header file for general utilities.
model_util.h
Library routines used for model processing.
VERB_DEBUG
#define VERB_DEBUG
Definition: utilities.h:112
component_hand
int component_hand(Bstring &s)
Determines the hand of a component.
Definition: model_views.cpp:466
Transform::angle
double angle
Definition: Transform.h:29
Bcomponent::flag
int flag[MAXLINK]
Definition: rwmodel.h:57
Bpolygon::comp
Bcomponent * comp[MAXLINK]
Definition: rwmodel.h:105
model_number_connected_clusters
int model_number_connected_clusters(Bmodel *model)
Definition: model_poly.cpp:1626
Bpolygon
Definition: rwmodel.h:102
add_item
char * add_item(char **list, unsigned long size)
Adds an item to a linked list.
Definition: linked_list.cpp:26
Matrix3
Definition: Matrix3.h:17
Bstring::length
long length() const
Definition: Bstring.cpp:263
count_list
long count_list(char *list)
Counts the number of items in a linked list.
Definition: linked_list.cpp:235
component_add
Bcomponent * component_add(Bcomponent **comp, Bstring &id)
Adds a component to a linked list.
Definition: rwmodel.cpp:267
link_add
Blink * link_add(Blink **link, Bcomponent *comp1, Bcomponent *comp2, double length, double radius)
Adds a component link to a linked list.
Definition: rwmodel.cpp:315
Bmodel::sel
int sel
Definition: rwmodel.h:129
prime_factors
long * prime_factors(long number, long &n)
Finds all the prime factor for the input number.
Definition: math_util.cpp:152
VERB_PROCESS
#define VERB_PROCESS
Definition: utilities.h:107
model_poly_generate
int model_poly_generate(Bmodel *model)
Generates polygons based on a vertex network.
Definition: model_poly.cpp:145
model_poly_compare
int model_poly_compare(Bmodel *model, Bmodel *refmodel)
Compares a model with reference models based on the eigenvalues of the adjacency matrix.
Definition: model_poly.cpp:1495
model_links.h
Library routines used for model link processing.
Blink::comp
Bcomponent * comp[2]
Definition: rwmodel.h:84
Vector3::distance
double distance(const Vector3 &v)
Definition: Vector3.h:227
Bsymop::angle
double angle
Definition: symmetry.h:27
Bmodel::hand
int hand
Definition: rwmodel.h:123
Bpolygon::number
int number
Definition: rwmodel.h:104
model_poly_energy
double model_poly_energy(Bmodel *model, double angle_ref)
Calculates the different energy terms for all models.
Definition: model_poly.cpp:915
poly_get_connectivity
int poly_get_connectivity(Bcomponent *comp, int ilink, int nlink, Bpolygon *poly)
Definition: model_poly.cpp:85
Bstring::contains
bool contains(const Bstring &s)
Definition: Bstring.cpp:584
Matrix::LU_decomposition
double LU_decomposition()
Matrix inversion by LU decomposition.
Definition: matrix.cpp:78
Transform
Definition: Transform.h:24
M_PI
#define M_PI
Definition: utilities.h:59
linked_list.h
Header file for generalized linked list functions.
model_poly_sphere_coor
vector< double > model_poly_sphere_coor(Bmodel *model)
Generates coordinates for components based on the eigenvectors of the adjacency matrix.
Definition: model_poly.cpp:1659
Blink::length
float length
Definition: rwmodel.h:86
Blink::next
Blink * next
Definition: rwmodel.h:83
comp_type_list_kill
int comp_type_list_kill(Bcomptype *type)
Deallocates memory for a list of component types.
Definition: rwmodel.cpp:926
Bcomponent::fom
float fom
Definition: rwmodel.h:65
Vector3::scalar
double scalar(const Vector3 &v) const
Definition: Vector3.h:247
Bmodel::type
Bcomptype * type
Definition: rwmodel.h:131
model_gyration_radius
double model_gyration_radius(Bmodel *model)
Calculates the radius of gyration for a model.
Definition: model_util.cpp:503
Bmodel::type_id
Bstring type_id
Definition: rwmodel.h:122
Vector3::angle
double angle(Vector3< T2 > &v)
Definition: Vector3.h:257
length
double length(vector< T > v)
Definition: Vector3.h:528
model_poly_dual
Bmodel * model_poly_dual(Bmodel *model, int order)
Calculates the dual of a polyhedral network.
Definition: model_poly.cpp:454
component_6digit_type
Bstring component_6digit_type(Bcomponent *comp)
Definition: model_poly.cpp:351
Bpolygon::next
Bpolygon * next
Definition: rwmodel.h:103
Bsymop::order
int order
Definition: symmetry.h:26
Bmodel::symmetry
Bstring symmetry
Definition: rwmodel.h:124
model_poly_faces
int model_poly_faces(Bmodel *model)
Generates links between the vertices to define the polyhedron faces.
Definition: model_poly.cpp:39
Bstring::canonical
Bstring canonical(int n)
Definition: Bstring.cpp:527
model_poly.h
Functions to manipulate polyhedral coordinate files.
Vector3::length2
double length2()
Definition: Vector3.h:221
model_rotate
long model_rotate(Bmodel *model, Matrix3 mat)
Rotates the model.
Definition: model_transform.cpp:238
Bmodel::next
Bmodel * next
Definition: rwmodel.h:120
Bcomponent::sel
int sel
Definition: rwmodel.h:66
model_add_type_by_id
Bcomptype * model_add_type_by_id(Bmodel *model, Bstring &id)
Add a type to a model if the identifier does not exist already.
Definition: rwmodel.cpp:411
Bcomponent::radius
float radius
Definition: rwmodel.h:62
model
Bmodel * model
Definition: bshow.cpp:32
model_poly_pentagon_adjacency
int model_poly_pentagon_adjacency(Bmodel *model)
Calculates the number of edges shared by pentagons.
Definition: model_poly.cpp:1041
model_poly_regularity
double model_poly_regularity(Bmodel *model)
Analyzes a model for polygon regularity.
Definition: model_poly.cpp:750
Transform::origin
Vector3< double > origin
Definition: Transform.h:27
Matrix::eigen_sort
void eigen_sort(vector< double > &val)
Computes all eigenvalues and eigenvectors of a real symmetric matrix.
Definition: matrix.cpp:677
Bmodel::fom
float fom
Definition: rwmodel.h:128
random_numbers.h
Header file for functions for creating random images.
Matrix
Definition: Matrix.h:21
Bstring
Definition: Bstring.h:29
Bcomponent::link
Bcomponent * link[MAXLINK]
Definition: rwmodel.h:55
Bmodel::link
Blink * link
Definition: rwmodel.h:133
poly_list_kill
int poly_list_kill(Bpolygon *poly)
Deallocates memory for a list of polygons.
Definition: rwmodel.cpp:1070
model_principal_axes
Vector3< double > model_principal_axes(Bmodel *model, Vector3< double > *eigenvec)
Calculates the principal axes of a model.
Definition: model_util.cpp:534
matrix_linear.h
Header file for matrix functions.
Bcomponent::vec
Vector3< float > vec
Definition: rwmodel.h:60
Bcomponent::next
Bcomponent * next
Definition: rwmodel.h:52
Bpolygon::normal
Vector3< float > normal
Definition: rwmodel.h:106
model_link_list_generate
long model_link_list_generate(Bmodel *model, double maxlength)
Generates a link list for a model based on vertex separation.
Definition: model_links.cpp:70
model_rotate_and_compare
double model_rotate_and_compare(Bmodel *model, Transform t)
Copies and rotates the model and compares it with the original.
Definition: model_transform.cpp:369
Bsymop
Definition: symmetry.h:24
Vector3< double >
model_adjacency_matrix
Matrix model_adjacency_matrix(Bmodel *model)
Constructs the adjacency matrix for a model.
Definition: model_compare.cpp:152
Vector3.h
Class for 3-value vectors.
show
int show(0)
NSMAX
#define NSMAX
Definition: model_poly.cpp:1080
model_poly_planarity
double model_poly_planarity(Bmodel *model)
Analyzes a model for polygon planarity.
Definition: model_poly.cpp:835
verbose
int verbose
Bmodel
Definition: rwmodel.h:119
model_poly_find_symmetry
Bstring model_poly_find_symmetry(Bmodel *model, double threshold)
Finds the symmetry axes associated with polyhedral elements.
Definition: model_poly.cpp:1095
Transform::axis
Vector3< double > axis
Definition: Transform.h:28
model_poly_links
int model_poly_links(Bmodel *model)
Calculates all the model links.
Definition: model_poly.cpp:597
model_poly_analyze
int model_poly_analyze(Bmodel *model)
Analyzes a model for polygon regularity and planarity.
Definition: model_poly.cpp:538
model_center_of_mass
Vector3< double > model_center_of_mass(Bmodel *model)
Definition: model_util.cpp:475
model_poly_hand
int model_poly_hand(Bmodel *model)
Calculates the polyhedron hand.
Definition: model_poly.cpp:1427
model_extended_vertex_types
int model_extended_vertex_types(Bmodel *model)
Determines the vertex type based on adjacent and opposed polygons.
Definition: model_poly.cpp:396
Bmodel::comp
Bcomponent * comp
Definition: rwmodel.h:132
VERB_FULL
#define VERB_FULL
Definition: utilities.h:109
VERB_LABEL
#define VERB_LABEL
Definition: utilities.h:106
Bsymop::axis
Vector3< double > axis
Definition: symmetry.h:25
Bcomponent::loc
Vector3< float > loc
Definition: rwmodel.h:58
Blink::fom
float fom
Definition: rwmodel.h:89
model_transform.h
Library routines used for model transformation.
model_compare.h
Functions to compare models and components.
TWOPI
#define TWOPI
Definition: utilities.h:68
model_vertex_types
int model_vertex_types(Bmodel *model)
Determines the vertex type based on adjacent polygons.
Definition: model_poly.cpp:313
tab
ostream & tab(ostream &out)
Definition: utilities.cpp:21
math_util.h
Header file for general utilities.
Bpolygon::sel
int sel
Definition: rwmodel.h:109
Bpolygon::closed
int closed
Definition: rwmodel.h:107
Bcomponent
Definition: rwmodel.h:51