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