| Bsoft 2.0.5 Bernard's software package

marker.cpp
Go to the documentation of this file.
1
9 #include "rwmodel.h"
10 #include "marker.h"
11 #include "matrix_linear.h"
12 #include "Matrix3.h"
13 #include "Matrix.h"
14 #include "ps_marker.h"
15 #include "qsort_functions.h"
16 #include "linked_list.h"
17 #include "utilities.h"
18 #include "timer.h"
19 #include <fstream>
20
21 // Declaration of global variables
22 extern int verbose; // Level of output to the screen
23
24 // Local function prototypes
25 int markers_findOneToOne(Bmarker* refset, Bmarker* applyset);
26 double* markers_RoughMatch(Bmarker* setA, Bmarker* setB, double dist_cutoff);
27 int markers_sort_rel_distance(Bmarker* set, Bmarker* ref);
28
34 long marker_stats(Bmarker* markers)
35 {
36 long n(0);
37 Bmarker* mark;
38 Vector3<double> min(1e30, 1e30, 1e30), max(-1e30, -1e30, -1e30);
39 Vector3<double> avg, std;
40
41 for ( mark = markers; mark; mark = mark->next ) if ( mark->sel ) {
42 min = min.min(mark->loc);
43 max = max.max(mark->loc);
44 avg += mark->loc;
45 std += mark->loc * mark->loc;
46 n++;
47 }
48
49 avg /= n;
50 std = ((std/n) - (avg*avg)).square_root();
51
52 cout << "Number of selected markers: " << n << endl;
53 cout << "Minimum: " << min << endl;
54 cout << "Maximum: " << max << endl;
55 cout << "Average: " << avg << endl;
56 cout << "Standard deviation: " << std << endl;
57
58 return n;
59 }
60
61 Bmarker* markers_copy(Bmarker* mark, int sel_flag)
62 {
63 Bmarker* newmark = NULL;
64 Bmarker* m = NULL;
65 Bmarker* m2 = NULL;
66 long nmark(0);
67
68 for ( m = mark; m; m = m->next ) if ( !sel_flag || m->sel ) {
69 m2 = (Bmarker *) add_item((char **) &m2, sizeof(Bmarker));
70 if ( !newmark ) newmark = m2;
71 m2->id = m->id;
72 m2->img_num = m->img_num;
73 m2->loc = m->loc;
74 m2->err = m->err;
75 m2->res = m->res;
76 m2->fom = m->fom;
77 m2->sel = m->sel;
78 nmark++;
79 }
80
81 if ( verbose & VERB_PROCESS )
82 cout << "Marker model initialized with " << nmark << " markers" << endl << endl;
83
84 return newmark;
85 }
86
92 Bmarker* markers_copy(Bmarker* mark)
93 {
94 return markers_copy(mark, 0);
95 }
96
102 Bmarker* markers_copy_selected(Bmarker* mark)
103 {
104 return markers_copy(mark, 1);
105 }
106
120 long markers_add(Bmarker** mark, Bmarker* mark2, double mindist, int sel)
121 {
122 int id(0);
123 Bmarker* m;
124 Bmarker* m2;
125
126 for ( m = *mark; m; m = m->next ) if ( id < m->id ) id = m->id;
127 for ( m2 = mark2; m2; m2 = m2->next ) m2->sel = 1;
128
129 if ( *mark ) {
130 for ( m = *mark; m; m = m->next )
131 for ( m2 = mark2; m2; m2 = m2->next )
132 if ( m->loc.distance(m2->loc) < mindist )
133 m2->sel = 0;
134 m = *mark;
135 for ( m2 = mark2; m2; m2 = m2->next ) if ( m2->sel ) {
136 m = (Bmarker *) add_item((char **) &m, sizeof(Bmarker));
137 m->id = ++id;
138 m->img_num = m2->img_num;
139 m->loc = m2->loc;
140 m->err = m2->err;
141 m->res = m2->res;
142 m->fom = m2->fom;
143 m->sel = m2->sel;
144 if ( sel > 0 ) m->sel = sel;
145 }
146 kill_list((char *) mark2, sizeof(Bmarker));
147 } else *mark = mark2;
148
149 long nmark = count_list((char *) *mark);
150
151 return nmark;
152 }
153
159 long markers_delete_non_selected(Bmarker** mark)
160 {
161 Bmarker* m = markers_copy_selected(*mark);
162 kill_list((char *) *mark, sizeof(Bmarker));
163 *mark = m;
164
165 return count_list((char *) m);
166 }
167 /*
168 long markers_delete_non_selected(Bmarker** mark)
169 {
170 Bmarker* m = NULL;
171 long nmark(0);
172
173 for ( m = *mark; m; ) {
174 if ( m->sel < 1 ) {
175 m = (Bmarker *) remove_item((char **)mark, (char *)m, sizeof(Bmarker));
176 } else {
177 m = m->next;
178 nmark++;
179 }
180 }
181
182 return nmark;
183 }
184 */
185
192 int marker_shift(Bmarker* markers, Vector3<double> shift)
193 {
194 Bmarker* mark;
195
196 for ( mark = markers; mark; mark = mark->next )
197 mark->loc += shift;
198
199 return 0;
200 }
201
208 int marker_scale(Bmarker* markers, Vector3<double> scale)
209 {
210 Bmarker* mark;
211
212 for ( mark = markers; mark; mark = mark->next ) {
213 mark->loc *= scale;
214 mark->err *= scale;
215 }
216
217 return 0;
218 }
219
226 int marker_transform(Bmarker* markers, Transform t)
227 {
228 int nmark(0);
229 Bmarker* mark;
230
231 Matrix3 mat = Matrix3(t.axis, t.angle);
232 mat = t.scale * mat;
233
234 for ( mark = markers; mark; mark = mark->next, nmark++ ) {
235 mark->loc = t * mark->loc;
236 mark->err = mat * mark->err;
237 }
238
239 return nmark;
240 }
241
248 double marker_compare(Bmarker* mark1, Bmarker* mark2)
249 {
250 int nmark(0);
251 double R(0);
252 Bmarker* m1;
253 Bmarker* m2;
254
255 for ( m1 = mark1, m2 = mark2; m1 && m2; m1 = m1->next, m2 = m2->next, nmark++ ) {
256 m2->err = m1->loc - m2->loc;
257 m2->res = m2->err.length();
258 R += m2->res * m2->res;
259 }
260
261 if ( nmark ) R = sqrt(R/nmark);
262
263 return R;
264 }
265
279 Matrix3 marker_find_matrix(Bmarker* markers1, Bmarker* markers2,
280 Vector3<double> origin1, Vector3<double> origin2)
281 {
282 int i, j, n(0);
283 Bmarker* mark1;
284 Bmarker* mark2;
285 Vector3<double> loc1, loc2;
286 Matrix3 mat(1);
287 vector<double> x(4), y(4), bx(4), by(4), bz(4);
288 Matrix a(4,4);
289
290 for ( i=0; i<4; i++ ) bx[i] = by[i] = bz[i] = 0;
291
292 for ( mark1 = markers1; mark1; mark1 = mark1->next ) if ( mark1->sel ) {
293 for ( mark2 = markers2; mark2 && mark2->id != mark1->id; mark2 = mark2->next ) ;
294 if ( mark2 && mark2->sel ) {
295 loc1 = mark1->loc - origin1;
296 loc2 = mark2->loc - origin2;
297 for ( i=0; i<3; i++ ) {
298 x[i] = loc1[i];
299 y[i] = loc2[i];
300 }
301 x[3] = y[3] = 1;
302 for ( i=0; i<4; i++ ) {
303 for ( j=0; j<4; j++ )
304 a[i][j] += x[i]*x[j];
305 bx[i] += x[i]*y[0];
306 by[i] += x[i]*y[1];
307 bz[i] += x[i]*y[2];
308 }
309 n++;
310 }
311 }
312
313 if ( n < 3 ) {
314 cerr << "Error in marker_find_matrix: Too few shared markers! (" << n << ")" << endl << endl;
315 return mat;
316 }
317
318 // cout << a;
319 a.LU_decomposition();
320 a.multiply_in_place(bx);
321 a.multiply_in_place(by);
322 a.multiply_in_place(bz);
323 // cout << a;
324
325 for ( i=0; i<3; i++ ) {
326 mat[0][i] = bx[i];
327 mat[1][i] = by[i];
328 mat[2][i] = bz[i];
329 }
330
331 return mat;
332 }
333
346 Transform marker_find_transform(Bmarker* markers1, Bmarker* markers2, Vector3<double> origin)
347 {
348 int i, j, n(0);
349 Bmarker* mark1;
350 Bmarker* mark2;
351 Vector3<double> loc1, loc2;
352 Matrix3 mat(1);
353 Matrix a(4,4);
354 // double x[4], y[4], bx[4], by[4], bz[4];
355 vector<double> x(4), y(4), bx(4), by(4), bz(4);
356 Transform t;
357
358 if ( verbose & VERB_DEBUG )
359 cout << "DEBUG marker_find_transform: origin=" << origin << endl;
360
361 for ( i=0; i<4; i++ ) bx[i] = by[i] = bz[i] = 0;
362
363 for ( mark1 = markers1; mark1; mark1 = mark1->next ) if ( mark1->sel ) {
364 for ( mark2 = markers2; mark2 && mark2->id != mark1->id; mark2 = mark2->next ) ;
365 if ( mark2 && mark2->sel ) {
366 loc1 = mark1->loc - origin;
367 loc2 = mark2->loc - origin;
368 for ( i=0; i<3; i++ ) {
369 x[i] = loc1[i];
370 y[i] = loc2[i];
371 }
372 x[3] = y[3] = 1;
373 for ( i=0; i<4; i++ ) {
374 for ( j=0; j<4; j++ )
375 a[i][j] += x[i]*x[j];
376 bx[i] += x[i]*y[0];
377 by[i] += x[i]*y[1];
378 bz[i] += x[i]*y[2];
379 }
380 n++;
381 }
382 }
383
384 if ( n < 3 ) {
385 cerr << "Error in marker_find_transform: Too few shared markers! (" << n << ")" << endl << endl;
386 return t;
387 }
388
389 if ( verbose & VERB_DEBUG )
390 cout << a << endl;
391
392 t = transform_matrix_solve(a, bx, by, bz, 0);
393
394 t.origin = origin;
395
396 return t;
397 }
398
416 Transform markers_find_rottrans(Bmarker* set1, Bmarker* set2, double tolerance)
417 {
418 Transform t;
419 long n = count_list((char *) set1);
420
421 if ( n != count_list((char *) set2) ) {
422 cerr << "Error: The two sets must have the same number of points!" << endl;
423 return t;
424 }
425
426 // Set pointers to point arrays
427 Bmarker* m1;
428 Bmarker* m2;
429
430 int i, j(0), goodpoints = n, lastgoodpoints = n + 1, imaxdev;
431 double xshift, yshift, xscale, yscale, phi, maxdev;
432 double xstdev, ystdev, bestxstdev = tolerance*100, bestystdev = tolerance*100;
433 double phi_min = -M_PI, phi_max = M_PI, phi_step = M_PI/10000;
434 double cos_phi, sin_phi;
435 double bestphi(0), bestxshift(0), bestyshift(0);
436 double bestxscale = 1, bestyscale = 1;
437 double R, bestR = 1e37;
438 double dx, dy, dd;
439
440 double* s1 = new double[n];
441 double* s2 = new double[n];
442
443 // Data points to ignore
444 int* ignore = new int[n];
445
446 for ( i=0; i<n; i++ ) s1[i] = s2[i] = ignore[i] = 0;
447
448 // if ( verbose & VERB_DEBUG )
449 if ( verbose & VERB_FULL ) {
450 cout << "Coordinate sets:" << endl;
451 for ( m1=set1, m2=set2; m1; m1=m1->next, m2=m2->next )
452 cout << m1->loc[0] << "," << m1->loc[1] << " - " << m2->loc[0] << "," << m2->loc[1] << endl;
453 cout << endl << "Fitting the coordinate sets:" << endl;
454 }
455
456 while ( ( bestxstdev > tolerance || bestystdev > tolerance )
457 && goodpoints > n/2 && goodpoints < lastgoodpoints ) {
458 lastgoodpoints = goodpoints;
459 bestR = 1e30;
460 for ( phi=phi_min; phi<=phi_max; phi+=phi_step ) {
461 cos_phi = cos(phi);
462 sin_phi = sin(phi);
463 for ( i=j=0, m1=set1, m2=set2; m1; m1=m1->next, m2=m2->next, i++ ) {
464 if ( !ignore[i] ) {
465 s1[j] = m1->loc[0]*cos_phi - m1->loc[1]*sin_phi;
466 s2[j] = m2->loc[0];
467 j++;
468 }
469 }
470 linear_least_squares(0, j-1, s1, s2, xshift, xscale);
471 for ( i=j=0, xstdev = 0, m1=set1, m2=set2; m1; m1=m1->next, m2=m2->next, i++ ) {
472 if ( !ignore[i] ) {
473 dx = m2->loc[0] - (xscale*s1[j] + xshift);
474 xstdev += dx*dx;
475 s1[j] = m1->loc[0]*sin_phi + m1->loc[1]*cos_phi;
476 s2[j] = m2->loc[1];
477 j++;
478 }
479 }
480 linear_least_squares(0, j-1, s1, s2, yshift, yscale);
481 for ( i=j=0, ystdev = 0, m1=set1, m2=set2; m1; m1=m1->next, m2=m2->next, i++ ) {
482 if ( !ignore[i] ) {
483 dy = m2->loc[1] - (yscale*s1[j] + yshift);
484 ystdev += dy*dy;
485 j++;
486 }
487 }
488 R = 1e37;
489 if ( j > 0 ) {
490 R = sqrt((xstdev + ystdev)/j);
491 xstdev = sqrt(xstdev/j);
492 ystdev = sqrt(ystdev/j);
493 }
494 if ( bestR > R ) {
495 bestxstdev = xstdev;
496 bestystdev = ystdev;
497 bestR = R;
498 bestphi = phi;
499 bestxshift = xshift;
500 bestyshift = yshift;
501 bestxscale = xscale;
502 bestyscale = yscale;
503 }
504 }
505
506 if ( bestxscale < 0 && bestyscale < 0 && fabs(bestphi) > M_PI_2 ) {
507 bestxscale = -bestxscale;
508 bestyscale = -bestyscale;
509 bestphi = bestphi + M_PI;
510 if ( bestphi > M_PI ) bestphi -= TWOPI;
511 }
512
513 // Calculate the coordinates for the second set using the first set
514 imaxdev = 0;
515 maxdev = 0;
516 cos_phi = cos(bestphi);
517 sin_phi = sin(bestphi);
518 for ( i=j=0, m1=set1, m2=set2; m1; m1=m1->next, m2=m2->next, i++ ) {
519 if ( !ignore[i] ) {
520 dx = m2->loc[0] - (bestxscale*(m1->loc[0]*cos_phi -
521 m1->loc[1]*sin_phi) + bestxshift);
522 dy = m2->loc[1] - (bestyscale*(m1->loc[0]*sin_phi +
523 m1->loc[1]*cos_phi) + bestyshift);
524 dd = dx*dx + dy*dy;
525 if ( maxdev < dd ) {
526 maxdev = dd;
527 imaxdev = i;
528 }
529 j++;
530 if ( verbose & VERB_DEBUG ) {
531 cout << "DEBUG markers_find_rottrans: " << dx << "," << dy << endl;
532 }
533 }
534 }
535 ignore[imaxdev] = 1;
536 goodpoints--;
537 phi_min = bestphi - 0.1;
538 phi_max = bestphi + 0.1;
539 if ( goodpoints < n/4 )
540 cerr << "Error: Number of points used (" << goodpoints << ") too small!" << endl;
541 if ( verbose >= VERB_FULL )
542 cout << " " <<
543 j << " " << bestxshift << " " << bestyshift << " " << bestxscale << " " << bestyscale << " " <<
544 bestphi*180.0/M_PI << " (" << bestxstdev << " " << bestystdev << " " << bestR << ")" << endl;
545 }
546 if ( verbose >= VERB_FULL )
547 cout << "Fit: " <<
548 j << " " << bestxshift << " " << bestyshift << " " << bestxscale << " " << bestyscale << " " <<
549 bestphi*180.0/M_PI << " (" << bestxstdev << " " << bestystdev << " " << bestR << ")" << endl;
550 if ( verbose >= VERB_PROCESS ) cout << endl;
551
552 delete[] s1;
553 delete[] s2;
554 delete[] ignore;
555
556 t.trans[0] = bestxshift;
557 t.trans[1] = bestyshift;
558 t.scale[0] = bestxscale;
559 t.scale[1] = bestyscale;
560 t.angle = bestphi;
561 t.fom = bestR;
562
563 return t;
564 }
565
585 Transform* markers_map_and_find_transform(Bmarker** set, int nseries, int refset, Vector3<long> size)
586 {
587 int j, matched_pairs;
588 Transform* tlist = NULL;
589 Transform* t = NULL;
590 Bstring filename;
591
592 if ( verbose & VERB_LABEL )
593 cout << "X-shift Y-shift Z-shift X-scale Y-scale Z-scale Angle" << endl;
594
595 for ( j=0; j<nseries; j++ ) {
596 t = (Transform *) add_item((char **) &t, sizeof(Transform));
597 if ( !tlist ) tlist = t;
598 *t = Transform();
599 if ( j != refset ) {
600 matched_pairs = markers_findOneToOne(set[refset],set[j]);
601 if ( matched_pairs != 0 ) {
602 *t = markers_find_rottrans(set[refset], set[j], 2);
603 if ( t->fom ) {
604 filename = Bstring(j, "final_errors%d.ps");
605 ps_marker_errors(filename, set[refset], set[j], *t, size, 20);
606 if ( verbose & VERB_LABEL )
607 cout << t->trans << " " << t->scale << " " << t->angle*180/M_PI << endl;
608 }
609 if ( verbose & VERB_DEBUG ) {
610 filename = Bstring(j, "final_match%d.ps");
611 ps_marker_match(set[refset], set[j], filename);
612 }
613 } else {
614 error_show("Error in markers_map_and_find_transform", __FILE__, __LINE__);
615 cerr <<"Not able to match micrographs " << refset+1 << " and " << j+1 << endl;
616 return tlist;
617 }
618 }
619 }
620
621 return tlist;
622 }
623
624 /*
625 @author Samuel Payne
626 @brief Finds a one to one mapping of two coordinate sets. The sets should
627 have a large intersection to begin with.
628 @param *refset coordinate set serving as reference
629 @param *applyset coordinate set to be matched to refset
630 @return int matched_pairs the number of points in the 1 to 1 mapping
631
632 To get a rough matching, we attempt to match every point in B with
633 a point in A. (Looping through a few points in A as well.) The
634 transformation parameters are recorded for the rough match with
635 the lowest error. Finally it goes through an exaustive brute force
636 matching with the estimates of the transform parameters and
637 produces the one to one mapping. It rewrites the point* sets so
638 that the matching points have the same index.
639 (set1[0] matches set2[0], set1[1] matches set2[1], ...)
640
641 **/
642 int markers_findOneToOne(Bmarker* refset, Bmarker* applyset)
643 {
644 long num_matches=0;
645 double error;
646 Vector3<double> calc;
647 double besterror = 100, phi(0), xshift(0), yshift(0), zshift(0);
648 double* match_params = NULL;
649 Bmarker *m, *mr, *mA, *mB, *setA, *setB, *bestB;
650
651 long nA = count_list((char *) refset);
652 long nB = count_list((char *) applyset);
653 Vector3<double> min = refset->loc;
654 Vector3<double> max = refset->loc;
655
656 // if ( verbose & VERB_DEBUG ) {
657 cout << "DEBUG markers_findOneToOne: nA=" << nA << " nB=" << nB << endl;
658
659 for ( m=refset; m; m=m->next ) {
660 min = min.min(m->loc);
661 max = max.max(m->loc);
662 }
663
664 double refsize = max.distance(min);
665 Vector3<double> refcenter = (max + min) * 0.5;
666
667 double dist_cutoff = refsize *.03;
668 double dist_err_cutoff = 0.5 * refsize;
669
670 min = applyset->loc;
671 max = applyset->loc;
672 for ( m=applyset; m; m=m->next ) {
673 min = min.min(m->loc);
674 max = max.max(m->loc);
675 }
676
677 // double applysize = max.distance(min);
678 Vector3<double> applycenter = (max + min) * 0.5;
679
680 for ( mA=refset; mA; mA=mA->next ) {
681 if ( mA->loc.distance(refcenter) < refsize/4 ) {
682 setA = (Bmarker *) copy_list((char *) refset, sizeof(Bmarker));
683 markers_sort_rel_distance(setA, mA);
684 for ( mB=applyset; mB; mB=mB->next ) {
685 if ( mB->loc.distance(applycenter) < refsize/4 ) {
686 setB = (Bmarker *) copy_list((char *) applyset, sizeof(Bmarker));
687 markers_sort_rel_distance(setB, mB);
688 match_params = markers_RoughMatch(setA, setB, dist_cutoff);
689 if ( (match_params[0] < besterror) && (match_params[4] > nA/3) ) {
690 besterror = match_params[0];
691 phi = match_params[1];
692 xshift = match_params[2];
693 yshift = match_params[3];
694 }//end if besterr
695 delete[] match_params;
696 kill_list((char *) setB, sizeof(Bmarker));
697 }
698 }
699 kill_list((char *) setA, sizeof(Bmarker));
700 }
701 }
702
703 // if ( besterror > 99 ) return 0; //no matches with an error less than 100 are acceptable
704
705 // if ( verbose & VERB_DEBUG ) {
706 cout << "DEBUG markers_findOneToOne: Final match found. Parameter estimates:" << endl;
707 cout << "\tangle " << phi*180/M_PI << " xshift " << xshift << " yshift " << yshift << endl;
708 // }
709
710 num_matches = 0;
711 setA = (Bmarker *) copy_list((char *) refset, sizeof(Bmarker));
712 setB = (Bmarker *) copy_list((char *) applyset, sizeof(Bmarker));
713 m = applyset;
714 mr = refset;
715 for ( mA=setA; mA; mA=mA->next ) {
716 calc[0] = mA->loc[0]* cos(phi) + mA->loc[1] * sin(phi) + xshift;
717 calc[1] = -1*mA->loc[0]* sin(phi) + mA->loc[1] * cos(phi) + yshift;
718 calc[2] = zshift;
719 bestB = NULL;
720 besterror = dist_err_cutoff;
721 for ( mB=setB; mB; mB=mB->next ) {
722 error = mB->loc.distance(calc);
723 if ( error < besterror ) {
724 besterror = error;
725 bestB = mB;
726 }
727 }
728 if ( bestB ) {
729 copy_item((char *)m, (char *)bestB, sizeof(Bmarker));
730 copy_item((char *)mr, (char *)mA, sizeof(Bmarker));
731 m = m->next;
732 mr = mr->next;
733 num_matches++;
734 }
735 }
736
737 kill_list((char *) setA, sizeof(Bmarker));
738 kill_list((char *) setB, sizeof(Bmarker));
739
740 kill_list((char *) m, sizeof(Bmarker));
741 kill_list((char *) mr, sizeof(Bmarker));
742
743 return num_matches;
744 }
745
746 /*
747 @author Samuel Payne
748 @brief Produces a match of two sets and estimate the transform parameters.
749 @param Bmarker* setA the first coordinate set.
750 @param Bmarker* setB the second coordinate set.
751 @param double dist_cutoff max difference allowed in matching d_rel variables
752 @return double* the transform parameters, the set error, and size.
753
754 This finds the rough matching of two sets of points. These sets are
755 assumed to be sorted relative to their distance to a relative point.
756 It then computes a histogram of all the angular deviations. Taking
757 the largest bin as the true angle (not averaging all values as that
758 is subject to outliers). It removes all matches whose angular
759 deviations are further from the true angle than the angle tolerance
760 allows. Finally it calculates the x and y shift parameters, error and
761 set size.
762 **/
763 double* markers_RoughMatch(Bmarker* setA, Bmarker* setB, double dist_cutoff)
764 {
765 int a, i, j, bins = 360, max;
766 double best_phi=0, phi, ang_tol = M_PI/10, xshift, yshift, error = 1e37;
767 double scale = bins*1.0/(TWOPI);
768 double dx, dy, sumdx_sq, sumdy_sq, sumdx, sumdy;
769
770 long nA = count_list((char *) setA);
771 // long nB = count_list((char *) setB);
772
773 Bmarker *mA, *mB;
774 double d;
775
776 Bmarker** match = new Bmarker*[nA];
777 int* histo = new int[bins];
778 double* params = new double[5];
779 double* phi_devs = new double[nA];
780
781 /* The loop starts at a=1, b=1 because the first points have a zero
782 distances. They always match each other (a trivial solution). they
783 also have a zero angle, which is not characteristic of the set in
784 general. so it should be excluded. */
785 for ( a=1, mA=setA->next, mB=setB->next; mA && mB; mA=mA->next, mB=mB->next, a++ ) {
786 // for( a=1, b=1; a<nA && b<nB; a++, b++ ) {
787 /* These while loops find an 'a' and 'b' that match each other according to the
788 relative distance variable. while the next point of b matches better than the
789 current than advance the b counter. same for a. This strategy works because the
790 sets are sorted according to the d_rel variable (relative distance). If the difference
791 between the distance vars is less than a cutoff the match is accepted. */
792 d = mA->err.length2();
793 while ( mB->next &&
794 ( fabs(d - mB->err.length2()) > fabs(d - mB->next->err.length2()) ) ) {
795 mB = mB->next;
796 }
797 d = mB->err.length2();
798 while ( mA->next &&
799 ( fabs(mA->err.length2() - d) > fabs(mA->next->err.length2() - d)) ) {
800 mA = mA->next;
801 a++;
802 }
803 if ( fabs(mA->err.length2() - mB->err.length2()) < dist_cutoff ) {
804 /* Here a histogram of the angular deviations is set up. There are 360
805 bins which are meant to correspond to the 360 degrees in a unit circle.
806 The angles are shifted between 0 and 2PIs so they can be scaled into a
807 bin easily. The additional 0.5 shift before casting to int ensures that
808 values slightly under a bin are put in bin they are closest to. In the
809 bottom else j==bin, therefore j = 360, which corresponds to 360 degrees,
810 the same as 0 degrees. therefore it is put into histo[0]. */
811 match[a] = mB;
812 phi = angle_set_negPI_to_PI(mA->fom - mB->fom);
813 phi_devs[a] = phi;
814 j = (int) (scale*(phi)+ 0.5);
815 if ( j < bins ) histo[j]++;
816 else histo[0]++;
817 }
818 }
819
820 //find the Max bin value. that is an initial estimate of the angle
821 for ( max=0, i=0; i<bins; i++ ) {
822 if ( histo[i] > max ) {
823 best_phi = i; //now holds the degree value of the angle
824 max = histo[i];
825 }
826 }
827 best_phi = best_phi / scale; //now holds the RADIAN value
828 xshift = yshift = j = 0;
829 for ( a=1, mA=setA; mA && a<nA; a++, mA=mA->next ) {
830 if ( match[a] ) {
831 phi = fabs(phi_devs[a] - best_phi);
832 if ( phi > M_PI ) phi -= TWOPI;
833 if ( fabs(phi) > ang_tol ) {
834 match[a] = NULL;
835 } else {
836 dx = match[a]->loc[0] - mA->loc[0]*cos(best_phi) - mA->loc[1]*sin(best_phi);
837 dy = match[a]->loc[1] + mA->loc[0]*sin(best_phi) - mA->loc[1]*cos(best_phi);
838 xshift += dx;
839 yshift += dy;
840 j++; //here j is acting as a count variable
841 }
842 }
843 }
844 xshift = xshift/j;
845 yshift = yshift/j;
846 sumdx = sumdy = sumdx_sq = sumdy_sq = j = 0;
847
848 for ( a=1, mA=setA; mA && a<nA; a++, mA=mA->next ) {
849 if ( match[a] ) {
850 dx = match[a]->loc[0] - mA->loc[0]*cos(best_phi) - mA->loc[1]*sin(best_phi) - xshift;
851 dy = match[a]->loc[1] + mA->loc[0]*sin(best_phi) - mA->loc[1]*cos(best_phi) - yshift;
852 sumdx += dx;
853 sumdy += dy;
854 sumdx_sq += dx*dx;
855 sumdy_sq += dy*dy;
856 j++; //here j is acting as a count var
857 }
858 }
859
860 if ( j ) {
861 sumdx = sumdx/j;
862 sumdy = sumdy/j;
863 error = sqrt((sumdx_sq + sumdy_sq)/j - sumdx*sumdx - sumdy*sumdy);
864 if ( !isfinite(error) ) error = 1e37;
865 }
866
867 params[0] = error;
868 params[1] = best_phi;
869 params[2] = xshift;
870 params[3] = yshift;
871 params[4] = j; //num_matches
872
873 if ( verbose & VERB_DEBUG ) {
874 /*if ( error < 100 && j > nA/5 )*/
875 if ( max > 15 ){
876 cout << endl << "DEBUG markers_RoughMatch:" << endl;
877 cout << "error " << error << " angle " << best_phi << " xshift " <<
878 xshift << " yshift " << yshift << " count " << j << endl;
879 cout << "DEBUG markers_RoughMatch: angular deviation histogram bins" << endl;
880 for ( a=0; a<bins; a++ ) {
881 if ( histo[a] != 0 )
882 cout << "bin " << a << " value " << histo[a] << endl;
883 }
884 }
885 }
886
887 delete[] histo;
888 delete[] match;
889 delete[] phi_devs;
890
891 return params;
892 }
893
909 long markers_limit(int target_num, int sign, Bmarker** set)
910 {
911 long n = count_list((char *) set);
912
913 if ( target_num < 1 || n < 1 ) return -1;
914 if ( target_num >= n ) return 0;
915
916 long i;
917 Bmarker* m, *mp;
918 double* toSort = new double[n];
919
920 for ( i=0, m=*set; i<n && m; i++, m=m->next ) toSort[i] = m->fom;
921
922 if ( sign < 0 )
923 qsort((void *) toSort, n, sizeof(double), QsortSmallToLargeFloat);
924 else
925 qsort((void *) toSort, n, sizeof(double), QsortLargeToSmallFloat);
926
927 // if ( verbose & VERB_DEBUG )
928 cout << "DEBUG markers_limit: n=" << n << " target_num=" << target_num << endl;
929
930 long count(0);
931 double cutoff = toSort[target_num];
932
933 delete[] toSort;
934
935 for ( m=mp=*set; m; ) { cout << "Marker " << m->id << " Previous " << mp->id << endl;
936 if ( sign*m->fom < sign*cutoff ) {
937 cout << "Removing " << m->id << " from " << (*set)->id << endl;
938 if ( *set == m ) *set = m->next;
939 m = (Bmarker *) remove_item((char **) &mp, (char *) m, sizeof(Bmarker));
940 if ( m ) cout << "New marker " << m->id << " Previous " << mp->id << " Set " << (*set)->id << endl;
941 } else {
942 count++;
943 mp = m;
944 m = m->next;
945 }
946 }
947
948 if ( verbose & VERB_LABEL )
949 cout << "Limiting the size of the coordinate set from " << n << " to " <<
950 target_num << " (threshold = " << cutoff << ")" << endl;
951
952 return count;
953 }
954
955 /*
956 @author Samuel Payne
957 @brief Sorts a set of markers based on the distance to a reference marker.
958 @param *set coordinate set.
959 @param *ref reference point.
960 @return int 0.
961
962 The FOM is set to the angle of rotation of the vector connecting
963 the reference marker to the marker.
964
965 **/
966 int markers_sort_rel_distance(Bmarker* set, Bmarker* ref)
967 {
968 Bmarker* m, *mp;
969
970 for ( m=set; m; m=m->next ) {
971 m->err = m->loc - ref->loc;
972 m->fom = m->err.length2();
973 }
974
975 long count = 1;
976
977 while ( count ) {
978 count = 0;
979 for ( m=mp=set; m; mp=m, m=m->next ) {
980 if ( m->fom < mp->fom ) {
981 mp->next = m->next;
982 m->next = mp;
983 m = mp;
984 count++;
985 }
986 }
987 }
988
989 for ( m=set; m; m=m->next )
990 m->fom = atan2(m->err[1], m->err[0]);
991
992 return 0;
993 }
994
1002 Bmodel* model_from_markers(Bmarker* markers, Vector3<double> origin, Vector3<double> sam)
1003 {
1004 if ( !markers ) return NULL;
1005
1006 Bmarker* mark;
1007 Bmodel* model = model_init("Markers");
1008 Bcomponent* comp = NULL;
1009 Bstring comptype = "MRK";
1010 Bstring id;
1011
1012 if ( verbose )
1013 cout << "Generating a model from markers" << endl << endl;
1014
1015 model->id = "Markers";
1016
1017 for ( mark = markers; mark; mark = mark->next ) {
1018 id = Bstring(mark->id, "%d");
1019 comp = component_add(&comp, id);
1020 if ( !model->comp ) model->comp = comp;
1021 comp->type = model_add_type_by_id(model, comptype);
1022 comp->loc = sam * (mark->loc - origin);
1023 comp->radius = sam[0];
1024 }
1025
1026 return model;
1027 }
1028
1042 int marker_plane(Bmarker* markers, Vector3<double> origin)
1043 {
1044 long i, j, n;
1045 double offset, d, R;
1046 vector<double> b(3);
1047 Matrix a(3,3);
1048 Bmarker* mark;
1049 Vector3<double> loc, normal, sum;
1050
1051 for ( i=0; i<3; i++ ) b[i] = 0;
1052 sum = 0;
1053 for ( n=0, mark = markers; mark; mark = mark->next, n++ ) {
1054 loc = mark->loc - origin;
1055 sum += loc;
1056 for ( i=0; i<3; i++ ) {
1057 for ( j=0; j<=i; j++ )
1058 a[j][i] += loc[i]*loc[j];
1059 b[i] += loc[i];
1060 }
1061 }
1062 sum /= n;
1063 for ( i=1; i<3; i++ )
1064 for ( j=0; j<i; j++ )
1065 a[i][j] = a[j][i];
1066 offset = 0;
1067 if ( a[0][0] == 0 ) {
1068 normal = Vector3<double>(1, 0, 0);
1069 } else if ( a[1][1] == 0 ) {
1070 normal = Vector3<double>(0, 1, 0);
1071 } else if ( a[2][2] == 0 ) {
1072 normal = Vector3<double>(0, 0, 1);
1073 } else {
1074 // show_matrix(3, 3, a);
1075 a.LU_decomposition(b);
1076 // show_matrix(3, 3, a);
1077 normal = Vector3<double>(b[0], b[1], b[2]);
1078 // offset = 1.0/normal.length();
1079 normal.normalize();
1080 offset = sum.scalar(normal);
1081 cout << b[0] << tab << b[1] << tab << b[2] << tab << offset << endl;
1082 }
1083 n = 0;
1084 R = 0;
1085 cout << "Marker\tDistance" << endl;
1086 for ( mark = markers; mark; mark = mark->next ) {
1087 d = (mark->loc - origin).scalar(normal) - offset;
1088 cout << mark->id << tab << d << endl;
1089 R += d*d;
1090 n++;
1091 }
1092 R = sqrt(R/n);
1093 cout << "Solution: " << normal[0] << " x + " << normal[1] << " y + " <<
1094 normal[2] << " z = " << offset << " R = " << R << endl;
1095
1096 return 0;
1097 }
1098
1104 Bmarker* markers_sort_by_id(Bmarker** mark)
1105 {
1106 if ( ! *mark ) return NULL;
1107
1108 long i, max_id(0);
1109 Bmarker* m;
1110
1111 for ( m = *mark; m; m = m->next ) if ( max_id <= m->id ) max_id = m->id + 1;
1112
1113 if ( verbose & VERB_DEBUG )
1114 cout << "DEBUG markers_sort_by_id: max_id = " << max_id << endl;
1115
1116 Bmarker** mlist = new Bmarker*[max_id];
1117 for ( i=0; i<max_id; i++ ) mlist[i] = NULL;
1118
1119 for ( m = *mark; m; m = m->next ) mlist[m->id] = m;
1120
1121 m = *mark = NULL;
1122
1123 for ( i=0; i<max_id; i++ ) {
1124 if ( mlist[i] ) {
1125 if ( m ) {
1126 m->next = mlist[i];
1127 m = m->next;
1128 } else {
1129 m = mlist[i];
1130 *mark = m;
1131 }
1132 }
1133 }
1134
1135 m->next = NULL;
1136
1137 delete[] mlist;
1138
1139 if ( verbose & VERB_DEBUG )
1140 cout << "DEBUG markers_sort_by_id: *mark = " << *mark << endl;
1141
1142 return *mark;
1143 }
1144
1150 long markers_renumber(Bmarker* mark)
1151 {
1152 if ( ! mark ) return 0;
1153
1154 if ( verbose & VERB_DEBUG )
1155 cout << "DEBUG markers_renumber" << endl;
1156
1157 long nmark(0);
1158 Bmarker* m;
1159
1160 for ( m = mark; m; m = m->next )
1161 m->id = ++nmark;
1162
1163 return nmark;
1164 }
1165
1176 long markers_center(Bmarker* mark, Vector3<double> center)
1177 {
1178 if ( ! mark ) return 0;
1179
1180 if ( verbose & VERB_DEBUG )
1181 cout << "DEBUG markers_center" << endl;
1182
1183 long nmark;
1184 Bmarker* m;
1185 Vector3<double> mark_center, shift;
1186
1187 for ( nmark=0, m = mark; m; m = m->next, nmark++ )
1188 mark_center += m->loc;
1189
1190 if ( nmark ) {
1191 mark_center /= nmark;
1192 shift = center - mark_center;
1193 for ( m = mark; m; m = m->next ) m->loc += shift;
1194 }
1195
1196 return nmark;
1197 }
1198
1208 Bmarker* marker_set_at_radius(double rad, double ainc)
1209 {
1210 long n;
1211 double a;
1212 Bmarker* marklist = NULL;
1213 Bmarker* mark = NULL;
1214
1215 for ( n=0, a=-M_PI; a<M_PI; a+=ainc ) {
1216 mark = (Bmarker *) add_item((char **) &mark, sizeof(Bmarker));
1217 if ( !marklist ) marklist = mark;
1218 n++;
1219 mark->id = n;
1220 mark->loc = Vector3<double>(rad*cos(a), rad*sin(a), 0);
1221 }
1222
1223 return marklist;
1224 }
1225
1237 int marker_sets_to_bild(Bstring& filename, Bmarker* mark1, Bmarker* mark2)
1238 {
1239 Bmarker* mark;
1240
1241 if ( verbose )
1242 cout << "Generating a bild file: " << filename << endl << endl;
1243
1244 ofstream fbld(filename.c_str());
1245 if ( fbld.fail() ) return -1;
1246
1247 fbld << endl;
1248 fbld << ".color red" << endl;
1249 for ( mark = mark1; mark; mark = mark->next ) if ( mark->sel ) {
1250 fbld << ".sphere " << mark->loc[0] << " " << mark->loc[1] << " " << mark->loc[2] << " " << 10.0 << endl;
1251 }
1252
1253 fbld << endl;
1254 fbld << ".color blue" << endl;
1255 for ( mark = mark2; mark; mark = mark->next ) if ( mark->sel ) {
1256 fbld << ".sphere " << mark->loc[0] << " " << mark->loc[1] << " " << mark->loc[2] << " " << 10.0 << endl;
1257 }
1258
1259 fbld << endl;
1260
1261 fbld.close();
1262
1263 return 0;
1264 }
1265
1266
copy_list
char * copy_list(char *list, unsigned long size)
Generates a complete copy of a linked list.
Definition: linked_list.cpp:185
M_PI_2
#define M_PI_2
Definition: utilities.h:62
qsort_functions.h
Header file for utility functions for use in qsort calls.
Bcomponent::type
Bcomptype * type
Definition: rwmodel.h:54
markers_findOneToOne
int markers_findOneToOne(Bmarker *refset, Bmarker *applyset)
Definition: marker.cpp:642
Vector3::normalize
double normalize()
Definition: Vector3.h:236
Bmodel::id
Bstring id
Definition: rwmodel.h:121
Vector3::length
double length()
Definition: Vector3.h:222
utilities.h
Header file for general utilities.
VERB_DEBUG
#define VERB_DEBUG
Definition: utilities.h:112
angle_set_negPI_to_PI
double angle_set_negPI_to_PI(double angle)
Returns an angle between -PI and PI.
Definition: utilities.cpp:594
marker_transform
int marker_transform(Bmarker *markers, Transform t)
Transforming markers.
Definition: marker.cpp:226
Transform::angle
double angle
Definition: Transform.h:29
kill_list
long kill_list(char *list, unsigned long size)
Frees all the items in a linked list.
Definition: linked_list.cpp:214
Transform::fom
double fom
Definition: Transform.h:32
Bmarker
Definition: marker.h:21
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
count_list
long count_list(char *list)
Counts the number of items in a linked list.
Definition: linked_list.cpp:235
markers_delete_non_selected
long markers_delete_non_selected(Bmarker **mark)
Deletes markers not selected.
Definition: marker.cpp:159
Matrix::multiply_in_place
int multiply_in_place(vector< double > &vec)
Definition: matrix.cpp:49
component_add
Bcomponent * component_add(Bcomponent **comp, Bstring &id)
Adds a component to a linked list.
Definition: rwmodel.cpp:267
marker_find_transform
Transform marker_find_transform(Bmarker *markers1, Bmarker *markers2, Vector3< double > origin)
Determines the rotation matrix between two sets of markers.
Definition: marker.cpp:346
Matrix.h
Generalized matrix class.
model_from_markers
Bmodel * model_from_markers(Bmarker *markers, Vector3< double > origin, Vector3< double > sam)
Convert markers to a model.
Definition: marker.cpp:1002
markers_center
long markers_center(Bmarker *mark, Vector3< double > center)
Centers a set of markers.
Definition: marker.cpp:1176
VERB_PROCESS
#define VERB_PROCESS
Definition: utilities.h:107
marker_scale
int marker_scale(Bmarker *markers, Vector3< double > scale)
Scaling markers.
Definition: marker.cpp:208
markers_sort_by_id
Bmarker * markers_sort_by_id(Bmarker **mark)
Sorts a set of markers by ID number.
Definition: marker.cpp:1104
Vector3::distance
double distance(const Vector3 &v)
Definition: Vector3.h:227
Matrix3.h
3x3 Matrix manipulation functions
timer.h
Utilities for timing functions.
QsortLargeToSmallFloat
int QsortLargeToSmallFloat(const void *x, const void *y)
Utility function for sorting floating point values in qsort.
Definition: qsort_functions.cpp:31
Vector3::max
Type max()
Definition: Vector3.h:175
scalar
double scalar(vector< T1 > &v1, vector< T2 > &v2)
Definition: Vector3.h:611
markers_limit
long markers_limit(int target_num, int sign, Bmarker **set)
This method constricts a marker set to target_num points.
Definition: marker.cpp:909
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.
isfinite
bool isfinite(complex< T > &value)
markers_find_rottrans
Transform markers_find_rottrans(Bmarker *set1, Bmarker *set2, double tolerance)
Finds the rotation and shift between two sets of vectors.
Definition: marker.cpp:416
model_init
Bmodel * model_init(Bstring &id)
Initializes a model structure.
Definition: rwmodel.cpp:144
markers_copy_selected
Bmarker * markers_copy_selected(Bmarker *mark)
Copies a set of markers based on selection.
Definition: marker.cpp:102
marker_plane
int marker_plane(Bmarker *markers, Vector3< double > origin)
Fits a plane to a set of markers.
Definition: marker.cpp:1042
marker_compare
double marker_compare(Bmarker *mark1, Bmarker *mark2)
Compare marker sets and calculates the root-mean-square deviation.
Definition: marker.cpp:248
Vector3::scalar
double scalar(const Vector3 &v) const
Definition: Vector3.h:247
marker_stats
long marker_stats(Bmarker *markers)
Calculating marker statistics.
Definition: marker.cpp:34
ps_marker_errors
int ps_marker_errors(Bstring &filename, Bmarker *set1, Bmarker *set2, Transform t, Vector3< int > size, float err_scale)
Output a postscript file that graphs the deviations of points in a Bmarker from their predicted locat...
Definition: ps_marker.cpp:34
ps_marker_match
int ps_marker_match(Bmarker *set1, Bmarker *set2, Bstring &filename)
Output a postscript file that draws a line between matching features in a pair of coordinate sets.
Definition: ps_marker.cpp:124
ps_marker.h
Header file for postscript tools dealing with Bmarkers.
copy_item
char * copy_item(char *toitem, char *fromitem, unsigned long size)
Copies an item to an existing item without changing the link.
Definition: linked_list.cpp:87
marker_shift
int marker_shift(Bmarker *markers, Vector3< double > shift)
Shifting markers.
Definition: marker.cpp:192
Transform::scale
Vector3< double > scale
Definition: Transform.h:31
Bmarker::fom
float fom
Definition: marker.h:28
Bmarker::id
int id
Definition: marker.h:23
Transform::trans
Vector3< double > trans
Definition: Transform.h:30
remove_item
char * remove_item(char **list, char *item, unsigned long size)
Finds the given item and deletes it from the linked list.
Definition: linked_list.cpp:114
Vector3::length2
double length2()
Definition: Vector3.h:221
markers_renumber
long markers_renumber(Bmarker *mark)
Renumbers a set of markers.
Definition: marker.cpp:1150
Bstring::c_str
const char * c_str()
Definition: Bstring.h:70
marker_sets_to_bild
int marker_sets_to_bild(Bstring &filename, Bmarker *mark1, Bmarker *mark2)
Generates a bild file with the two marker sets.
Definition: marker.cpp:1237
Bmarker::next
Bmarker * next
Definition: marker.h:22
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
Transform::origin
Vector3< double > origin
Definition: Transform.h:27
QsortSmallToLargeFloat
int QsortSmallToLargeFloat(const void *x, const void *y)
Utility function for sorting floating point values in qsort.
Definition: qsort_functions.cpp:17
Matrix
Definition: Matrix.h:21
Bstring
Definition: Bstring.h:29
verbose
int verbose
matrix_linear.h
Header file for matrix functions.
Bmarker::img_num
int img_num
Definition: marker.h:24
rwmodel.h
Header file for reading and writing atomic model files.
markers_copy
Bmarker * markers_copy(Bmarker *mark, int sel_flag)
Definition: marker.cpp:61
Vector3< double >
Bmarker::err
Vector3< float > err
Definition: marker.h:26
marker_set_at_radius
Bmarker * marker_set_at_radius(double rad, double ainc)
Generates a marker set at a given radius with z=0.
Definition: marker.cpp:1208
Vector3::min
Type min()
Definition: Vector3.h:169
markers_RoughMatch
double * markers_RoughMatch(Bmarker *setA, Bmarker *setB, double dist_cutoff)
Definition: marker.cpp:763
Bmarker::loc
Vector3< float > loc
Definition: marker.h:25
markers_sort_rel_distance
int markers_sort_rel_distance(Bmarker *set, Bmarker *ref)
Definition: marker.cpp:966
Bmodel
Definition: rwmodel.h:119
Transform::axis
Vector3< double > axis
Definition: Transform.h:28
transform_matrix_solve
Transform transform_matrix_solve(Matrix a, vector< double > &bx, vector< double > &by, vector< double > &bz, int flag)
Solves a 3D geometry fit matrix.
Definition: Transform.cpp:30
markers_map_and_find_transform
Transform * markers_map_and_find_transform(Bmarker **set, int nseries, int refset, Vector3< long > size)
This function finds the transform parameters between sets of coordinates. These sets are expected to ...
Definition: marker.cpp:585
marker_find_matrix
Matrix3 marker_find_matrix(Bmarker *markers1, Bmarker *markers2, Vector3< double > origin1, Vector3< double > origin2)
Determines the rotation matrix between two sets of markers.
Definition: marker.cpp:279
Bmodel::comp
Bcomponent * comp
Definition: rwmodel.h:132
markers_add
long markers_add(Bmarker **mark, Bmarker *mark2, double mindist, int sel)
Adds a set of markers to another.
Definition: marker.cpp:120
VERB_FULL
#define VERB_FULL
Definition: utilities.h:109
VERB_LABEL
#define VERB_LABEL
Definition: utilities.h:106
Bcomponent::loc
Vector3< float > loc
Definition: rwmodel.h:58
Bmarker::res
float res
Definition: marker.h:27
TWOPI
#define TWOPI
Definition: utilities.h:68
marker.h
Header file for image parameter functions.
Bmarker::sel
int sel
Definition: marker.h:29
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
linear_least_squares
double linear_least_squares(int n1, int n2, double *x, double *y, double &a, double &b)
Does a linear least squares fit between two vectors.
Definition: matrix_linear.cpp:28
Bcomponent
Definition: rwmodel.h:51