| Bsoft 2.0.5 Bernard's software package

model_create.cpp
Go to the documentation of this file.
1
9 #include "rwmodel.h"
10 #include "model_create.h"
11 #include "model_transform.h"
12 #include "model_symmetry.h"
13 #include "model_util.h"
14 #include "random_numbers.h"
15 #include "utilities.h"
16
17 // Declaration of global variables
18 extern int verbose; // Level of output to the screen
19
32 Bcomponent* model_add_component(Bmodel* model, Bstring &id, Bstring &type, Vector3<double> loc)
33 {
34 if ( !model ) return NULL;
35
36 Bmodel* mp = model;
37
38 if ( id.length() ) {
39 for ( mp = model; mp; mp = mp->next )
40 if ( mp->id == id ) break;
41 if ( !mp ) mp = model;
42 }
43
44 if ( type.length() < 1 ) {
45 if ( model->type ) type = model->type->id;
46 else type = "VER";
47 }
48
49 Bcomptype* ct = model_add_type_by_id(mp, type);
50
51 long n;
52 Bcomponent* comp = NULL;
53
54 for ( n=0, comp = mp->comp; comp; comp = comp->next ) n++;
55
56 Bstring cid = Bstring(++n, "%d");
57
58 comp = component_add(&mp->comp, cid);
59 comp->loc = loc;
60 comp->type = ct;
61
62 return comp;
63 }
64
82 Bmodel* model_platonic(Bsymmetry* sym, double radius)
83 {
84 Bstring id("1");
85 Bmodel* model = model_init(id);
86 model->symmetry = sym->label;
87
88 Bstring comptype = "VER";
89 Bcomptype* ct = model_add_type_by_id(model, comptype);
90 Bcomponent* comp = component_add(&model->comp, id);
91 comp->type = ct;
92 comp->radius = radius/10;
93
94 // double search_radius;
95
96 if ( model->symmetry == "T-3" ) {
97 model->id = "Tetrahedron";
98 // search_radius = 2*radius;
99 comp->loc = Vector3<double>(radius/sqrt(3), radius/sqrt(3), radius/sqrt(3));
100 } else if ( model->symmetry == "O-2" ) {
101 model->id = "Truncated octahedron";
102 // search_radius = 1.2*radius;
103 comp->loc = Vector3<double>(0, -radius/sqrt(2), radius/sqrt(2));
104 } else if ( model->symmetry == "O-3" ) {
105 model->id = "Cube";
106 // search_radius = 1.5*radius;
107 comp->loc = Vector3<double>(radius/sqrt(3), radius/sqrt(3), radius/sqrt(3));
108 } else if ( model->symmetry == "O-4" ) {
109 model->id = "Octahedron";
110 // search_radius = 1.5*radius;
111 comp->loc = Vector3<double>(0, 0, radius);
112 } else if ( model->symmetry == "I-2" ) {
113 model->id = "Truncated icosahedron";
114 // search_radius = 0.8*radius;
115 comp->loc = Vector3<double>(0, 0, radius);
116 } else if ( model->symmetry == "I-3" ) {
117 model->id = "Dodecahedron";
118 // search_radius = radius;
119 comp->loc = Vector3<double>(radius/sqrt(3), radius/sqrt(3), radius/sqrt(3));
120 } else if ( model->symmetry == "I-5" ) {
121 model->id = "Icosahedron";
122 // search_radius = 1.2*radius;
123 comp->loc = Vector3<double>(0, radius/sqrt(2+GOLDEN), radius/sqrt(3-GOLDEN));
124 } else {
125 cerr << "Error: Symmetry " << sym->label << " not supported!" << endl;
126 model_kill(model);
127 return NULL;
128 }
129
130 if ( verbose ) {
131 cout << "Generating a " << model->id << ":" << endl;
132 cout << "Symmetry: " << model->symmetry << endl;
133 cout << "Radius: " << radius << endl << endl;
134 }
135
136 comp->view = View(comp->loc[0], comp->loc[1], comp->loc[2], 0);
137
138 Vector3<double> origin;
139 View ref_view;
140 model_apply_point_group(model, model->symmetry, origin, ref_view, 1);
141
142 return model;
143 }
144
153 Bmodel* model_helix(double radius, double helix_rise, double helix_angle, long ncomp)
154 {
155 long i;
156 double start = -(ncomp/2.0 - 0.5)*helix_rise;
157 // double search_radius = 1.2*sqrt(helix_rise*helix_rise + 2*radius*radius*(1 - cos(helix_angle)));
158 Bstring id("Helix");
159 Bmodel* model = model_init(id);
160 model->symmetry = Bstring(helix_rise, "H%.3g") + Bstring(helix_angle*180.0/M_PI, ",%.3g");
161 Bstring comptype = "VER";
162 Bcomptype* ct = model_add_type_by_id(model, comptype);
163 id = "1";
164 Bcomponent* comp = component_add(&model->comp, id);
165 comp->type = ct;
166 comp->loc[0] = radius;
167 comp->loc[2] = start;
168 comp->radius = radius/10;
169
170 if ( verbose ) {
171 cout << "Generating a " << model->id << ":" << endl;
172 cout << "Radius: " << radius << endl;
173 cout << "Helical rise and rotation: " << helix_rise << " " << helix_angle*180.0/M_PI << endl;
174 cout << "Number of components: " << ncomp << endl << endl;
175 }
176
177 for ( i=1; i<ncomp; i++ ) {
178 id = Bstring(i+1, "%d");
179 comp = component_add(&comp, id);
180 comp->type = ct;
181 comp->loc[0] = radius*cos(i*helix_angle);
182 comp->loc[1] = radius*sin(i*helix_angle);
183 comp->loc[2] = start + i*helix_rise;
184 comp->radius = radius/10;
185 }
186
187 return model;
188 }
189
201 Bmodel* model_random(long ncomp, double comp_radius, double max_radius)
202 {
203 Bstring id("Random");
204 double R = ncomp * pow(comp_radius/max_radius, 3);
205
206 if ( verbose ) {
207 cout << "Generating a random model: " << id << endl;
208 cout << "Number of components: " << ncomp << endl;
209 cout << "Component radius: " << comp_radius << endl;
210 cout << "Maximum model radius: " << max_radius << endl;
211 cout << "Packing density: " << R << endl << endl;
212 }
213
214 if ( R > 0.35 ) {
215 cerr << "Error: The packing density is too high!" << endl << endl;
216 return NULL;
217 }
218
219 random_seed();
220
221 long i;
222 double inner_radius(max_radius - comp_radius);
223 double d;
224 Bmodel* model = model_init(id);
225 Bstring comptype = "VER";
226 Bcomponent* comp = NULL;
227 Bcomponent* comp2 = NULL;
228 Bcomptype* ct = model_add_type_by_id(model, comptype);
229
230 for ( i=1; i<=ncomp; i++ ) {
231 id = Bstring(i, "%d");
232 comp = component_add(&comp, id);
233 if ( !model->comp ) model->comp = comp;
234 comp->type = ct;
235 for ( d = 0; d < 2*comp_radius; ) {
236 comp->loc = vector3_random(inner_radius);
237 for ( d = 4*comp_radius, comp2 = model->comp;
238 comp2 != comp && d >= 2*comp_radius; comp2 = comp2->next )
239 d = comp->loc.distance(comp2->loc);
240 }
241 comp->view = random_view();
242 comp->radius = comp_radius;
243 }
244
245 return model;
246 }
247
260 Bmodel* model_random(long ncomp, double comp_radius, Vector3<double> min, Vector3<double> max)
261 {
262 Bstring id("Random");
263 Vector3<double> cmin(min + comp_radius);
264 Vector3<double> cmax(max - comp_radius);
265 double R(ncomp * (4.0*M_PI/3.0)*comp_radius*comp_radius*comp_radius/(max - min).volume());
266
267 if ( verbose ) {
268 cout << "Generating a random model: " << id << endl;
269 cout << "Number of components: " << ncomp << endl;
270 cout << "Component radius: " << comp_radius << endl;
271 cout << "Minimum coordinates: " << cmin << endl;
272 cout << "Maximum coordinates: " << cmax << endl;
273 cout << "Packing density: " << R << endl << endl;
274 }
275
276 if ( R > 0.35 ) {
277 cerr << "Error: The packing density is too high!" << endl << endl;
278 return NULL;
279 }
280
281 random_seed();
282
283 long i;
284 double d;
285 Bmodel* model = model_init(id);
286 Bstring comptype = "VER";
287 Bcomponent* comp = NULL;
288 Bcomponent* comp2 = NULL;
289 Bcomptype* ct = model_add_type_by_id(model, comptype);
290
291 for ( i=1; i<=ncomp; i++ ) {
292 id = Bstring(i, "%d");
293 comp = component_add(&comp, id);
294 if ( !model->comp ) model->comp = comp;
295 comp->type = ct;
296 for ( d = 0; d < 2*comp_radius; ) {
297 comp->loc = vector3_random(cmin, cmax);
298 for ( d = 4*comp_radius, comp2 = model->comp;
299 comp2 != comp && d >= 2*comp_radius; comp2 = comp2->next )
300 d = comp->loc.distance(comp2->loc);
301 }
302 comp->view = random_view();
303 comp->radius = comp_radius;
304 }
305
306 return model;
307 }
308
318 Bmodel* model_random_gaussian(long ncomp, double std)
319 {
320 Bstring id("RandomGaussian");
321
322 if ( verbose ) {
323 cout << "Generating a random gaussian model: " << id << endl;
324 cout << "Number of components: " << ncomp << endl;
325 }
326
327 random_seed();
328
329 long i;
330 Bmodel* model = model_init(id);
331 Bstring comptype = "VER";
332 Bcomponent* comp = NULL;
333 Bcomptype* ct = model_add_type_by_id(model, comptype);
334
335 for ( i=1; i<=ncomp; i++ ) {
336 id = Bstring(i, "%d");
337 comp = component_add(&comp, id);
338 if ( !model->comp ) model->comp = comp;
339 comp->type = ct;
340 comp->loc = vector3_random_gaussian(0, std);
341 comp->view = random_view();
342 }
343
344 double R = model_gyration_radius(model);
345
346 if ( verbose )
347 cout << "Radius of gyration: " << R << " A" << endl << endl;
348
349 return model;
350 }
351
361 Bmodel* model_random_shell(long ncomp, double radius)
362 {
363 Bstring id("RandomShell");
364
365 if ( verbose ) {
366 cout << "Generating a random shell model: " << id << endl;
367 cout << "Number of components: " << ncomp << endl;
368 cout << "Radius: " << radius << endl;
369 }
370
371 random_seed();
372
373 long i;
374 Bmodel* model = model_init(id);
375 Bstring comptype = "VER";
376 Bcomponent* comp = NULL;
377 Bcomptype* ct = model_add_type_by_id(model, comptype);
378
379 for ( i=1; i<=ncomp; i++ ) {
380 id = Bstring(i, "%d");
381 comp = component_add(&comp, id);
382 if ( !model->comp ) model->comp = comp;
383 comp->type = ct;
384 comp->loc = vector3_random_unit_sphere();
385 comp->view = View(comp->loc[0], comp->loc[1], comp->loc[2], 0);
386 comp->loc *= radius;
387 }
388
389 double R = model_gyration_radius(model);
390
391 if ( verbose )
392 cout << "Radius of gyration: " << R << " A" << endl << endl;
393
394 return model;
395 }
396
415 Bmodel* model_random_shell(long ncomp, double radius, double separation)
416 {
417 Bstring id("RandomShell");
418
419 if ( verbose ) {
420 cout << "Generating a random shell model: " << id << endl;
421 cout << "Number of components: " << ncomp << endl;
422 cout << "Radius: " << radius << endl;
423 cout << "Separation: " << separation << endl;
424 }
425
426 random_seed();
427
428 long i;
429 double d, pd(ncomp*separation*separation/(radius*radius));
430
431 if ( pd > 8 ) ncomp = 8*radius*radius/(separation*separation);
432
433 Bmodel* model = model_init(id);
434 Bstring comptype = "VER";
435 Bcomponent* comp = NULL;
436 Bcomponent* comp2 = NULL;
437 Bcomptype* ct = model_add_type_by_id(model, comptype);
438
439 for ( i=1; i<=ncomp; i++ ) {
440 id = Bstring(i, "%d");
441 comp = component_add(&comp, id);
442 if ( !model->comp ) model->comp = comp;
443 comp->type = ct;
444 comp->radius = separation/10;
445 for ( d = 0; d < separation; ) {
446 comp->loc = vector3_random_unit_sphere();
447 comp->loc *= radius;
448 for ( d = 2*separation, comp2 = model->comp;
449 comp2 != comp && d >= separation; comp2 = comp2->next )
450 d = comp->loc.distance(comp2->loc);
451 }
452 comp->view = View(comp->loc[0], comp->loc[1], comp->loc[2], 0);
453 }
454
455 double R = model_gyration_radius(model);
456 model->fom = R;
457
458 return model;
459 }
460
472 Bmodel* model_create_shell(long number, double radius, double distance)
473 {
474 // flag = 0: the number is set by generation
475 // flag = 1: the radius must be derived
476 // flag = 2: the distance must be derived
477 int flag(0);
478 if ( radius <= 0 ) flag = 1;
479 else if ( distance <= 0 ) {
480 if ( number <= 0 ) distance = radius/10;
481 else flag = 2;
482 }
483
484 Bmodel* model = model_init("Sphere");
485
486 Bcomponent* comp = NULL;
487 Bstring id;
488 Bstring comptype("VER");
489 Bcomptype* ct = model_add_type_by_id(model, comptype);
490
491 long i(number), n, t;
492 double x, y, z;
493 double theta_step, theta, phi, phi_step, rad_sin_theta;
494 double lam(0.1), rn;
495
496 random_seed();
497
498 double irm = lam/get_rand_max();
499
500 if ( flag ) {
501 if ( flag == 1 ) radius = distance*sqrt(number/12.5L);
502 else distance = radius/sqrt(number/12.5L);
503 for ( t=i=0; t<1000 && i != number; t++ ) {
504 theta_step = sqrt(3.0/4.0)*distance/radius;
505 for ( i=0, theta = 0; theta <= M_PI; theta += theta_step ) {
506 rad_sin_theta = radius*sin(theta);
507 n = (long) (TWOPI*rad_sin_theta/distance);
508 phi_step = 1.5*TWOPI;
509 if ( theta > 0 && theta < TWOPI )
510 phi_step = TWOPI*1.0L/n;
511 for ( phi = 0; phi < TWOPI - phi_step/2; phi += phi_step, i++ ) ;
512 }
513 if ( i != number ) {
514 rn = irm*random();
515 if ( flag == 1 ) radius *= 1 + (number - i)*rn/number;
516 else distance *= 1 + (i - number)*rn/number;
517 }
518 }
519 }
520
521 theta_step = sqrt(3.0/4.0)*distance/radius;
522
523 double cr(radius/sqrt(number));
524
525 if ( verbose & VERB_DEBUG )
526 cout << "DEBUG model_create_shell: number=" << number << " distance=" <<
527 distance << " radius=" << radius << " theta_step=" << theta_step << endl;
528
529 for ( i=0, theta = 0; theta <= M_PI; theta += theta_step ) {
530 z = radius*cos(theta);
531 rad_sin_theta = radius*sin(theta);
532 n = (long) (TWOPI*rad_sin_theta/distance);
533 phi_step = 1.5*TWOPI;
534 if ( theta > 0 && theta < TWOPI )
535 phi_step = TWOPI*1.0L/n;
536 for ( phi = 0; phi < TWOPI - phi_step/2; phi += phi_step ) {
537 x = cos(phi)*rad_sin_theta;
538 y = sin(phi)*rad_sin_theta;
539 id = Bstring(++i, "%d");
540 comp = component_add(&comp, id);
541 if ( !model->comp ) model->comp = comp;
542 comp->type = ct;
543 comp->loc = Vector3<double>(x, y, z);
544 comp->view = View(x, y, z, 0);
545 comp->view.normalize();
546 comp->radius = cr;
547 }
548 }
549
550 if ( verbose ) {
551 cout << "Generating a sphere:" << endl;
552 cout << "Number of components: " << i << endl;
553 cout << "Separation distance: " << distance << endl;
554 cout << "Radius: " << radius << endl << endl;
555 }
556
557 return model;
558 }
559
569 Bmodel* model_create_fibonacci_sphere(long number, double radius)
570 {
571 if ( radius <= 0 ) radius = 1;
572 if ( number <= 0 ) number = 20;
573
574 Bmodel* model = model_init("FibonacciSphere");
575
576 Bcomponent* comp = NULL;
577 Bstring id;
578 Bstring comptype("VER");
579 Bcomptype* ct = model_add_type_by_id(model, comptype);
580
581 long i;
582 double x, y, z, st, phi;
583 double ga(4*M_PI/(sqrt(5.0)+1.0));
584 double cr(radius/sqrt(number));
585 RGBA<float> color(0,0,1,1);
586
587
588 if ( verbose & VERB_DEBUG )
589 cout << "DEBUG model_create_fibonacci_sphere: number=" << number <<
590 " radius=" << radius << endl;
591
592 for ( i=0; i<number; ) {
593 z = 1 - (2.0*i + 1.0)/number;
594 st = sin(acos(z));
595 phi = ga*i;
596 x = cos(phi)*st;
597 y = sin(phi)*st;
598 id = Bstring(++i, "%d");
599 comp = component_add(&comp, id);
600 if ( !model->comp ) model->comp = comp;
601 comp->type = ct;
602 comp->loc = Vector3<double>(x, y, z);
603 comp->loc *= radius;
604 comp->view = View(x, y, z, 0);
605 comp->view.normalize();
606 comp->radius = cr;
607 comp->color = color;
608 }
609
610 if ( verbose ) {
611 cout << "Generating a Fibonacci sphere:" << endl;
612 cout << "Number of components: " << i << endl;
613 cout << "Radius: " << radius << endl << endl;
614 }
615
616 return model;
617 }
618
619 long model_subdivide(Bmodel* model, long division)
620 {
621 long i, j, n, ncomp;
622 Bcomponent* comp, *comp2, *comp3;
623
624 for ( ncomp=0, comp = model->comp; comp; comp = comp->next, ncomp++ ) ;
625
626 if ( division < 1 ) return ncomp;
627
628 double search_radius = 1/pow(2.0,division - 1.0);
629 Bstring id, comptype("VER");
630 Bcomptype* ct = model_add_type_by_id(model, comptype);
631
632 if ( model->symmetry == "I-3" ) search_radius *= 1.44;
633 else if ( model->symmetry == "I-5" ) search_radius *= 1.104;
634
635 for ( i=0, n=ncomp, comp = model->comp; comp && i<ncomp; comp = comp->next, i++ ) {
636 for ( j=i, comp2 = comp; comp2 && j<ncomp; comp2=comp2->next, j++ ) {
637 if ( comp != comp2 ) {
638 if ( comp->loc.distance(comp2->loc) < search_radius ) {
639 id = Bstring(++n, "%ld");
640 comp3 = component_add(&comp2, id);
641 comp3->type = ct;
642 comp3->loc = (comp->loc + comp2->loc)/2;
643 comp3->view = View(comp3->loc[0], comp3->loc[1], comp3->loc[2], 0);
644 }
645 }
646 }
647 }
648
649 return n;
650 }
651
652 long model_spherize(Bmodel* model, double sphere_fraction)
653 {
654 if ( fabs(sphere_fraction) < 1e-3 ) return 0;
655
656 double v;
657 Bcomponent* comp;
658
659 for ( comp = model->comp; comp; comp = comp->next ) {
660 v = 1/(1-sphere_fraction*(1-comp->loc.length()));
661 comp->loc *= v;
662 }
663
664 return 0;
665 }
666
675 Bmodel* model_create_dodecahedron(double radius, long divisions, double sphere_fraction)
676 {
677 Bsymmetry* sym = init_point_group_symmetry("I-3");
678 Bsymmetry* sym2 = init_point_group_symmetry("I-5");
679
680 Bmodel* model = model_platonic(sym, 1);
681 if ( divisions > 1 ) model->next = model_platonic(sym2, 0.8);
682
683 if ( divisions < 1 ) divisions = 1;
684 if ( divisions > 4 ) {
685 cout << "Warning: Divisions bigger than 4 cannot be tesselated!" << endl;
686 cout << " Divisions reset to 4" << endl << endl;
687 divisions = 4;
688 }
689
690 if ( verbose ) {
691 cout << "Generating a dodecahedral sphere:" << endl;
692 cout << "Radius: " << radius << endl;
693 cout << "Divisions: " << divisions << endl << endl;
694 }
695
696 long i, n;
697 Vector3<double> origin;
698 Vector3<double> scale(radius, radius, radius);
699
700
701 for ( i=0; i<divisions; i++ ) {
702 if ( i == 1 )
703 n = model_merge(model);
704 else
705 n = model_subdivide(model, i);
706 if ( verbose )
707 cout << "Division " << i+1 << ": " << n << " components" << endl;
708 }
709 if ( verbose )
710 cout << endl;
711
712 model_spherize(model, sphere_fraction);
713
714 model_scale(model, scale, origin);
715
716 model_set_component_radius(model, radius/(4*divisions));
717
718 kill_symmetry(sym);
719 kill_symmetry(sym2);
720
721 return model;
722 }
723
732 Bmodel* model_create_icosahedron(double radius, long divisions, double sphere_fraction)
733 {
734 Bsymmetry* sym = init_point_group_symmetry("I-5");
735 Bmodel* model = model_platonic(sym, 1);
736
737 if ( divisions < 1 ) divisions = 1;
738 if ( divisions > 4 ) {
739 cout << "Warning: Divisions bigger than 4 cannot be tesselated!" << endl;
740 cout << " Divisions reset to 4" << endl << endl;
741 divisions = 4;
742 }
743
744 if ( verbose ) {
745 cout << "Generating an icosahedral sphere:" << endl;
746 cout << "Radius: " << radius << endl;
747 cout << "Divisions: " << divisions << endl << endl;
748 }
749
750 long i, n;
751 Vector3<double> origin;
752 Vector3<double> scale(radius, radius, radius);
753
754 for ( i=0; i<divisions; i++ ) {
755 n = model_subdivide(model, i);
756 if ( verbose )
757 cout << "Division " << i+1 << ": " << n << " components" << endl;
758 }
759 if ( verbose )
760 cout << endl;
761
762 model_spherize(model, sphere_fraction);
763
764 model_scale(model, scale, origin);
765
766 model_set_component_radius(model, radius/(4*divisions));
767
768 kill_symmetry(sym);
769
770 return model;
771 }
772
788 double ellipsoid_slice_distance_error(Vector3<double> axes, double z1, double z2, double distance)
789 {
790 double temp1 = z1/axes[2], temp2 = z2/axes[2];
791 double a1 = sqrt(1 - temp1*temp1);
792 double a2 = sqrt(1 - temp2*temp2);
793
794 return Vector3<double>(a1*axes[0],0,z1).distance(Vector3<double>(a2 * axes[0],0,z2))
795 + Vector3<double>(0,a1*axes[1],z1).distance(Vector3<double>(0,a2*axes[1],z2)) - 2.0 * distance;
796 }
797
806 double ellipsoid_next_z(Vector3<double> axes, double z1, double distance)
807 {
808 double z2(z1 - distance);
809 if ( z2 < -axes[2] ) z2 = -axes[2];
810
811 double epsilon(0.0001); // any smaller and it never exits while loop below!! //z precision
812 double slice_error(0.1 * distance); //margin of error for the distance between points between slices
813
814 if ( ellipsoid_slice_distance_error(axes, z1, z2, distance) < epsilon * distance )
815 return z2; // z2 does not bracket the root with z1, it is the root.
816
817 double z3 = z1;
818 double midpoint(0);
819
820 while (fabs(z3 - z2) > 2 * epsilon
821 || fabs(ellipsoid_slice_distance_error(axes,z1,midpoint,distance)) > slice_error) {
822 midpoint = (z3 + z2) / 2;
823 if ( ellipsoid_slice_distance_error(axes, z1, z2, distance)
824 * ellipsoid_slice_distance_error(axes, z1, midpoint, distance) < 0 )
825 z3 = midpoint;
826 else if ( ellipsoid_slice_distance_error(axes, z1, z3, distance)
827 * ellipsoid_slice_distance_error(axes, z1, midpoint, distance) < 0 )
828 z2 = midpoint;
829 else break;
830 }
831
832 return midpoint;
833 }
834
835
846 double ellipse_next_x(Vector3<double> axes, double x1, double distance)
847 {
848 double distance2 = distance*distance;
849 double temp = axes[1] * x1 / axes[0];
850 double y1 = sqrt(axes[1]*axes[1] - temp*temp);
851 // if (isnan(y1)) y1 = 0;
852 if ( !isfinite(y1) ) y1 = 0;
853 Vector3<double> old(x1,y1,0), mid;
854
855 if ( Vector3<double>(-axes[0],0,0).distance2(old) < distance2 ) return x1;
856
857 double right = x1;
858 double left = fmax(-axes[0], x1 - distance);
859 temp = axes[1] * left / axes[0];
860 double f_left = sqrt(axes[1]*axes[1] - temp*temp);
861 double d2;
862
863 // exit conditions (precision in x and distance)
864 double epsilon(0.0001);
865 double maxerror(0.1 * distance);
866
867 if ( fabs(Vector3<double>(left,f_left,0).distance(old) - distance) < epsilon * distance )
868 return left; //if left doesn't bracket the root, it is the root
869
870 while ( fabs((right - left) / right) > 2 * epsilon
871 || fabs(mid.distance(old) - distance) > maxerror ) {
872 mid[0] = (right + left) / 2.0;
873 temp = axes[1] * mid[0] / axes[0];
874 mid[1] = sqrt(axes[1]*axes[1] - temp*temp);
875 d2 = mid.distance2(old);
876 if ( d2 > distance2 ) {
877 left = mid[0];
878 } else if ( d2 < distance2 ) {
879 right = mid[0];
880 } else break;
881 }
882
883 return mid[0];
884 }
885
897 Bmodel* model_create_circle(double radius, double z, double distance)
898 {
899 if ( radius <= 0 ) {
900 cerr << "Error: The circle radius must given!" << endl;
901 return NULL;
902 }
903
904 if ( distance <= 0 ) distance = radius/10;
905
906 if ( verbose & VERB_FULL )
907 cout << "Creating a circle of radius " << radius << " at z=" << z <<
908 " with separation " << distance << endl << endl;
909
910 Bmodel* model = model_init("Circle");
911 Bcomponent* comp;
912
913 Bstring comptype = "CIR";
914 Bcomptype* ct = model_add_type_by_id(model, comptype);
915 Bstring id("1");
916
917 long i, n(0);
918 double temp = distance/radius;
919 double angle = acos(1 - temp*temp/2);
920 double angle2;
921 long numpts = (long) (TWOPI / angle + 0.5);
922 angle = TWOPI / numpts;
923
924 if ( radius * 2 < distance ) { //if radius is too small, just place one point at the center
925 comp = component_add(&model->comp, id);
926 comp->loc = Vector3<double>(0,0,z);
927 } else {
928 for( i = 0; i < numpts; i++ ){
929 angle2 = angle * i;
930 id = Bstring(++n, "%d");
931 comp = component_add(&model->comp, id);
932 comp->loc = Vector3<double>(radius * cos(angle2), radius * sin(angle2), z);
933 comp->type = ct;
934 }
935 }
936
937 return model;
938 }
939
947 Bmodel* model_create_ellipse(Vector3<double> axes, double distance)
948 {
949 if (fabs((axes[0] - axes[1]) / axes[1]) < 0.001) // when eccentricity ~ 0, make circle
950 return model_create_circle((axes[0] + axes[1])/2, axes[2], distance);
951
952 //error margins, to be parameterized possibly
953 double derror(0.1 * distance); //error for component separation distance
954 double lastpair(0.85 * distance); //accuracy for an added pair of coordinates' separation
955 double enderror(0.85 * distance); //accuracy for an endpoint distance to be added
956
957 long n = 1;
958 double temp;
959 Vector3<double> loc_old(axes[0], 0, axes[2]), loc_new(0, 0, axes[2]);
960
961 Bstring id("1");
962 Bmodel* model = model_init("Ellipse");
963 Bcomponent* comp = component_add(&model->comp, id);
964 Bstring comptype = "ELL";
965 Bcomptype* ct = model_add_type_by_id(model, comptype);
966 comp->type = ct;
967
968 if ( axes[0] * 2 < distance && axes[1] * 2 < distance ) { //if too small, just put 1 point in middle
969 comp->loc = loc_new;
970 } else {
971 comp->loc = loc_old;
972 while ( loc_old[0] > -axes[0] ) {
973 loc_new[0] = ellipse_next_x(axes, loc_old[0], distance);
974 temp = axes[1] * loc_new[0] / axes[0];
975 loc_new[1] = sqrt(axes[1]*axes[1] - temp*temp);
976 if (fabs(loc_new.distance(loc_old) - distance) < derror //top point is distance from prev top point
977 && 2 * loc_new[1] > lastpair) { //2 points upper and lower too close together
978 id = Bstring(++n, "%ld");
979 comp = component_add(&comp, id);
980 comp->type = ct;
981 comp->loc = loc_new;
982 comp->loc[1] = -comp->loc[1];
983 id = Bstring(++n, "%ld");
984 comp = component_add(&comp, id);
985 comp->type = ct;
986 comp->loc = loc_new;
987 loc_old = loc_new;
988 } else {
989 loc_new = Vector3<double>(-axes[0], 0, axes[2]);
990 if ( loc_new.distance(loc_old) > enderror ) { // if not too bad, put a point at the end
991 id = Bstring(++n, "%ld");
992 comp = component_add(&comp, id);
993 comp->type = ct;
994 comp->loc = loc_new;
995 break;
996 } else break; //don't add endpoint, exit
997 }
998 }
999 }
1000
1001 return model;
1002 }
1003
1011 Bmodel* model_create_ellipsoid(Vector3<double> axes, double distance)
1012 {
1013 long swap_yx(0), swap_zx(0), swap_zy(0), swap_slice(0);
1014 double distance2 = distance*distance;
1015
1016 if ( verbose ) {
1017 cout << "Generating an ellipsoid:" << endl;
1018 cout << "Axes: " << axes << endl;
1019 cout << "Separation: " << distance << endl;
1020 }
1021
1022 // arrange so semi_x > semi_y > semi_z
1023 if (axes[1] > axes[0]) {axes = Vector3<double>(axes[1],axes[0],axes[2]); swap_yx = 1;}
1024 if (axes[2] > axes[0]) {axes = Vector3<double>(axes[2],axes[1],axes[0]); swap_zx = 1;}
1025 if (axes[2] > axes[1]) {axes = Vector3<double>(axes[0],axes[2],axes[1]); swap_zy = 1;}
1026
1027 // compare x-y and y-z eccentricities to set slice axis to z
1028 if (axes[1] * axes[1] < axes[0] * axes[2]) { //simplified ecc. comparison
1029 axes = Vector3<double>(axes[1],axes[2],axes[0]);
1030 swap_slice = 1;
1031 }
1032
1033
1034 long nellipse(0);
1035 double zend = -axes[2], dz = 2*axes[2], temp(0);
1036 Vector3<double> ell_axis(0,0,axes[2]);
1037
1038 Bstring id("1");
1039 Bmodel* model = model_init("Ellipsoid");
1040 Bmodel* current = model;
1041 Bcomponent* comp = component_add(&model->comp, 1);
1042 comp->loc[2] = -zend;
1043
1044 while ( ell_axis[1]*ell_axis[1] + dz*dz > distance2 ) { //y is shorter axis than x, use y to test
1045 ell_axis[2] = ellipsoid_next_z(axes, ell_axis[2], distance);
1046 temp = ell_axis[2]/axes[2];
1047 temp = sqrt(1 - temp*temp);
1048 ell_axis[0] = temp * axes[0];
1049 ell_axis[1] = temp * axes[1];
1050 current->next = model_create_ellipse(ell_axis, distance);
1051 current = current->next;
1052 dz = ell_axis[2] - zend;
1053 nellipse++;
1054 }
1055
1056 if ( verbose ) cout << "Ellipses Generated: " << nellipse << endl << endl;
1057
1058 double derror(0.9*distance2); //allowed error in separation distance for an endpoint
1059
1060 if ( ( ell_axis[0]*ell_axis[0] + dz*dz > derror ) && ( ell_axis[1]*ell_axis[1] + dz*dz > derror ) ) {
1061 current->next = model_init("Endpoint");
1062 comp = component_add(&current->next->comp, 1);
1063 comp->loc[2] = zend;
1064 }
1065
1066 model_merge(model);
1067
1068 Bstring comptype = "VER";
1069 Bcomptype* ct = model_add_type_by_id(model, comptype);
1070 for ( comp = model->comp; comp; comp = comp->next) {
1071 comp->type = ct;
1072 comp->radius = distance/3;
1073 }
1074
1075 Vector3<double> x(1,0,0),y(0,1,0),z(0,0,1);
1076 Matrix3 mat(1);
1077 if(swap_slice) { mat = Matrix3(y,x) * mat; mat = Matrix3(x,z) * mat;}
1078 if(swap_zy) mat = Matrix3(z,y) * mat;
1079 if(swap_zx) mat = Matrix3(z,x) * mat;
1080 if(swap_yx) mat = Matrix3(y,x) * mat;
1081
1082 cout << mat << endl;
1083
1084 model_rotate(model, mat);
1085
1086 return model;
1087 }
1088
1101 Bmodel* model_create_cylinder(Vector3<double> direction, double radius,
1102 double length, double distance)
1103 {
1104 if ( radius <= 0 ) {
1105 cerr << "Error: The cylinder radius must given!" << endl;
1106 return NULL;
1107 }
1108
1109 if ( length <= 0 ) {
1110 cerr << "Error: The cylinder length must given!" << endl;
1111 return NULL;
1112 }
1113
1114 if ( distance <= 0 || distance > radius ) distance = radius/10;
1115
1116 if ( direction.length() < 0.5 )
1117 direction = Vector3<double>(0,0,1);
1118
1119 direction.normalize();
1120
1121 if ( verbose & VERB_FULL )
1122 cout << "Creating a cylinder in direction " << direction << ", radius "
1123 << radius << " and length " << length <<
1124 " with separation " << distance << endl << endl;
1125
1126 Bmodel* model = model_init("Cylinder");
1127 Bcomponent* comp;
1128
1129 Bstring comptype = "CYL";
1130 Bcomptype* ct = model_add_type_by_id(model, comptype);
1131 Bstring id("1");
1132
1133 long i, t(0), n(0);
1134 double a, z, dz(distance/sqrt(2.0));
1135 double temp(distance/radius);
1136 double da(acos(1 - temp*temp/2));
1137 long numpts = (long) (TWOPI / da + 0.5);
1138 da = TWOPI / numpts;
1139
1140 for ( z = -length/2; z <= length/2; z += dz ) {
1141 a = ( t )? da/2: 0;
1142 for( i = 0; i < numpts; i++, a += da ){
1143 id = Bstring(++n, "%d");
1144 comp = component_add(&model->comp, id);
1145 comp->loc = Vector3<double>(radius * cos(a), radius * sin(a), z);
1146 comp->type = ct;
1147 }
1148 t = 1 - t;
1149 }
1150
1151 Vector3<double> ref(0,0,1);
1152 Matrix3 mat = Matrix3(ref, direction);
1153 model_rotate(model, mat);
1154
1155 return model;
1156 }
1157
1170 Bmodel* model_create_plane(double length, double width, double z, double distance)
1171 {
1172 if ( length <= 0 || width <= 0 ) {
1173 cerr << "Error: The plane length and width must given!" << endl;
1174 return NULL;
1175 }
1176
1177 if ( distance <= 0 ) distance = length/10;
1178
1179 if ( verbose & VERB_FULL ) {
1180 cout << "Creating a plane:" << endl;
1181 cout << "Size: " << length << " x " << width << endl;
1182 cout << "Height: " << z << endl;
1183 cout << "Separation: " << distance << endl;
1184 }
1185
1186 Bmodel* model = model_init("Plane");
1187 Bcomponent* comp;
1188
1189 Bstring comptype = "PLN";
1190 Bcomptype* ct = model_add_type_by_id(model, comptype);
1191 Bstring id("1");
1192
1193 long t(0), n(0);
1194 double x, y, hl(length/2), hw(width/2), radius(distance/3);
1195 double dx = distance;
1196 double dy = distance/sqrt(2.0);
1197
1198 for ( y = -hw; y <= hw; y += dy ) {
1199 t = 1 - t;
1200 for ( x = (t)? -hl: -hl+dx/2; x < hl; x += dx ) {
1201 id = Bstring(++n, "%d");
1202 comp = component_add(&model->comp, id);
1203 comp->loc = Vector3<double>(x, y, z);
1204 comp->type = ct;
1205 comp->view = View(0,0,1,0);
1206 comp->radius = radius;
1207 }
1208 }
1209
1210 if ( verbose & VERB_FULL )
1211 cout << "Number of components created: " << n << endl << endl;
1212
1213 return model;
1214 }
1215
1229 Bmodel* model_create_spindle(Vector3<double> direction, double radius,
1230 double separation, double packing)
1231 {
1232 if ( radius <= 0 ) {
1233 cerr << "Error: The sphere radius must given!" << endl;
1234 return NULL;
1235 }
1236
1237 if ( separation <= 0 ) {
1238 cerr << "Error: The component separation distance must given!" << endl;
1239 return NULL;
1240 }
1241
1242 if ( packing <= 0 ) {
1243 cerr << "Error: The packing distance must given!" << endl;
1244 return NULL;
1245 }
1246
1247 if ( direction.length() < 0.5 )
1248 direction = Vector3<double>(0,0,1);
1249
1250 direction.normalize();
1251
1252 if ( verbose & VERB_FULL )
1253 cout << "Creating a spindle in direction " << direction << ", radius "
1254 << radius << " with separation " << separation <<
1255 " and packing " << packing << endl << endl;
1256
1257 Bmodel* model = model_init("Spindle");
1258 Bcomponent* comp;
1259
1260 Bstring comptype = "SPN";
1261 Bcomptype* ct = model_add_type_by_id(model, comptype);
1262 Bstring id("1");
1263
1264 long n(0);
1265 double rp, da(0);
1266 double a, b, amax;
1267 Vector3<double> loc;
1268
1269 for ( ; radius > packing; radius -= packing ) {
1270 amax = 3*M_PI*M_PI*radius/(2*packing);
1271 for ( a=0; a<amax; a+=da ) {
1272 b = M_PI*(a/amax - 0.5);
1273 loc = Vector3<double>(cos(a) * cos(b), sin(a) * cos(b), sin(b)) * radius;
1274 id = Bstring(++n, "%d");
1275 comp = component_add(&model->comp, id);
1276 comp->loc = loc;
1277 comp->type = ct;
1278 cout << loc << endl;
1279 rp = sqrt(loc[0]*loc[0] + loc[1]*loc[1]);
1280 if ( rp > 0.1 ) da = separation/rp;
1281 else da = 1;
1282 }
1283 }
1284
1285 Vector3<double> ref(0,0,1);
1286 Matrix3 mat = Matrix3(ref, direction);
1287 model_rotate(model, mat);
1288
1289 return model;
1290 }
1291
1292
distance
double distance(vector< T1 > &v1, vector< T2 > &v2)
Definition: Vector3.h:536
model_subdivide
long model_subdivide(Bmodel *model, long division)
Definition: model_create.cpp:619
model_set_component_radius
long model_set_component_radius(Bmodel *model, double comprad)
Set the display radius for all components to a specific value.
Definition: rwmodel.cpp:1264
Bcomponent::type
Bcomptype * type
Definition: rwmodel.h:54
vector3_random
Vector3< double > vector3_random(const double min, const double max)
Generates a random vector within a defined cube.
Definition: random_numbers.cpp:440
model_create.h
Library routines used for model creation.
Vector3::normalize
double normalize()
Definition: Vector3.h:236
random_seed
long random_seed()
Gets a random seed and sets the flag.
Definition: random_numbers.cpp:41
Bmodel::id
Bstring id
Definition: rwmodel.h:121
ellipsoid_slice_distance_error
double ellipsoid_slice_distance_error(Vector3< double > axes, double z1, double z2, double distance)
Calculates how far the slice separation is from ideal.
Definition: model_create.cpp:788
Vector3::length
double length()
Definition: Vector3.h:222
model_create_circle
Bmodel * model_create_circle(double radius, double z, double distance)
Creates a circle with the given radius, height, and component separation.
Definition: model_create.cpp:897
vector3_random_gaussian
Vector3< double > vector3_random_gaussian(double avg, double std)
Generates a random vector within a random gaussian-distributed length.
Definition: random_numbers.cpp:502
model_helix
Bmodel * model_helix(double radius, double helix_rise, double helix_angle, long ncomp)
Generates a helix model.
Definition: model_create.cpp:153
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
ellipse_next_x
double ellipse_next_x(Vector3< double > axes, double x1, double distance)
Calculates the next slice's x component to evenly space points.
Definition: model_create.cpp:846
verbose
int verbose
RGBA< float >
Matrix3
Definition: Matrix3.h:17
Bstring::length
long length() const
Definition: Bstring.cpp:263
GOLDEN
#define GOLDEN
Definition: utilities.h:81
model_symmetry.h
Library routines used for model symmetry operations.
component_add
Bcomponent * component_add(Bcomponent **comp, Bstring &id)
Adds a component to a linked list.
Definition: rwmodel.cpp:267
model_random
Bmodel * model_random(long ncomp, double comp_radius, double max_radius)
Generates components at random non-overlapping locations and with random views.
Definition: model_create.cpp:201
kill_symmetry
int kill_symmetry(Bsymmetry *sym)
Deallocates a symmetry structure.
Definition: symmetry.cpp:207
Vector3::distance
double distance(const Vector3 &v)
Definition: Vector3.h:227
model_create_cylinder
Bmodel * model_create_cylinder(Vector3< double > direction, double radius, double length, double distance)
Creates a cylinder with the given radius, length, and component separation.
Definition: model_create.cpp:1101
Vector3::distance2
double distance2(const Vector3 &v)
Definition: Vector3.h:228
random_view
View random_view()
Calculates a random view.
Definition: View.cpp:101
M_PI
#define M_PI
Definition: utilities.h:59
isfinite
bool isfinite(complex< T > &value)
model_random_shell
Bmodel * model_random_shell(long ncomp, double radius)
Generates random components on a shell.
Definition: model_create.cpp:361
model_kill
int model_kill(Bmodel *model)
Deallocates all memory in the list.
Definition: rwmodel.cpp:1124
model_init
Bmodel * model_init(Bstring &id)
Initializes a model structure.
Definition: rwmodel.cpp:144
vector3_random_unit_sphere
Vector3< double > vector3_random_unit_sphere()
Generates a random vector on the unit sphere.
Definition: random_numbers.cpp:419
Bcomponent::view
View view
Definition: rwmodel.h:59
model_create_dodecahedron
Bmodel * model_create_dodecahedron(double radius, long divisions, double sphere_fraction)
Creates an dodecahedron point model.
Definition: model_create.cpp:675
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
length
double length(vector< T > v)
Definition: Vector3.h:528
init_point_group_symmetry
Bsymmetry * init_point_group_symmetry(Bstring symmetry_string)
Sets up a symmetry structure from a string identifier.
Definition: symmetry.cpp:39
model_create_ellipsoid
Bmodel * model_create_ellipsoid(Vector3< double > axes, double distance)
Creates an ellipsoid with given semiaxes and component separation.
Definition: model_create.cpp:1011
model_platonic
Bmodel * model_platonic(Bsymmetry *sym, double radius)
Generates a platonic polyhedron.
Definition: model_create.cpp:82
model_random_gaussian
Bmodel * model_random_gaussian(long ncomp, double std)
Generates components at random gaussian-distributed locations and with random views.
Definition: model_create.cpp:318
irm
double irm(1.0L/get_rand_max())
Bmodel::symmetry
Bstring symmetry
Definition: rwmodel.h:124
View::normalize
double normalize()
Definition: View.h:106
model_rotate
long model_rotate(Bmodel *model, Matrix3 mat)
Rotates the model.
Definition: model_transform.cpp:238
get_rand_max
long get_rand_max()
Finds the maximum random number for a system.
Definition: random_numbers.cpp:22
Bmodel::next
Bmodel * next
Definition: rwmodel.h:120
Bsymmetry::label
Bstring label
Definition: symmetry.h:41
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
Bsymmetry
Definition: symmetry.h:38
model
Bmodel * model
Definition: bshow.cpp:32
volume
T volume(vector< T > v)
Definition: Vector3.h:545
model_apply_point_group
long model_apply_point_group(Bmodel *model, Bstring &symmetry_string, Vector3< double > origin, View ref_view, int flags=0)
Applying symmetry to model components.
Definition: model_symmetry.cpp:71
Bmodel::fom
float fom
Definition: rwmodel.h:128
random_numbers.h
Header file for functions for creating random images.
model_create_icosahedron
Bmodel * model_create_icosahedron(double radius, long divisions, double sphere_fraction)
Creates an icosahedron point model.
Definition: model_create.cpp:732
Bstring
Definition: Bstring.h:29
model_create_plane
Bmodel * model_create_plane(double length, double width, double z, double distance)
Creates a plane with the given length, width, height, and component separation.
Definition: model_create.cpp:1170
Bcomponent::next
Bcomponent * next
Definition: rwmodel.h:52
rwmodel.h
Header file for reading and writing atomic model files.
Bcomptype::id
Bstring id
Definition: rwmodel.h:27
model_spherize
long model_spherize(Bmodel *model, double sphere_fraction)
Definition: model_create.cpp:652
Vector3< double >
model_create_spindle
Bmodel * model_create_spindle(Vector3< double > direction, double radius, double separation, double packing)
Creates a spindle packed inside a sphere.
Definition: model_create.cpp:1229
View
Definition: View.h:26
model_create_ellipse
Bmodel * model_create_ellipse(Vector3< double > axes, double distance)
Creates an ellipse with given semiaxes and component separation.
Definition: model_create.cpp:947
model_scale
long model_scale(Bmodel *model, Vector3< double > scale, Vector3< double > origin)
Scales a model.
Definition: model_transform.cpp:87
Bmodel
Definition: rwmodel.h:119
model_add_component
Bcomponent * model_add_component(Bmodel *model, Bstring &id, Bstring &type, Vector3< double > loc)
Adds a component to a model.
Definition: model_create.cpp:32
model_merge
long model_merge(Bmodel *model)
Merges components from all models into one.
Definition: model_util.cpp:299
Bcomptype
Definition: rwmodel.h:25
Bmodel::comp
Bcomponent * comp
Definition: rwmodel.h:132
ellipsoid_next_z
double ellipsoid_next_z(Vector3< double > axes, double z1, double distance)
Calculates the next slice's z component to evenly space slices.
Definition: model_create.cpp:806
VERB_FULL
#define VERB_FULL
Definition: utilities.h:109
model_create_shell
Bmodel * model_create_shell(long number, double radius, double distance)
Creates a sphere point model.
Definition: model_create.cpp:472
Bcomponent::loc
Vector3< float > loc
Definition: rwmodel.h:58
model_transform.h
Library routines used for model transformation.
TWOPI
#define TWOPI
Definition: utilities.h:68
Bcomponent::color
RGBA< float > color
Definition: rwmodel.h:63
model_create_fibonacci_sphere
Bmodel * model_create_fibonacci_sphere(long number, double radius)
Creates a Fibonacci sphere point model.
Definition: model_create.cpp:569
Bcomponent
Definition: rwmodel.h:51