1#ifndef RNAPUZZLER_VECTOR_MATH_H
2#define RNAPUZZLER_VECTOR_MATH_H
3
4/*
5 *      RNApuzzler math helper
6 *
7 *      c  Daniel Wiegreffe, Daniel Alexander, Dirk Zeckzer
8 *      ViennaRNA package
9 */
10
11#include <math.h>
12#include <stdio.h>
13
14#include "definitions.inc"
15
16#define MATH_PI      3.141592653589793
17#define MATH_PI_HALF (MATH_PI / 2.0)
18#define MATH_TWO_PI  (2.0 * MATH_PI)
19#define TO_DEGREE    (180.0 / MATH_PI)
20#define TO_RAD       (MATH_PI / 180.0)
21
22PRIVATE double
23toDegree(double angle);
24
25
26PRIVATE double
27toRad(double angle);
28
29
30/**
31 * @brief vectorLength2D
32 *      - calculates the length of a 2D vector
33 * @param vector
34 *      - double array[2] with vector coordinates x,y
35 * @return
36 *      - length of input vector
37 */
38PRIVATE double
39vectorLength2D(const double vector[2]);
40
41
42/**
43 * @brief vectorLength2DSquared
44 *      - calculates the squared length of a 2D vector
45 * @param vector
46 *      - double array[2] with vector coordinates x,y
47 * @return
48 *      - squared length of input vector
49 */
50PRIVATE double
51vectorLength2DSquared(const double vector[2]);
52
53
54/**
55 * @brief scalarProduct2D
56 *      - calculates the scalar product (or dot product) of two given 2D vectors
57 *        v1 * v2 = ( v1.x * v2.x + v1.y * v2.y ) / ( |v1| * |v2| )
58 * @param vector1
59 *      - double array[2] with vector coordinates x,y
60 * @param vector2
61 *      - double array[2] with vector coordinates x,y
62 * @return
63 *      - scalar product of both given input vectors
64 */
65PRIVATE double
66scalarProduct2D(const double  *vector1,
67                const double  *vector2);
68
69
70/**
71 * @brief normalize
72 *      - normalizes the vector to length 1, same direction
73 * @param vector
74 *      - double array[2] with vector coordinates x,y
75 */
76PRIVATE void
77normalize(double *vector);
78
79
80/**
81 * @brief isToTheRightPointPoint determines if a point is left or right to a line.
82 * @param lineStart[2]
83 * @param lineEnd[2]
84 * @param point[2]
85 * @return 1 if point is right to the vector from lineStart to lineEnd, 0 otherwise
86 */
87PRIVATE short
88isToTheRightPointPoint(const double lineStart[2],
89                       const double lineEnd[2],
90                       const double point[2]);
91
92
93/**
94 * @brief isToTheRightPointVector
95 *      - same as isToTheRight but works with vectors.
96 * @param lineStart
97 * @param lineVector
98 * @param point
99 * @return 1 if point is right to the vector starting at lineStart, 0 otherwise
100 */
101PRIVATE short
102isToTheRightPointVector(const double  lineStart[2],
103                        const double  lineVector[2],
104                        const double  point[2]);
105
106
107/**
108 * @brief angleBetweenVectors2D
109 *      - calculates the angle between both given vectors.
110 * @param vector1
111 *      - double array[2] with vector coordinates x,y
112 * @param vector2
113 *      - double array[2] with vector coordinates x,y
114 * @return
115 *      - angle between vector1 and vector2 in degree
116 */
117PRIVATE double
118angleBetweenVectors2D(const double  vector1[2],
119                      const double  vector2[2]);
120
121
122/**
123 * @brief anglePtPtPt2D
124 *      - calculates angle defined by three points.
125 * @param p2
126 *      - some point
127 * @param p2
128 *      - center point of that angle
129 * @param p3
130 *      - some point
131 * @return
132 *      - angle defined by points in degree
133 */
134PRIVATE double
135anglePtPtPt2D(const double  *p1,
136              const double  *p2,
137              const double  *p3);
138
139
140/**
141 * @brief normalizeAngle
142 *      - Does nothing if angle is inside [0,2*PI] or [0,360°]. Otherwise transforms the angle into this interval.
143 * @param angle
144 * @param useDegree
145 * @return angle in interval [0,2*PI] or [0,360°]
146 */
147PRIVATE double
148normalizeAngle(const double angle,
149               short        useDegree);
150
151
152/**
153 * @brief rotatePointAroundPoint
154 *      - Performs a rotation of a point around a rotation center by a given angle.
155 *        A positive angle results in a clockwise rotation while
156 *        a negative angle results in counterclockwise rotation.
157 *        Returns to rotated point.
158 * @param point
159 *      - double array[2] with point coordinates x,y
160 * @param rotationCenter
161 *      - double array[2] with point coordinates x,y
162 * @param angle
163 *      - angle in radiant format
164 * @param ret
165 *      - insert double array[2] here to act as return value
166 */
167PRIVATE void
168rotatePointAroundPoint(const double *point,
169                       const double *rotationCenter,
170                       const double angle,
171                       double       *ret);
172
173
174/**
175 * @brief rotateVectorByAngle
176 *      - Performs a rotation of a vector by a given angle.
177 *        A positive angle results in a clockwise rotation while
178 *        a negative angle results in counterclockwise rotation.
179 *        Returns to rotated vector.
180 * @param vector
181 *      - double array[2] with vector coordinates x,y
182 * @param angle
183 *      - angle in radiant format
184 * @param ret
185 *      - insert double array[2] here to act as return value
186 */
187PRIVATE void
188rotateVectorByAngle(const double  *vector,
189                    const double  angle,
190                    double        *ret);
191
192
193/**
194 * @brief translatePointByVector
195 *      - Performs a translation of a point by a given vector.
196 *        Returns to rotated vector.
197 * @param point
198 *      - double array[2] with point coordinates x,y
199 * @param trans
200 *      - translation vector as double array[2] with vector coordinates x,y
201 * @param ret
202 *      - insert double array[2] here to act as return value
203 */
204PRIVATE void
205translatePointByVector(const double *point,
206                       const double *trans,
207                       double       *ret);
208
209
210/**
211 * @brief solveSquareEquation
212 *      - Solves a square equation with ABC method. Writes results to solution1 and solution2
213 *        Input: a*x² + b*x + c = 0
214 *        Output: solution1, solution2 if they exist
215 * @param a
216 * @param b
217 * @param c
218 * @param sol1
219 *      - solution1 pointer
220 * @param sol2
221 *      - solution2 pointer
222 * @return
223 *      - count of solutions (0, 1 or 2)
224 */
225PRIVATE short
226solveSquareEquation(const double  a,
227                    const double  b,
228                    const double  c,
229                    double        *sol1,
230                    double        *sol2);
231
232
233/**
234 * @brief getCutPointsOfCircles
235 *      - Calculates the common points (cut points) of two circles given by their center
236 *        and radius. The resulting cut points are returned in variables ret1 and ret2 while
237 *        the methods return value states how many cut points exist.
238 * @param c1
239 *      - center of circle1. coordinates given as double array[2].
240 * @param r1
241 *      - radius of circle1.
242 * @param c2
243 *      - center of circle2. coordinates given as double array[2].
244 * @param r2
245 *      - radius of circle2.
246 * @param ret1
247 *      - insert double array[2] here. values are set if there is at least 1 cut point.
248 * @param ret2
249 *      - insert double array[2] here. values are set if there are 2 cut points.
250 * @return
251 *      - number of cut points: 0, 1 or 2. -1 if circles match (infinite cut points)
252 */
253PRIVATE short
254getCutPointsOfCircles(const double  *c1,
255                      const double  r1,
256                      const double  *c2,
257                      const double  r2,
258                      double        *ret1,
259                      double        *ret2);
260
261
262/**
263 * @brief getCutPointsOfCircleAndLine
264 *      - Calculates the common points (cut points) of a given circle and a given line.
265 *        The resulting cut points are returned in the variables ret1 and ret2 while
266 *        the function also returns the number of cut points.
267 * @param center
268 *      - center of the circle. coordinates given as double array[2].
269 * @param radius
270 *      - radius of the circle.
271 * @param anchor
272 *      - anchor point of the line. coordinates given as double array[2].
273 * @param direction
274 *      - direction vector of the line. coordinates given as double array[2].
275 * @param ret1
276 *      - insert double array[2] here. values are set if there is at least 1 cut point.
277 * @param ret2
278 *      - insert double array[2] here. values are set if there are 2 cut point.
279 * @return
280 *      - number of cut points: 0, 1 or 2.
281 */
282PRIVATE short
283getCutPointsOfCircleAndLine(const double  *center,
284                            const double  radius,
285                            const double  *anchor,
286                            const double  *direction,
287                            double        *ret1,
288                            double        *ret2);
289
290
291/**
292 * @brief vector
293 *      - creates a vector from pStart to pEnd.
294 * @param pStart
295 *      - double array[2] with coordinates of point
296 * @param pEnd
297 *      - double array[2] with coordinates of point
298 * @param v
299 *      - double array[2] used to return the vector
300 */
301PRIVATE void
302vector(const double pStart[2],
303       const double pEnd[2],
304       double       v[2]);
305
306
307/**
308 * @brief normal
309 *      - creates the normal vector to the given input vector.
310 *        The output normal vector has length 1.
311 * @param v
312 *      - double array[2] with vector coordinates
313 * @param n
314 *      - double array[2] used to return the normal vector
315 */
316PRIVATE void
317normal(const double v[2],
318       double       n[2]);
319
320
321PRIVATE void
322unit(const double v[2],
323     double       u[2]);
324
325
326/**
327 * @brief min
328 *      - the typical minimum function. calculates the minimum of two given numbers.
329 * @param number1
330 * @param number2
331 * @return
332 *      - the smaller number
333 */
334PRIVATE double
335min(const double  number1,
336    const double  number2);
337
338
339/**
340 * @brief sign
341 *      - calculates the sign of a given number.
342 * @param number
343 * @return
344 *      - the sign of the number
345 */
346PRIVATE double
347sign(const double number);
348
349
350PRIVATE void
351circle(const double A[2],
352       const double B[2],
353       const double C[2],
354       double       center[2],
355       double       *radius);
356
357
358PRIVATE double
359toDegree(double angle)
360{
361  return angle * TO_DEGREE;
362}
363
364
365PRIVATE double
366toRad(double angle)
367{
368  return angle * TO_RAD;
369}
370
371
372PRIVATE double
373vectorLength2D(const double vector[2])
374{
375  double  x = vector[0];
376  double  y = vector[1];
377
378  return sqrt(x * x + y * y);
379}
380
381
382PRIVATE double
383vectorLength2DSquared(const double vector[2])
384{
385  double  x = vector[0];
386  double  y = vector[1];
387
388  return x * x + y * y;
389}
390
391
392PRIVATE double
393scalarProduct2D(const double  *vector1,
394                const double  *vector2)
395{
396  double  x1            = vector1[0];
397  double  y1            = vector1[1];
398  double  x2            = vector2[0];
399  double  y2            = vector2[1];
400  double  scalarProduct = (x1 * x2 + y1 * y2);
401
402  return scalarProduct;
403}
404
405
406PRIVATE void
407normalize(double *vector)
408{
409  double length = vectorLength2D(vector);
410
411  vector[0] /= length;
412  vector[1] /= length;
413}
414
415
416PRIVATE short
417isToTheRightPointPoint(const double lineStart[2],
418                       const double lineEnd[2],
419                       const double point[2])
420{
421  /*
422   * implicite knowledge:
423   * a normal to a vector is always directed to the right
424   *
425   * idea:
426   * add the normal vector of the line to any point of the line  -> the resulting point is to the right of the line
427   * add the negative normal vector to the same point            -> the resulting point is to the left  of the line
428   * now get the distances of these points to the point of interest
429   * if that point is closer to the right point than to the left ->   that point itself is to the right of the line
430   */
431
432  double  vline[2] = {
433    lineEnd[0] - lineStart[0],
434    lineEnd[1] - lineStart[1]
435  };
436  double  normal[2] = {
437    vline[1], -vline[0]
438  };
439
440  double  right[2] = {
441    lineEnd[0] + normal[0],
442    lineEnd[1] + normal[1]
443  };
444  double  left[2] = {
445    lineEnd[0] - normal[0],
446    lineEnd[1] - normal[1]
447  };
448
449  double  vright[2] = {
450    point[0] - right[0], point[1] - right[1]
451  };
452  double  vleft[2] = {
453    point[0] - left[0], point[1] - left[1]
454  };
455
456  /*
457   * for comparing lengths of vectors there is no need to actually compute their length
458   * comparing their squares of their respective lengths grant the same results
459   * while saving some computation time (spare us the sqrt operation)
460   */
461  double  squaredDistanceRight  = scalarProduct2D(vright, vright);
462  double  squaredDistanceLeft   = scalarProduct2D(vleft, vleft);
463  short   ret                   = squaredDistanceRight < squaredDistanceLeft;
464
465  return ret;
466}
467
468
469PRIVATE short
470isToTheRightPointVector(const double  *lineStart,
471                        const double  *lineVector,
472                        const double  *point)
473{
474  double lineEnd[2] = {
475    lineStart[0] + lineVector[0], lineStart[1] + lineVector[1]
476  };
477
478  return isToTheRightPointPoint(lineStart, lineEnd, point);
479}
480
481
482PRIVATE double
483angleBetweenVectors2D(const double  vector1[2],
484                      const double  vector2[2])
485{
486  double  vectorNormalized1[2] = {
487    vector1[0], vector1[1]
488  };
489  double  vectorNormalized2[2] = {
490    vector2[0], vector2[1]
491  };
492
493  normalize(vectorNormalized1);
494  normalize(vectorNormalized2);
495  double  cosAngle  = scalarProduct2D(vectorNormalized1, vectorNormalized2);
496  double  angle     = 0.0;
497  if (fabs(cosAngle - -1.00) < EPSILON_7) {
498    /* cosAngle == -1 -> rad: PI deg: 180° */
499
500    angle = MATH_PI;
501  } else if (fabs(cosAngle - 1.00) < EPSILON_7) {
502    /* cosAngle == +1 -> rad: 0 deg: 0° */
503
504    angle = 0;
505  } else {
506    angle = acos(cosAngle);
507  }
508
509  return angle;
510}
511
512
513PRIVATE double
514anglePtPtPt2D(const double  *p1,
515              const double  *p2,
516              const double  *p3)
517{
518  double  v1[2] = {
519    p1[0] - p2[0], p1[1] - p2[1]
520  };
521  double  v2[2] = {
522    p3[0] - p2[0], p3[1] - p2[1]
523  };
524
525  return angleBetweenVectors2D(v1, v2);
526}
527
528
529PRIVATE double
530normalizeAngle(const double angle,
531               short        useDegree)
532{
533  double  min   = 0.0;
534  double  step  = useDegree ? 360.0 : MATH_TWO_PI;
535  double  max   = min + step;
536
537  int     viciousCircleCounter = 0;
538
539  double  ret = angle;
540
541  while (ret < min) {
542    ret += step;
543    viciousCircleCounter++;
544    if (viciousCircleCounter > 1000000)
545
546      break;
547  }
548
549  while (ret > max) {
550    ret -= step;
551    viciousCircleCounter++;
552    if (viciousCircleCounter > 1000000)
553
554      break;
555  }
556
557  return ret;
558}
559
560
561PRIVATE void
562rotatePointAroundPoint(const double *point,
563                       const double *rotationCenter,
564                       const double angle,
565                       double       *ret)
566{
567  double  x   = point[0];
568  double  y   = point[1];
569  double  x0  = rotationCenter[0];
570  double  y0  = rotationCenter[1];
571  double  phi = -angle;  /* negative value because we rotate clockwise for positive input */
572
573  ret[0]  = x0 + (x - x0) * cos(phi) - (y - y0) * sin(phi);
574  ret[1]  = y0 + (x - x0) * sin(phi) + (y - y0) * cos(phi);
575}
576
577
578PRIVATE void
579rotateVectorByAngle(const double  *vector,
580                    const double  angle,
581                    double        *ret)
582{
583  double c[2] = {
584    0, 0
585  };
586
587  rotatePointAroundPoint(vector, c, angle, ret);
588}
589
590
591PRIVATE void
592translatePointByVector(const double *point,
593                       const double *trans,
594                       double       *ret)
595{
596  ret[0]  = point[0] + trans[0];
597  ret[1]  = point[1] + trans[1];
598}
599
600
601PRIVATE short
602solveSquareEquation(const double  a,
603                    const double  b,
604                    const double  c,
605                    double        *sol1,
606                    double        *sol2)
607{
608  short   ret   = 0;
609  double  discr = b * b - 4 * a * c;
610
611  if (discr < 0.0) {
612    ret = 0;
613    return ret;
614  }
615
616  if (discr == 0.0)
617    ret = 1;
618  else
619    ret = 2;
620
621  double  answer1 = (-b + sqrt(discr)) / (2 * a);
622  double  answer2 = (-b - sqrt(discr)) / (2 * a);
623
624  *sol1 = answer1;
625  *sol2 = answer2;
626
627  return ret;
628}
629
630
631PRIVATE short
632getCutPointsOfCircles(const double  *c1,
633                      const double  r1,
634                      const double  *c2,
635                      const double  r2,
636                      double        *ret1,
637                      double        *ret2)
638{
639  short   answers = -2;
640  double  c1x     = c1[0];
641  double  c1y     = c1[1];
642  double  c2x     = c2[0];
643  double  c2y     = c2[1];
644
645  double  dx = c1x - c2x;
646
647  dx = dx < 0 ? -dx : dx;
648  double  dy = c1y - c2y;
649  dy = dy < 0 ? -dy : dy;
650  double  dr = r1 - r2;
651  dr = dr < 0 ? -dr : dr;
652
653  double  eps = 1.0;
654  /*
655   * if any delta is smaller than this epsilon this delta will be considered zero
656   * i.e. the values that are being compared are treated as equal
657   */
658
659  short smallDX = dx < eps;
660  short smallDY = dy < eps;
661  short smallDR = dr < eps;
662
663  if (smallDX && smallDY) {
664    if (smallDR)
665      /* circles coincide */
666      answers = -1;
667    else
668      /* circles are concentric but with different radius */
669      answers = 0;
670  } else
671
672  if (!smallDY) {
673    /*
674     * (smallDX || !smallDX) && !smallDY
675     * EQ1: circle1: (r1)² = (c1x - x)² + (c1y - y)²
676     * EQ2: circle2: (r2)² = (c2x - x)² + (c2y - y)²
677     */
678
679    /*
680     * EQ3: EQ1 - EQ2, get y
681     * EQ3: y = (x * k + l) / m = (k / m) * x + (l / m)
682     */
683    double  k = -2 * c1x + 2 * c2x;
684    double  l = c1x * c1x - c2x * c2x + c1y * c1y - c2y * c2y - r1 * r1 + r2 * r2;
685    double  m = (-1) * (-2 * c1y + 2 * c2y);
686
687    /*
688     * EQ4: replace y in EQ1 with EQ3
689     * transform equation into ax²+bx+c=0 shape
690     */
691    double  p = c1y - (l / m);
692    double  q = k / m;
693    double  a = q * q + 1;
694    double  b = -2 * c1x - 2 * p * q;
695    double  c = c1x * c1x + p * p - r1 * r1;
696
697    double  sol1;
698    double  sol2;
699    answers = solveSquareEquation(a, b, c, &sol1, &sol2);
700
701    if (answers > 0) {
702      ret1[0] = sol1;
703      ret1[1] = (sol1 * k + l) / m;
704    }
705
706    if (answers > 1) {
707      ret2[0] = sol2;
708      ret2[1] = (sol2 * k + l) / m;
709    }
710  } else {
711    /* smallDY && !smallDX */
712
713    double  k = -2 * c1y + 2 * c2y;
714    double  l = (c1x * c1x - c2x * c2x) + (c1y * c1y - c2y * c2y) + (r2 * r2 - r1 * r1);
715    double  m = (-1) * (-2 * c1x + 2 * c2x);
716
717    double  p = c1x - (l / m);
718    double  q = k / m;
719    double  a = q * q + 1;
720    double  b = -2 * c1y - 2 * p * q;
721    double  c = c1y * c1y + p * p - r1 * r1;
722
723    double  sol1;
724    double  sol2;
725
726    answers = solveSquareEquation(a, b, c, &sol1, &sol2);
727
728    if (answers == 0)
729      printf("no solution 2: %3.2lf %3.2lf %3.2lf\n", a, b, c);
730
731    if (answers > 0) {
732      ret1[1] = sol1;
733      ret1[0] = (sol1 * k + l) / m;
734    }
735
736    if (answers > 1) {
737      ret2[1] = sol2;
738      ret2[0] = (sol2 * k + l) / m;
739    }
740  }
741
742  return answers;
743}
744
745
746PRIVATE short
747getCutPointsOfCircleAndLine(const double  *center,
748                            const double  radius,
749                            const double  *anchor,
750                            const double  *direction,
751                            double        *ret1,
752                            double        *ret2)
753{
754  double  a = direction[0] * direction[0] + direction[1] * direction[1];
755  double  b = 2 * direction[0] * (anchor[0] - center[0]) + 2 * direction[1] *
756              (anchor[1] - center[1]);
757  double  c = (anchor[0] - center[0]) * (anchor[0] - center[0]) + (anchor[1] - center[1]) *
758              (anchor[1] - center[1]) - radius * radius;
759
760  double  solution1, solution2;
761  short   answers = solveSquareEquation(a, b, c, &solution1, &solution2);
762
763  if (answers > 0) {
764    ret1[0] = anchor[0] + solution1 * direction[0];
765    ret1[1] = anchor[1] + solution1 * direction[1];
766  }
767
768  if (answers > 1) {
769    ret2[0] = anchor[0] + solution2 * direction[0];
770    ret2[1] = anchor[1] + solution2 * direction[1];
771  }
772
773  return answers;
774}
775
776
777PRIVATE void
778vector(const double pStart[2],
779       const double pEnd[2],
780       double       v[2])
781{
782  v[0]  = pEnd[0] - pStart[0];
783  v[1]  = pEnd[1] - pStart[1];
784}
785
786
787PRIVATE void
788normal(const double v[2],
789       double       n[2])
790{
791  double  vNormal[2];
792
793  vNormal[0]  = v[1];
794  vNormal[1]  = -v[0];
795
796  double  vNormalUnit[2];
797  unit(vNormal, vNormalUnit);
798
799  n[0]  = vNormalUnit[0];
800  n[1]  = vNormalUnit[1];
801}
802
803
804PRIVATE void
805unit(const double v[2],
806     double       u[2])
807{
808  double length = vectorLength2D(v);
809
810  u[0]  = v[0] / length;
811  u[1]  = v[1] / length;
812}
813
814
815PRIVATE double
816min(const double  number1,
817    const double  number2)
818{
819  if (number1 < number2)
820    return number1;
821  else
822    return number2;
823}
824
825
826PRIVATE double
827sign(const double number)
828{
829  if (number > 0.0)
830    return 1.0;
831  else if (number < 0.0)
832    return -1.0;
833  else
834    return 0.0;
835}
836
837
838PRIVATE void
839circle(const double P1[2],
840       const double P2[2],
841       const double P3[2],
842       double       center[2],
843       double       *radius)
844{
845  /* initialize coefficients of the system of equations */
846  double alpha[3];
847
848  alpha[0]  = 1;
849  alpha[1]  = 1;
850  alpha[2]  = 1;
851
852  double  beta[3];
853  beta[0] = -P1[0];
854  beta[1] = -P2[0];
855  beta[2] = -P3[0];
856
857  double  gamma[3];
858  gamma[0]  = -P1[1];
859  gamma[1]  = -P2[1];
860  gamma[2]  = -P3[1];
861
862  double  r[3];
863  r[0]  = -(P1[0] * P1[0] + P1[1] * P1[1]);
864  r[1]  = -(P2[0] * P2[0] + P2[1] * P2[1]);
865  r[2]  = -(P3[0] * P3[0] + P3[1] * P3[1]);
866
867  /* eliminate alpha 1 und 2 */
868  beta[1]   -= beta[0];
869  gamma[1]  -= gamma[0];
870  beta[2]   -= beta[0];
871  gamma[2]  -= gamma[0];
872  r[1]      -= r[0];
873  r[2]      -= r[0];
874
875  double  A;
876  double  B;
877  double  C;
878
879  /* solve linear equations */
880  if ((fabs(beta[1]) < EPSILON_7)
881      && (fabs(gamma[1]) > EPSILON_7)) {
882    C = r[1] / gamma[1];
883    B = (r[2] - gamma[2] * C) / beta[2];
884    /* printf("beta[1] == %15.12lf\n",beta [1]); */
885  } else if ((fabs(beta[2]) < EPSILON_7)
886             && (fabs(gamma[2]) > EPSILON_7)) {
887    C = r[2] / gamma[2];
888    B = (r[1] - gamma[1] * C) / beta[1];
889    /* printf("beta[2] == %15.12lf\n", beta[2]); */
890  } else {
891    if (fabs(gamma[1]) < EPSILON_7) {
892      B = r[1] / beta[1];
893      C = (r[2] - beta[2] * B) / gamma[2];
894      /* printf("gamma[1] == %15.12lf\n", gamma[1]); */
895    } else if (fabs(gamma[2]) < EPSILON_7) {
896      B = r[2] / beta[2];
897      C = (r[1] - beta[1] * B) / gamma[1];
898      /* printf("gamma[2] == %15.12lf\n", gamma[2]); */
899    } else {
900      /*
901       * printf("  GL1: %15.12lf * B + %15.12lf * C = %15.12lf\n", beta[1],
902       * gamma[1], r[1]);
903       * printf("  GL2: %15.12lf * B + %15.12lf * C = %15.12lf\n", beta[2],
904       * gamma[2], r[2]);
905       */
906
907      gamma[2]  = gamma[2] * beta[1] - gamma[1] * beta[2];
908      r[2]      = r[2] * beta[1] - r[1] * beta[2];
909
910      /* printf("  GL C: %15.12lf * C = %15.12lf\n", gamma[2], r[2]); */
911      C = r[2] / gamma[2];
912      B = (r[1] - gamma[1] * C) / beta[1];
913    }
914  }
915
916  A = r[0] - beta[0] * B - gamma[0] * C;
917
918  /* calculate center and radius */
919  center[0] = B / 2;
920  center[1] = C / 2;
921  *radius   = sqrt(center[0] * center[0] + center[1] * center[1] - A);
922}
923
924
925#endif
926