| Bsoft 2.0.5 Bernard's software package

Bimage_symmetry.cpp
Go to the documentation of this file.
1
9 #include "Bimage.h"
10 #include "rwsymop.h"
11 #include "linked_list.h"
12 #include "utilities.h"
13
14 // Declaration of global variables
15 extern int verbose; // Level of output to the screen
16
31 double Bimage::symmetrize(Bsymmetry* sym, View ref_view, int flag)
32 {
33 if ( sym->point < 102 ) return 0;
34
35 long i, m, theorder(0);
36 double pwr(std*std);
37
38 if ( z == 1 ) {
39 if ( sym->label[0] != 'C' ) {
40 error_show("Error in Bimage::symmetrize: Only cyclic point group symmetries can be applied to 2D images!", __FILE__, __LINE__);
41 return -1;
42 }
43 ref_view = View(0, 0, 1, ref_view.angle());
44 }
45
46 calculate_background();
47
48 if ( verbose & VERB_PROCESS ) {
49 cout << "Applying symmetry " << sym->label << ":" << endl;
50 cout << "Transformation origin: " << image->origin() << endl;
51 cout << "Reference view: " << ref_view << endl;
52 cout << "Fill value: " << background(long(0)) << endl << endl;
53 }
54
55 change_type(Float);
56
57 Matrix3 mat = ref_view.matrix();
58
59 Vector3<double> new_axis(ref_view.vector3());
60
61 Bimage** plist;
62 for ( i=0, theorder = 1; i<sym->n; i++ ) {
63 m = sym->op[i].order;
64 if ( verbose & VERB_PROCESS )
65 cout << "Order[" << i+1 << "] = " << m << endl;
66 theorder *= m;
67 new_axis = mat * sym->op[i].axis;
68 plist = new Bimage*[m];
69 plist[0] = copy();
70 #ifdef HAVE_GCD
71 dispatch_apply(m-1, dispatch_get_global_queue(0, 0), ^(size_t k){
72 long j = k + 1;
73 plist[j] = rotate(size(), new_axis, j*M_PI*2.0/m);
74 });
75 #else
76 #pragma omp parallel for
77 for ( long j=1; j<m; j++ )
78 plist[j] = rotate(size(), new_axis, j*M_PI*2.0/m);
79 #endif
80 sum(m, plist);
81 for ( long j=0; j<m; j++ ) delete plist[j];
82 delete[] plist;
83 }
84 if ( verbose )
85 cout << endl;
86
87 if ( flag ) multiply(1.0L/theorder);
88
89 statistics();
90 calculate_background();
91
92 double f(std*std/pwr);
93 if ( !flag ) f /= theorder;
94
95 if ( verbose & VERB_PROCESS )
96 cout << "Symmetry FOM: " << f <<
97 " (" << n << ")" << endl << endl;
98
99 return f;
100 }
101
112 double Bimage::check_point_group(Bstring& check_string)
113 {
114 check_string = check_string.upper();
115
116 Bstring* sym_list = check_string.split(",");
117 Bstring* sym;
118 Bstring sym_best("none");
119
120 int order;
121 double angle, CC1, CC2, CC3, CCavg(0), CCbest(0);
122 Vector3<double> axis;
123
124 cout << "Group\tAxis1\tCC1\tAxis2\tCC2\tAxis3\tCC3\tCCavg" << endl;
125 for ( sym = sym_list; sym; sym = sym->next ) {
126 cout << *sym << tab;
127 if ( (*sym)[0] == 'C' ) {
128 // sscanf(sym->c_str(), "C%d", &order);
129 order = sym->substr(1,10).integer();
130 axis = Vector3<double>(0,0,1);
131 angle = M_PI*2.0L/order;
132 CCavg = CC1 = rotate_correlate(axis, angle);
133 cout << order << tab << CC1 << "\t-\t-\t-\t-\t" << CCavg << endl;
134 } else if ( (*sym)[0] == 'D' ) {
135 // sscanf(sym->c_str(), "D%d", &order);
136 order = sym->substr(1,10).integer();
137 axis = Vector3<double>(0,0,1);
138 angle = M_PI*2.0L/order;
139 CC1 = rotate_correlate(axis, angle);
140 axis = Vector3<double>(1,0,0);
141 angle = M_PI;
142 CC2 = rotate_correlate(axis, angle);
143 CCavg = (CC1 + CC2)/2;
144 cout << order << tab << CC1 << "\t2\t" << CC2 << "\t-\t-\t" << CCavg << endl;
145 } else if ( (*sym)[0] == 'T' ) {
146 axis = Vector3<double>(0,0,1);
147 angle = M_PI;
148 CC1 = rotate_correlate(axis, angle);
149 axis = Vector3<double>(1,0,0);
150 angle = M_PI;
151 CC2 = rotate_correlate(axis, angle);
152 axis = Vector3<double>(1/sqrt(3.0),1/sqrt(3.0),1/sqrt(3.0));
153 angle = M_PI*2.0L/3.0L;
154 CC3 = rotate_correlate(axis, angle);
155 CCavg = (CC1 + CC2 + CC3)/3;
156 cout << "2\t" << CC1 << "\t2\t" << CC2 << "\t3\t" << CC3 << tab << CCavg << endl;
157 } else if ( (*sym)[0] == 'O' ) {
158 axis = Vector3<double>(0,0,1);
159 angle = M_PI/2.0L;
160 CC1 = rotate_correlate(axis, angle);
161 axis = Vector3<double>(1,0,0);
162 CC2 = rotate_correlate(axis, angle);
163 axis = Vector3<double>(1/sqrt(3.0),1/sqrt(3.0),1/sqrt(3.0));
164 angle = M_PI*2.0L/3.0L;
165 CC3 = rotate_correlate(axis, angle);
166 CCavg = (CC1 + CC2 + CC3)/3;
167 cout << "4\t" << CC1 << "\t4\t" << CC2 << "\t3\t" << CC3 << tab << CCavg << endl;
168 } else if ( (*sym)[0] == 'I' ) {
169 axis = Vector3<double>(0,0,1);
170 angle = M_PI;
171 CC1 = rotate_correlate(axis, angle);
172 axis = Vector3<double>(1/sqrt(3.0),1/sqrt(3.0),1/sqrt(3.0));
173 angle = M_PI*2.0L/3.0L;
174 CC2 = rotate_correlate(axis, angle);
175 axis = Vector3<double>(1.0L/sqrt(GOLDEN*GOLDEN + 1),GOLDEN/sqrt(GOLDEN*GOLDEN + 1.0L),0);
176 angle = M_PI*2.0L/5.0L;
177 CC3 = rotate_correlate(axis, angle);
178 CCavg = (CC1 + CC2 + CC3)/3;
179 cout << "2\t" << CC1 << "\t3\t" << CC2 << "\t5\t" << CC3 << tab << CCavg << endl;
180 }
181 if ( CCbest < CCavg ) {
182 CCbest = CCavg;
183 sym_best = *sym;
184 }
185 }
186
187 cout << endl << "Best symmetry: " << sym_best << endl;
188 cout << "Correlation coefficient: " << CCbest << endl << endl;
189
190 return CCbest;
191 }
192
193 Vector3<double> vector3_closest_to_intersection(Vector3<double> origin1,
194 Vector3<double> origin2, Vector3<double> axis1, Vector3<double> axis2)
195 {
196 Vector3<double> a1 = axis1;
197 Vector3<double> a2 = axis2;
198 double a = a1.scalar(a1);
199 double b = a1.scalar(a2);
200 double c = a2.scalar(a2);
201 double d = a1.scalar(origin1 - origin2);
202 double e = a2.scalar(origin1 - origin2);
203
204 double s, t, denom = a*c - b*b;
205
206 if ( denom < 1e-30 ) { // Parallel lines
207 s = 0;
208 t = d/b;
209 } else {
210 s = (b*e - c*d)/denom;
211 t = (a*e - b*d)/denom;
212 }
213
214 if ( verbose & VERB_FULL )
215 cout << "Intersection distance: " << (origin1 + a1 * s).distance(origin2 + a2 * t) << endl;
216
217 Vector3<double> point = (origin1 + a1 * s + origin2 + a2 * t)/2;
218
219 return point;
220 }
221
234 double Bimage::find_cyclic_point_group(Bsymmetry* sym,
235 int binfac, double hires, double lores)
236 {
237 if ( sym->point < 102 || sym->point > 200 ) return 0;
238
239 if ( binfac < 1 ) binfac = 1;
240 if ( binfac > 4 ) binfac = 4;
241
242 if ( lores > 0 && hires > lores ) swap(hires, lores);
243 if ( hires < 2*binfac*image->sampling()[0] ) hires = 2*binfac*image->sampling()[0];
244 if ( lores < hires ) lores = real_size()[0];
245
246 Bimage* pb = bin_copy(binfac);
247
248 pb->calculate_background();
249
250 fft_plan planf = pb->fft_setup(FFTW_FORWARD, 1);
251 fft_plan planb = pb->fft_setup(FFTW_BACKWARD, 1);
252
253 double cc;
254 Vector3<double> axis(0,0,1), scale(1,1,1), translate;
255 Matrix3 mat(axis, sym->op->angle);
256
257 if ( verbose ) {
258 cout << endl << "Finding orientation based on symmetry " << sym->label << ":" << endl;
259 cout << "Resolution: " << hires << " - " << lores << " A" << endl;
260 cout << "Bin factor: " << binfac << endl;
261 }
262
263 Vector3<double> origin = pb->rotate_find_shift(mat,
264 hires, lores, pb->sizeX()/4, 0, 1, planf, planb, cc);
265
266 origin *= binfac;
267
268 delete pb;
269 fft_destroy_plan(planf);
270 fft_destroy_plan(planb);
271
272 translate = image->origin() - origin;
273 transform(scale, origin, translate, mat, FILL_BACKGROUND, 0);
274
275 if ( verbose ) {
276 cout << "Best origin: " << origin << " " << cc << endl;
277 cout << "Best shift: " << translate << endl << endl;
278 }
279
280 statistics();
281
282 return cc;
283 }
284
299 double Bimage::find_point_group(Bsymmetry* sym, double angle_step,
300 int binfac, double hires, double lores, int flags)
301 {
302 if ( sym->point < 102 ) return 0;
303
304 if ( ( flags & 1 ) && sym->point < 200 )
305 return find_cyclic_point_group(sym, binfac, hires, lores);
306
307 if ( binfac < 1 ) binfac = 1;
308 if ( binfac > 4 ) binfac = 4;
309
310 if ( lores > 0 && hires > lores ) swap(hires, lores);
311 if ( hires < 2*binfac*image->sampling()[0] ) hires = 2*binfac*image->sampling()[0];
312 if ( lores < hires ) lores = real_size()[0];
313
314 long i, op0(0), op1(0), grid_points;
315 double theta(M_PI_2), phi, phi_step, angle(M_PI), bestangle(0);
316 double bestcc(-1);
317 Vector3<double> ref_axis(0,0,1), axis1, axis2, axis3, bestaxis(ref_axis), bestaxis2(1,0,0);
318 Vector3<double> bestorigin, bestorigin2, scale(1,1,1), translate(0,0,0);
319 Matrix3 mat;
320
321 Bimage* pb = bin_copy(binfac);
322
323 pb->calculate_background();
324
325 bestorigin = bestorigin2 = pb->image->origin();
326
327 // Select the operation with the highest order
328 for ( i=0, angle = TWOPI; i<sym->n; i++ ) if ( sym->op[i].angle < angle ) {
329 angle = sym->op[i].angle;
330 op0 = i;
331 }
332
333 // Select the operation with the second highest order
334 for ( i=0, angle = TWOPI; i<sym->n; i++ ) if ( sym->op[i].angle < angle && i != op0 ) {
335 angle = sym->op[i].angle;
336 op1 = i;
337 }
338
339 // Count the number of points in the grid search
340 if ( z > 1 ) {
341 for ( grid_points=0, theta=0; theta<=M_PI_2+0.001; theta += angle_step ) {
342 phi_step = TWOPI;
343 if ( theta > 0 ) phi_step = angle_step/sin(theta);
344 for ( phi=0; phi<TWOPI; phi += phi_step ) grid_points++;
345 }
346 } else { // 2D
347 phi_step = angle_step;
348 for ( grid_points=0, phi=0; phi<TWOPI; phi += phi_step ) grid_points++;
349 }
350
351 // Set up the first grid of axes
352 int nax = (grid_points > 9)? grid_points: 9;
353 Vector3<double>* axis = new Vector3<double>[nax];
354 Vector3<double>* origin = new Vector3<double>[nax];
355 double* cc = new double[nax];
356
357 if ( z > 1 ) {
358 for ( i=0, theta=0; theta<=M_PI_2+0.001; theta += angle_step ) {
359 phi_step = TWOPI;
360 if ( theta > 0 ) phi_step = angle_step/sin(theta);
361 for ( phi=0; phi<TWOPI; phi += phi_step, i++ ) {
362 axis[i][0] = cos(phi)*sin(theta);
363 axis[i][1] = sin(phi)*sin(theta);
364 axis[i][2] = cos(theta);
365 }
366 }
367 } else { // 2D
368 phi_step = angle_step;
369 for ( i=0, phi=0; phi<TWOPI; phi += phi_step, i++ ) {
370 axis[i][0] = axis[i][1] = 0;
371 axis[i][2] = 1;
372 }
373 }
374
375 fft_plan planf = pb->fft_setup(FFTW_FORWARD, 1);
376 fft_plan planb = pb->fft_setup(FFTW_BACKWARD, 1);
377
378 if ( verbose ) {
379 cout << endl << "Finding orientation based on symmetry " << sym->label << ":" << endl;
380 cout << "Angular step size: " << angle_step*180.0/M_PI << endl;
381 cout << "Resolution: " << hires << " - " << lores << " A" << endl;
382 cout << "Bin factor: " << binfac << endl;
383 cout << "Grid points: " << grid_points << endl;
384 cout << "Major axis (" << sym->op[op0].order << "-fold):" << endl;
385 }
386
387 if ( verbose & VERB_LABEL )
388 cout << "#\tax\tay\taz\tCC" << endl;
389
390 long nmax(grid_points);
391 double da(angle_step), amin, amax;
392 Quaternion q1, q, qv;
393 if ( flags & 1 ) da = 0;
394 while ( da > 0.00175 ) { // 0.1 degree limit
395 if ( verbose )
396 cout << "Current angular step: " << da*180.0/M_PI << "\r" << flush;
397
398 #ifdef HAVE_GCD
399 dispatch_apply(nmax, dispatch_get_global_queue(0, 0), ^(size_t i){
400 Matrix3 mat = Matrix3(axis[i], sym->op[op0].angle);
401 origin[i] = pb->rotate_find_shift(mat,
402 hires, lores, pb->sizeX()/4, 0, 1, planf, planb, cc[i]);
403 });
404 #else
405 #pragma omp parallel for
406 for ( i=0; i<nmax; i++ ) {
407 Matrix3 mat = Matrix3(axis[i], sym->op[op0].angle);
408 origin[i] = pb->rotate_find_shift(mat,
409 hires, lores, pb->sizeX()/4, 0, 1, planf, planb, cc[i]);
410 }
411 #endif
412
413 for ( i=0; i<nmax; i++ ) {
414 if ( bestcc < cc[i] ) {
415 bestcc = cc[i];
416 bestaxis = axis[i];
417 bestorigin = origin[i];
418 }
419 if ( verbose & VERB_LABEL )
420 cout << i+1 << tab << axis[i] << tab << cc[i] << endl;
421 if ( verbose & VERB_TIME )
422 cout << "Grid points done: " << i << " (" << i*100.0/nmax << "%) Best: " << bestcc << "\r" << flush;
423 }
424 axis1 = bestaxis.cross(ref_axis);
425 if ( axis1.length() < 0.0001 ) axis1[0] = 1;
426 axis1.normalize();
427 axis2 = bestaxis.cross(axis1);
428 if ( axis2.length() < 0.0001 ) axis2[1] = 1;
429 axis2.normalize();
430 qv = Quaternion(0, bestaxis);
431 da /= 2; // Contract and calculate small grid
432 if ( z > 1 ) {
433 for ( i=0, theta = -da; theta <= da; theta += da ) {
434 q1 = Quaternion(axis1, theta);
435 for ( phi = -da; phi <= da; phi += da, i++ ) {
436 q = Quaternion(axis2, phi);
437 q *= q1;
438 q = q.rotate(qv);
439 axis[i] = q.axis();
440 }
441 }
442 nmax = i;
443 } else break;
444 }
445
446 delete[] axis;
447 delete[] origin;
448 delete[] cc;
449
450 if ( verbose ) {
451 cout << "Best major axis: " << bestaxis << " " << bestcc << endl;
452 cout << "Best origin: " << bestorigin*binfac << endl;
453 }
454
455 if ( sym->n > 1 ) {
456 if ( verbose )
457 cout << "Minor axis (" << sym->op[op1].order << "-fold):" << endl;
458 if ( verbose & VERB_LABEL )
459 cout << "#\tax\tay\taz\tCC" << endl;
460 bestcc = 0;
461 mat = Matrix3(bestaxis, sym->op[op0].axis);
462 axis2 = mat * sym->op[op1].axis;
463 da = angle_step;
464 amin = 0;
465 amax = M_PI;
466
467 // Count the number of points in the grid search
468 for ( grid_points=0, angle=amin; angle<amax; angle+=da ) grid_points++;
469
470 // Set up the first grid of axes
471 nax = (grid_points > 9)? grid_points: 9;
472 axis = new Vector3<double>[nax];
473 origin = new Vector3<double>[nax];
474 cc = new double[nax];
475
476 while ( da > 0.00175 ) { // 0.1 degree limit
477 for ( angle=amin, i=0; angle<amax; angle+=da, i++ ) {
478 mat = Matrix3(bestaxis, angle);
479 axis[i] = mat * axis2;
480 }
481 nax = i;
482
483 #ifdef HAVE_GCD
484 dispatch_apply(nax, dispatch_get_global_queue(0, 0), ^(size_t i){
485 Matrix3 mat = Matrix3(axis[i], sym->op[op1].angle);
486 origin[i] = pb->rotate_find_shift(mat,
487 hires, lores, pb->sizeX()/4, 0, 1, planf, planb, cc[i]);
488 });
489 #else
490 #pragma omp parallel for
491 for ( i=0; i<nax; i++ ) {
492 Matrix3 mat = Matrix3(axis[i], sym->op[op1].angle);
493 origin[i] = pb->rotate_find_shift(mat,
494 hires, lores, pb->sizeX()/4, 0, 1, planf, planb, cc[i]);
495 }
496 #endif
497
498 for ( angle=amin, i=0; angle<amax; angle+=da, i++ ) {
499 if ( bestcc < cc[i] ) {
500 bestcc = cc[i];
501 bestaxis2 = axis[i];
502 bestangle = angle;
503 bestorigin2 = origin[i];
504 }
505
506 if ( verbose & VERB_LABEL )
507 cout << i+1 << tab << axis[i] << tab << cc[i] << endl;
508 if ( verbose & VERB_TIME )
509 cout << "Angles done: " << i+1 << " (" << angle*100.0/M_PI << "%) Best: " << bestcc << "\r" << flush;
510 }
511 da /= 2;
512 amin = bestangle - da;
513 amax = bestangle + da;
514 }
515 bestorigin = vector3_closest_to_intersection(bestorigin, bestorigin2, bestaxis, bestaxis2);
516 if ( verbose ) {
517 cout << "Best minor axis: " << bestaxis2 << " " << bestcc << endl;
518 cout << "Best origin: " << bestorigin2*binfac << endl;
519 cout << "Best intersection origin: " << bestorigin*binfac << endl;
520 }
521
522 delete[] axis;
523 delete[] origin;
524 delete[] cc;
525 }
526
527 delete pb;
528 fft_destroy_plan(planf);
529 fft_destroy_plan(planb);
530
531 bestorigin *= binfac;
532 // bestorigin = bestorigin*binfac + 0.5;
533
534 mat = Matrix3(bestaxis, sym->op[op0].axis);
535 translate = image->origin() - bestorigin;
536 Matrix3 mat2 = Matrix3(sym->op[op0].axis, -bestangle);
537 if ( sym->n > 1 ) mat = mat2 * mat;
538 transform(scale, bestorigin, translate, mat, FILL_BACKGROUND, 0);
539 view(View(mat));
540
541 if ( verbose ) {
542 cout << "Best view: " << image->view() << endl;
543 cout << "Best shift: " << translate << endl << endl;
544 }
545
546 statistics();
547
548 return bestcc;
549 }
550
558 long Bimage::rotate_to_axis(Bsymmetry* sym, long axis, long axis_flag)
559 {
560 Matrix3 mat = symmetry_rotate_to_axis(sym, axis, axis_flag);
561
562 rotate(mat);
563
564 return 0;
565 }
566
583 int Bimage::change_symmetry(Bsymmetry* symold, Bsymmetry* symnu,
584 double radius, double z_slope)
585 {
586 long i, xx, yy, zz, nn;
587 double dx, dy, dz, dxo, dyo, dzo, da, r, ro(1), ca, sa, s;
588 double rr(symold->op[0].order*1.0L/symnu->op[0].order);
589 double af(1/rr - 1);
590
591 float* nudata = new float[datasize];
592
593 if ( verbose ) {
594 cout << "Changing the symmetry from " << symold->label << " to " << symnu->label << ":" << endl;
595 cout << "Radius: " << radius << endl;
596 cout << "Z-slope: " << z_slope << endl << endl;
597 }
598
599 for ( i=nn=0; nn<n; nn++ ) {
600 for ( zz=0; zz<z; zz++ ) {
601 dz = zz - image[nn].origin()[2];
602 s = -(radius + dz*z_slope)*af;
603 dzo = zz;
604 if ( dzo >= z - 1 ) dzo = z - 1.001;
605 for ( yy=0; yy<y; yy++ ) {
606 dy = yy - image[nn].origin()[1];
607 for ( xx=0; xx<x; xx++, i++ ) {
608 nudata[i] = 0;
609 dx = xx - image[nn].origin()[0];
610 da = af*atan2(dy, dx);
611 ca = cos(da);
612 sa = sin(da);
613 if ( radius > 0 ) {
614 r = sqrt(dx*dx + dy*dy);
615 if ( r > 0 ) ro = (1 + s/r);
616 else ro = 1;
617 dxo = ro*(dx*ca - dy*sa) + image[nn].origin()[0];
618 dyo = ro*(dx*sa + dy*ca) + image[nn].origin()[1];
619 } else {
620 dxo = rr*(dx*ca - dy*sa) + image[nn].origin()[0];
621 dyo = rr*(dx*sa + dy*ca) + image[nn].origin()[1];
622 }
623 if ( ro>0 && dxo>=0 && dxo<=x-1 && dyo>=0 && dyo<=y-1 )
624 nudata[i] = interpolate(dxo, dyo, dzo, nn, background(nn));
625 }
626 }
627 }
628 }
629
630 data_type(Float);
631
632 data_assign((unsigned char *) nudata);
633
634 statistics();
635
636 return 0;
637 }
638
654 Matrix3 Bimage::symmetry_equivalent(Bimage* pref, Bimage* pmask, Bsymmetry* sym)
655 {
656 Matrix3 mat(1);
657 if ( !sym ) return mat;
658 if ( sym->point > 600 ) return mat;
659 if ( !pref ) return mat;
660
661 if ( image->origin()[0] < 1 || image->origin()[1] < 1 || image->origin()[2] < 1 ) origin(size()/2);
662
663 if ( sym->point < 200 )
664 return symmetry_equivalent_cyclic(pref, pmask, sym);
665
666 long nstep(1), step;
667 double dang(0), angle(0);
668
669 if ( sym->point < 200 ) { // Cyclic
670 dang = M_PI/180.0; // 1 degree step size
671 nstep = 360/sym->op->order;
672 } else if ( sym->point == 202 ) { // D2
673 nstep = 6;
674 } else if ( sym->point < 300 ) { // Dihedral
675 dang = M_PI*1.0L/sym->op->order;
676 if ( sym->op->order%2 == 0 ) nstep = 2;
677 else nstep = 4;
678 } else if ( sym->point < 400 ) { // Tetrahedral
679 dang = M_PI_2;
680 nstep = 2;
681 } else if ( sym->point < 500 ) { // Octahedral
682 dang = M_PI_2;
683 nstep = 1;
684 } else { // Icosahedral
685 dang = M_PI_2;
686 nstep = 4;
687 }
688
689 double scale(sampling()[0]/pref->sampling()[0]);
690 Vector3<double> axis(0,0,1), best_axis(0,0,1);
691 Vector3<double> vscale(scale, scale, scale);
692 Vector3<double> ori(image->origin()), translate((pref->size() - size())/2);
693 Bimage* pt;
694
695 double ccbest(-1);
696 double cc, best_angle(0);
697 Quaternion q(axis, M_PI_2), q2;
698
699 if ( verbose ) {
700 cout << "Finding the symmetry equivalent for " << sym->label << endl;
701 cout << "Axis\t\t\tAngle\tCC" << setprecision(4) << endl;
702 }
703
704 for ( step = 0; step < nstep; ++step ) {
705 if ( sym->point == 202 ) { // D2
706 switch ( step ) {
707 case 1: angle = M_PI_2; axis = Vector3<double>(0,0,1); break;
708 case 2: angle = M_PI_2; axis = Vector3<double>(0,1,0); break;
709 case 3: angle = M_PI_2; axis = Vector3<double>(1,0,0); break;
710 case 4: angle = M_PI/1.5L; axis = Vector3<double>(1,1,1); break;
711 case 5: angle = -M_PI/1.5L; axis = Vector3<double>(1,1,1); break;
712 default: angle = 0;
713 }
714 axis.normalize();
715 } else if ( sym->point < 300 ) { // Dihedral
716 switch ( step ) {
717 case 1: angle = dang; break;
718 case 2: angle = M_PI_2; break;
719 case 3: angle = M_PI_2 - dang; break;
720 default: angle = 0;
721 }
722 axis.normalize();
723 } else if ( sym->point == 532 ) { // Icosahedral
724 switch ( step ) {
725 case 1: angle = dang; break;
726 case 2: angle = atan(1/GOLDEN); axis = Vector3<double>(1,0,0); break;
727 case 3: q2 = Quaternion(axis, angle); q = q2*q;
728 axis = q.axis(); angle = q.angle(); break;
729 default: angle = 0;
730 }
731 axis.normalize();
732 } else { // Cyclic, tetra-, octahedral
733 angle = step*dang;
734 }
735 mat = Matrix3(axis, angle);
736 pt = transform(pref->size(), vscale, ori, translate, mat, FILL_BACKGROUND);
737 cc = pt->correlate(pref, 0, pref->sizeX()/2, pmask);
738 if ( ccbest < cc ) {
739 ccbest = cc;
740 best_angle = angle;
741 best_axis = axis;
742 // if ( verbose & VERB_PROCESS )
743 // cout << "Better CC: " << cc << " (" << angle*180.0/M_PI << ")" << endl;
744 }
745 delete pt;
746 if ( verbose )
747 cout << axis << tab << angle*180.0/M_PI << tab << cc << endl;
748 }
749
750 if ( verbose ) {
751 cout << "Best axis and angle: " << best_axis << tab << best_angle*180.0/M_PI << endl;
752 cout << "Best CC: " << ccbest << endl;
753 cout << "Fixing symmetry " << sym->label << " orientation" << endl << endl;
754 }
755
756 mat = Matrix3(best_axis, best_angle);
757
758 return mat;
759 }
760
776 Matrix3 Bimage::symmetry_equivalent_cyclic(Bimage* pref, Bimage* pmask, Bsymmetry* sym)
777 {
778 Matrix3 mat(1);
779 if ( !sym ) return mat;
780 if ( sym->point > 200 ) return mat; // Not suitable for groups other than cyclic
781 if ( !pref ) return mat;
782
783 if ( image->origin()[0] < 1 || image->origin()[1] < 1 || image->origin()[2] < 1 ) origin(size()/2);
784
785 double hires(2*pref->sampling()[0]);
786 if ( hires < 20 ) hires = 20; // Starting resolution
787
788 double accuracy(M_PI*0.1/180.0); // Angular accuracy ~ 0.1 degrees
789 if ( accuracy < 3.0/pref->sizeX() ) accuracy = 3.0/pref->sizeX(); // or 2/3 Nyquest
790
791 double dang(hires/pref->real_size()[0]); // Initial angular step size
792 double angle, angmin(0), angmax(TWOPI/sym->op->order+0.01);
793 // long nstep(TWOPI/(sym->op->order*dang)), step;
794 double scale(sampling()[0]/pref->sampling()[0]);
795 Vector3<double> axis(0,0,1);
796 Vector3<double> vscale(scale, scale, scale);
797 Vector3<double> ori(image->origin()), translate((pref->size() - size())/2);
798
799 double ccbest(-1), cc, best_angle(0);
800 Vector3<double> shift, best_shift;
801
802 if ( verbose )
803 cout << "Finding the symmetry equivalent for " << sym->label << setprecision(4) << endl;
804
805 Bimage* pt = transform(pref->size(), vscale, ori, translate, mat, FILL_BACKGROUND);
806
807 // long nannuli(pref->x/2);
808 Bimage* ptcyl = pt->symmetrize_cylinder(1);
809 Bimage* prcyl = pref->symmetrize_cylinder(1);
810
811 delete pt;
812
813 best_shift = ptcyl->find_shift(prcyl, NULL, 4*pref->image->sampling()[0], 0, pref->x/4, 0, 1, ccbest);
814
815 if ( verbose ) {
816 cout << "Shift\t\t\tAngle\tCC" << endl;
817 cout << best_shift << tab << 0 << tab << ccbest << endl;
818 }
819
820 ptcyl->reslice("-xyz");
821
822 shift = ptcyl->find_shift(prcyl, NULL, 4*pref->image->sampling()[0], 0, pref->x/4, 0, 1, cc);
823
824 if ( verbose )
825 cout << shift << tab << 180 << tab << cc << endl;
826
827 if ( ccbest < cc ) {
828 ccbest = cc;
829 best_shift = shift;
830 if ( verbose )
831 cout << "Map is upside down - rotating 180 degrees around x axis" << endl << endl;
832 axis = Vector3<double>(1,0,0);
833 rotate(axis, M_PI);
834 axis = Vector3<double>(0,0,1);
835 // write_img("t.pif", this, 0);
836 }
837
838 delete ptcyl;
839 delete prcyl;
840
841 while ( dang >= accuracy ) {
842 ccbest = -1;
843 cout << "∆ang = " << dang*180.0/M_PI << tab << "res = " << hires << endl;
844 cout << "Shift\t\t\tAngle\tCC" << endl;
845 for ( angle = angmin; angle <= angmax; angle += dang ) {
846 mat = Matrix3(axis, angle);
847 pt = transform(pref->size(), vscale, ori, translate, mat, FILL_BACKGROUND);
848 // cc = pt->correlate(pref, 0, pref->sizeX()/2, pmask);
849 if ( pmask ) pt->multiply(pmask);
850 shift = pt->find_shift(pref, NULL, hires, 0, 10, 0, 1, cc);
851 if ( ccbest < cc ) {
852 ccbest = cc;
853 best_angle = angle;
854 best_shift = shift;
855 // if ( verbose & VERB_PROCESS )
856 // cout << "Better CC: " << cc << " (" << angle*180.0/M_PI << ")" << endl;
857 }
858 delete pt;
859 if ( verbose )
860 cout << shift << tab << angle*180.0/M_PI << tab << cc << endl;
861 }
862 dang *= 0.75;
863 angmin = best_angle - 2*dang;
864 angmax = best_angle + 2.1*dang;
865 hires = dang*pref->real_size()[0];
866 }
867
868 best_shift *= scale;
869
870 if ( verbose ) {
871 cout << "Best shift and angle: " << best_shift << tab << best_angle*180.0/M_PI << endl;
872 cout << "Best CC: " << ccbest << endl;
873 cout << "Fixing symmetry " << sym->label << " orientation" << endl << endl;
874 }
875
876 mat = Matrix3(axis, best_angle);
877 origin(size()/2 + best_shift);
878
879 return mat;
880 }
881
898 Bimage* Bimage::levelmask_asymmetric_units(Bsymmetry* sym, int index)
899 {
900 View ref = view_symmetry_reference(sym);
901
902 if ( verbose & VERB_PROCESS ) {
903 cout << "Generating an asymmetric unit mask:" << endl;
904 cout << "Symmetry: " << sym->label << endl;
905 cout << "Asymmetric unit: ";
906 if ( index > 0 ) cout << index << endl;
907 else cout << "all" << endl;
908 cout << "Reference vector: " << ref << endl << endl;
909 }
910
911 Bimage* pmask = copy_header();
912 pmask->data_type(UCharacter);
913 pmask->data_alloc();
914
915 if ( sym->point < 102 ) {
916 pmask->fill(1);
917 pmask->statistics();
918 return pmask;
919 }
920
921 long i, j, m, nn, xx, yy, zz;
922 double dist, mindist;
923 Vector3<double> testvec, symvec;
924 View* v;
925 View* symview = symmetry_get_all_views(sym, ref);
926
927 for ( i=nn=0; nn<n; nn++ ) {
928 for ( zz=0; zz<z; zz++ ) {
929 testvec[2] = (double)zz - pmask->image[nn].origin()[2];
930 for ( yy=0; yy<y; yy++ ) {
931 testvec[1] = (double)yy - pmask->image[nn].origin()[1];
932 for ( xx=0; xx<x; xx++, i++ ) {
933 testvec[0] = (double)xx - pmask->image[nn].origin()[0];
934 mindist = 1e30;
935 for ( j=m=1, v=symview; v; v=v->next, j++ ) {
936 symvec = v->vector3();
937 dist = testvec.distance(symvec);
938 if ( mindist > dist ) {
939 mindist = dist;
940 m = j;
941 }
942 }
943 if ( index < 1 ) pmask->set(i, m);
944 else if ( index == m ) pmask->set(i, 1);
945 }
946 }
947 }
948 }
949
950 kill_list((char *) symview, sizeof(View));
951
952 pmask->statistics();
953
954 return pmask;
955 }
956
971 int Bimage::replicate_asymmetric_unit(Bsymmetry* sym)
972 {
973 change_type(Float);
974
975 View ref = view_symmetry_reference(sym);
976
977 if ( verbose & VERB_PROCESS ) {
978 cout << "Replicating an asymmetric unit:" << endl;
979 cout << "Symmetry: " << sym->label << endl;
980 cout << "Reference vector: " << ref << endl << endl;
981 }
982
983 if ( sym->point < 102 ) return 0;
984
985 long i, j, cc, nn, xx, yy, zz, nsym(0);
986 double da, minda;
987 Vector3<double> vr(ref.vector3());
988 Vector3<double> v, vt, va;
989 Matrix3* m = symmetry_get_all_matrices(sym, nsym);
990
991 float* nudata = new float[datasize];
992
993 for ( i=nn=0; nn<n; nn++ ) {
994 for ( zz=0; zz<z; zz++ ) {
995 v[2] = zz - image[nn].origin()[2];
996 for ( yy=0; yy<y; yy++ ) {
997 v[1] = yy - image[nn].origin()[1];
998 for ( xx=0; xx<x; xx++ ) {
999 v[0] = xx - image[nn].origin()[0];
1000 minda = 1e30;
1001 for ( j=0; j<nsym; j++ ) {
1002 vt = m[j]*v;
1003 da = vt.angle(vr);
1004 if ( minda > da ) {
1005 minda = da;
1006 va = vt;
1007 }
1008 }
1009 va += image[nn].origin();
1010 for ( cc=0; cc<c; cc++, i++ )
1011 nudata[i] = interpolate(cc, va, nn, background(nn));
1012 }
1013 }
1014 }
1015 }
1016
1017 delete[] m;
1018
1019 data_assign((unsigned char *) nudata);
1020
1021 statistics();
1022
1023 return 0;
1024 }
1025
1042 Bimage* Bimage::find_symmetric_view(Bimage* ptemp, Bsymmetry* sym,
1043 double phi_step, double theta_step, double alpha_step, Vector3<double> shift)
1044 {
1045 if ( verbose ) {
1046 cout << "Finding the best symmetric view:" << endl;
1047 cout << "Theta step size: " << theta_step*180.0/M_PI << endl;
1048 cout << "Phi step size: " << phi_step*180.0/M_PI << endl;
1049 cout << "Alpha step size: " << alpha_step*180.0/M_PI << endl;
1050 cout << "Shift: " << shift << endl;
1051 cout << "Symmetry: " << sym->label << endl;
1052 }
1053
1054 View* views = asymmetric_unit_views(NULL, theta_step, phi_step, 1);
1055
1056 long nv = (long) (TWOPI/alpha_step)*count_list((char *)views);
1057
1058 if ( verbose )
1059 cout << "Number of views: " << nv << endl;
1060
1061 int i(0);
1062 View best_view;
1063 View* v;
1064 Vector3<double> best_shift;
1065 double a, CC, bestCC(0);
1066 Bimage* prot;
1067
1068 if ( verbose )
1069 cout << "#\tvx\tvy\tvz\tva\tCC" << endl;
1070 for ( v = views; v; v = v->next ) {
1071 for ( a = 0; a < TWOPI; a += alpha_step ) {
1072 i++;
1073 (*v)[3] = a;
1074 prot = rotate(size(), shift, *v);
1075 prot->symmetrize(sym, 1);
1076 CC = ptemp->correlate(prot);
1077 if ( bestCC < CC ) {
1078 bestCC = CC;
1079 best_view = *v;
1080 best_shift = shift;
1081 }
1082 if ( verbose & VERB_LABEL )
1083 cout << i << tab << v << tab << CC << endl;
1084 delete prot;
1085 }
1086 }
1087
1088 kill_list((char *) views, sizeof(View));
1089
1090 if ( verbose )
1091 cout << "Best view:\t" << best_view << tab << CC << endl;
1092
1093 prot = rotate(size(), shift, best_view);
1094
1095 return prot;
1096 }
1097
Bimage::change_type
void change_type(char letter)
Get the data type indicated by a single letter code.
Definition: Bimage.cpp:1743
distance
double distance(vector< T1 > &v1, vector< T2 > &v2)
Definition: Vector3.h:536
M_PI_2
#define M_PI_2
Definition: utilities.h:62
Vector3::cross
Vector3 cross(const Vector3 &v)
Definition: Vector3.h:250
Bimage::copy_header
Bimage * copy_header()
Definition: Bimage.h:650
FILL_BACKGROUND
#define FILL_BACKGROUND
Definition: utilities.h:174
Vector3::normalize
double normalize()
Definition: Vector3.h:236
Bsub_image::view
void view(double x, double y, double z, double a)
Definition: Bimage.h:143
Bimage.h
Header file for image class.
Bimage::sampling
Vector3< double > sampling()
Definition: Bimage.h:505
Vector3::length
double length()
Definition: Vector3.h:222
planb
fft_plan planb
Definition: bico.cpp:24
Bstring::substr
Bstring substr(long start, long len)
Definition: Bstring.cpp:324
View::next
View * next
Definition: View.h:28
Bsymmetry::n
int n
Definition: symmetry.h:42
verbose
int verbose
Quaternion::rotate
Quaternion rotate(const Quaternion &point)
Definition: Quaternion.h:173
Bimage::check_point_group
double check_point_group(Bstring &check_string)
Checks for the requested symmetries.
Definition: Bimage_symmetry.cpp:112
Bimage::symmetry_equivalent
Matrix3 symmetry_equivalent(Bimage *ptemp, Bimage *pmask, Bsymmetry *sym)
Finds the symmetry equivalent orientation of a particle with respect to a template.
Definition: Bimage_symmetry.cpp:654
utilities.h
Header file for general utilities.
Bimage::bin_copy
Bimage * bin_copy(long b)
Definition: Bimage.h:1284
planf
fft_plan planf
Definition: bico.cpp:24
Bimage::find_symmetric_view
Bimage * find_symmetric_view(Bimage *ptemp, Bsymmetry *sym, double phi_step, double theta_step, double alpha_step, Vector3< double > shift)
Finds the view that on symmetrizing fits best to a symmetric template.
Definition: Bimage_symmetry.cpp:1042
kill_list
long kill_list(char *list, unsigned long size)
Frees all the items in a linked list.
Definition: linked_list.cpp:214
Bimage::find_cyclic_point_group
double find_cyclic_point_group(Bsymmetry *sym, int binfac, double hires, double lores)
Finds the orientation for an image with a cyclic point group symmetry.
Definition: Bimage_symmetry.cpp:234
Bimage::index
long index(long nx, long ny) const
Definition: Bimage.h:383
Matrix3
Definition: Matrix3.h:17
GOLDEN
#define GOLDEN
Definition: utilities.h:81
count_list
long count_list(char *list)
Counts the number of items in a linked list.
Definition: linked_list.cpp:235
Quaternion
Definition: Quaternion.h:25
symmetry_rotate_to_axis
Matrix3 symmetry_rotate_to_axis(Bsymmetry *sym, long axis, long axis_flag)
Rotation matrix to orient a symmetry axis on the z axis.
Definition: symmetry.cpp:347
Bimage::symmetrize_cylinder
Bimage * symmetrize_cylinder(int flag)
Calculates a cylindrically symmetrized map.
Definition: Bimage_helix.cpp:524
rwsymop.h
Header file for reading and writing symmetry operators.
VERB_PROCESS
#define VERB_PROCESS
Definition: utilities.h:107
Bimage::rotate_to_axis
long rotate_to_axis(Bsymmetry *sym, long axis, long axis_flag)
Rotates to a symmetry axis.
Definition: Bimage_symmetry.cpp:558
Bimage::multiply
void multiply(long j, Complex< double > cv)
Definition: Bimage.h:312
Vector3::distance
double distance(const Vector3 &v)
Definition: Vector3.h:227
Bsymop::angle
double angle
Definition: symmetry.h:27
Bimage::correlate
double correlate(Bimage *p)
Calculates correlation coefficient between two images.
Definition: Bimage_correlate.cpp:36
Bimage::rotate_correlate
double rotate_correlate(Vector3< double > axis, double angle)
Rotates a copy of an image and correlates it with the original.
Definition: Bimage_correlate.cpp:195
Bimage::interpolate
double interpolate(long cc, double xx, double yy=0, double zz=0, long nn=0, double fill=0) const
Interpolates using a given location.
Definition: Bimage.cpp:1392
Float
Definition: utilities.h:157
Bimage::sizeX
long sizeX() const
Definition: Bimage.h:380
Bimage
General image parameter class.
Definition: Bimage.h:163
Bimage::real_size
Vector3< double > real_size()
Definition: Bimage.h:487
Bimage::data_alloc
unsigned char * data_alloc()
Definition: Bimage.h:256
Bimage::transform
int transform(Vector3< double > scale, Vector3< double > origin, Vector3< double > translate, Matrix3 mat, int fill_type=0, double fill=0)
Transforms an image by translation, rotation, scaling and skewing, in place.
Definition: Bimage_transform.cpp:37
M_PI
#define M_PI
Definition: utilities.h:59
linked_list.h
Header file for generalized linked list functions.
Bimage::shift
int shift(Vector3< double > vec, int fill_type=0, double fill=0)
Shifts an image.
Definition: Bimage_transform.cpp:587
Bsymmetry::point
int point
Definition: symmetry.h:39
symmetry_get_all_matrices
Matrix3 * symmetry_get_all_matrices(Bsymmetry *sym, long &nsym)
Get all symmetry-related views of one given view.
Definition: symmetry.cpp:520
Vector3::scalar
double scalar(const Vector3 &v) const
Definition: Vector3.h:247
Bimage::change_symmetry
int change_symmetry(Bsymmetry *symold, Bsymmetry *symnu, double radius, double z_slope)
Changes the symmetry order for cyclic and dihedral maps.
Definition: Bimage_symmetry.cpp:583
Bimage::statistics
long statistics()
Calculates the statistics for an image.
Definition: Bimage_stats.cpp:22
Bstring::next
Bstring * next
Definition: Bstring.h:31
Vector3::angle
double angle(Vector3< T2 > &v)
Definition: Vector3.h:257
Bimage::data_assign
unsigned char * data_assign(unsigned char *nudata)
Assign image data.
Definition: Bimage.cpp:852
VERB_TIME
#define VERB_TIME
Definition: utilities.h:110
fft_plan
fftwf_plan fft_plan
Definition: fft.h:16
Bimage::sum
void sum(long m, Bimage **p)
Sums an array of images with their FOM blocks.
Definition: Bimage_combine.cpp:23
asymmetric_unit_views
View * asymmetric_unit_views(Bsymmetry *sym, double theta_step, double phi_step, int flag)
Initializes a well-distributed set of views in an asymmetric unit.
Definition: symmetry.cpp:570
Bsymop::order
int order
Definition: symmetry.h:26
Bimage::symmetrize
double symmetrize(Bstring &symmetry_string, int flag)
Definition: Bimage.h:1178
Bimage::size
Vector3< long > size() const
Definition: Bimage.h:373
Bimage::calculate_background
int calculate_background(long nn, int flag)
Calculates the background for one sub-image.
Definition: Bimage_background.cpp:27
Bstring::upper
Bstring upper()
Definition: Bstring.cpp:316
View::vector3
Vector3< double > vector3()
Definition: View.h:126
Bsub_image::origin
void origin(double x, double y, double z)
Definition: Bimage.h:127
Bsub_image::sampling
void sampling(double x, double y, double z)
Definition: Bimage.h:123
Bimage::view
void view(double vx, double vy, double vz, double va)
Definition: Bimage.h:589
Bsymmetry::label
Bstring label
Definition: symmetry.h:41
Bimage::set
void set(long j, double v)
Sets a single value at the given index.
Definition: Bimage.cpp:1096
Bsymmetry
Definition: symmetry.h:38
Bimage::symmetry_equivalent_cyclic
Matrix3 symmetry_equivalent_cyclic(Bimage *pref, Bimage *pmask, Bsymmetry *sym)
Finds the cyclic symmetry equivalent orientation of a particle with respect to a template.
Definition: Bimage_symmetry.cpp:776
Bimage::levelmask_asymmetric_units
Bimage * levelmask_asymmetric_units(Bsymmetry *sym, int index)
Calculates a multi-level mask to indicate asymmetric units.
Definition: Bimage_symmetry.cpp:898
UCharacter
Definition: utilities.h:149
Bstring
Definition: Bstring.h:29
Bimage::copy
Bimage * copy()
Copies the header information and data of an image into a new image structure.
Definition: Bimage.cpp:2695
Bimage::sizeX
void sizeX(long nx)
Definition: Bimage.h:377
Bimage::fft_setup
fft_plan fft_setup(fft_direction dir, int opt=0)
Sets up a plan for fast Fourier transforms.
Definition: Bimage_fft.cpp:29
View::matrix
Matrix3 matrix()
Definition: View.h:150
Vector3< double >
fft_destroy_plan
int fft_destroy_plan(fft_plan plan)
Deallocates a plan for fast Fourier transforms.
Definition: fft.cpp:87
Quaternion::axis
Vector3< double > axis()
Definition: Quaternion.h:144
View::angle
double angle()
Definition: View.h:95
View
Definition: View.h:26
Bimage::rotate
int rotate()
Rotates an image using parameters defined in the image in place.
Definition: Bimage_transform.cpp:253
Bimage::find_shift
int find_shift(Bimage *pref, Bimage *pmask, double hires, double lores, double radius, double sigma, int refine_flag)
Calculates a cross-correlation map to find the shift for the pair of images.
Definition: Bimage_correlate.cpp:932
Bstring::integer
long integer()
Definition: Bstring.cpp:539
vector3_closest_to_intersection
Vector3< double > vector3_closest_to_intersection(Vector3< double > origin1, Vector3< double > origin2, Vector3< double > axis1, Vector3< double > axis2)
Definition: Bimage_symmetry.cpp:193
Bimage::find_point_group
double find_point_group(Bsymmetry *sym, double angle_step, int binfac, double hires, double lores, int flags)
Finds the orientation for an image with a specific point group symmetry.
Definition: Bimage_symmetry.cpp:299
Bsymmetry::op
Bsymop * op
Definition: symmetry.h:43
Bimage::fill
void fill(double v)
Definition: Bimage.h:698
Bimage::replicate_asymmetric_unit
int replicate_asymmetric_unit(Bsymmetry *sym)
Calculates a full map from one asymmetric unit.
Definition: Bimage_symmetry.cpp:971
VERB_FULL
#define VERB_FULL
Definition: utilities.h:109
Bimage::background
double background(long nn)
Definition: Bimage.h:542
VERB_LABEL
#define VERB_LABEL
Definition: utilities.h:106
Bimage::data_type
DataType data_type()
Definition: Bimage.h:349
Bsymop::axis
Vector3< double > axis
Definition: symmetry.h:25
TWOPI
#define TWOPI
Definition: utilities.h:68
Bimage::rotate_find_shift
Vector3< double > rotate_find_shift(Matrix3 mat, double hires, double lores, double radius, double sigma, int refine_flag, fft_plan planf, fft_plan planb, double &cc)
Rotates and find shift by cross-correlation.
Definition: Bimage_correlate.cpp:1306
symmetry_get_all_views
View * symmetry_get_all_views(Bsymmetry *sym, View asu_view)
Get all symmetry-related views of one given view.
Definition: symmetry.cpp:448
error_show
int error_show(string message, string file, int line)
Displays the error with file and line reference.
Definition: utilities.cpp:755
tab
ostream & tab(ostream &out)
Definition: utilities.cpp:21
Bimage::image
Bsub_image * image
Definition: Bimage.h:188
view_symmetry_reference
View view_symmetry_reference(Bsymmetry *sym)
Returns an asymmetric unit reference point.
Definition: symmetry.cpp:315
Bimage::origin
void origin(double ox, double oy, double oz)
Definition: Bimage.h:563
Bstring::split
Bstring * split()
Definition: Bstring.cpp:597