blob: 8971fca92b6ce60e46085801a40e5ef962fc4ef2 [file] [log] [blame]
caryclark@google.com9e49fb62012-08-27 14:11:33 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
caryclark@google.com27accef2012-01-25 18:57:23 +00007#include "QuadraticUtilities.h"
caryclark@google.comd88e0892012-03-27 13:23:51 +00008#include <math.h>
caryclark@google.com27accef2012-01-25 18:57:23 +00009
caryclark@google.com03f97062012-08-21 13:13:52 +000010/*
11
12Numeric Solutions (5.6) suggests to solve the quadratic by computing
13
14 Q = -1/2(B + sgn(B)Sqrt(B^2 - 4 A C))
15
16and using the roots
17
18 t1 = Q / A
19 t2 = C / Q
rmistry@google.comd6176b02012-08-23 18:14:13 +000020
caryclark@google.com03f97062012-08-21 13:13:52 +000021*/
22
caryclark@google.coma7e483d2012-08-28 20:44:43 +000023// note: caller expects multiple results to be sorted smaller first
24// note: http://en.wikipedia.org/wiki/Loss_of_significance has an interesting
25// analysis of the quadratic equation, suggesting why the following looks at
26// the sign of B -- and further suggesting that the greatest loss of precision
27// is in b squared less two a c
caryclark@google.com27accef2012-01-25 18:57:23 +000028int quadraticRoots(double A, double B, double C, double t[2]) {
29 B *= 2;
30 double square = B * B - 4 * A * C;
31 if (square < 0) {
32 return 0;
33 }
34 double squareRt = sqrt(square);
35 double Q = (B + (B < 0 ? -squareRt : squareRt)) / -2;
36 int foundRoots = 0;
caryclark@google.com03f97062012-08-21 13:13:52 +000037 double ratio = Q / A;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000038 if (approximately_zero_or_more(ratio) && approximately_one_or_less(ratio)) {
39 if (approximately_less_than_zero(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +000040 ratio = 0;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000041 } else if (approximately_greater_than_one(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +000042 ratio = 1;
caryclark@google.com78e17132012-04-17 11:40:34 +000043 }
caryclark@google.coma7e483d2012-08-28 20:44:43 +000044 t[0] = ratio;
45 ++foundRoots;
caryclark@google.com27accef2012-01-25 18:57:23 +000046 }
caryclark@google.com03f97062012-08-21 13:13:52 +000047 ratio = C / Q;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000048 if (approximately_zero_or_more(ratio) && approximately_one_or_less(ratio)) {
49 if (approximately_less_than_zero(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +000050 ratio = 0;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000051 } else if (approximately_greater_than_one(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +000052 ratio = 1;
caryclark@google.com78e17132012-04-17 11:40:34 +000053 }
caryclark@google.coma7e483d2012-08-28 20:44:43 +000054 if (foundRoots == 0 || !approximately_negative(ratio - t[0])) {
caryclark@google.comc899ad92012-08-23 15:24:42 +000055 t[foundRoots++] = ratio;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000056 } else if (!approximately_negative(t[0] - ratio)) {
57 t[foundRoots++] = t[0];
58 t[0] = ratio;
caryclark@google.comc899ad92012-08-23 15:24:42 +000059 }
caryclark@google.com27accef2012-01-25 18:57:23 +000060 }
61 return foundRoots;
62}
caryclark@google.com8dcf1142012-07-02 20:27:02 +000063
64void dxdy_at_t(const Quadratic& quad, double t, double& x, double& y) {
65 double a = t - 1;
66 double b = 1 - 2 * t;
67 double c = t;
68 if (&x) {
69 x = a * quad[0].x + b * quad[1].x + c * quad[2].x;
70 }
71 if (&y) {
72 y = a * quad[0].y + b * quad[1].y + c * quad[2].y;
73 }
74}
75
76void xy_at_t(const Quadratic& quad, double t, double& x, double& y) {
77 double one_t = 1 - t;
78 double a = one_t * one_t;
79 double b = 2 * one_t * t;
80 double c = t * t;
81 if (&x) {
82 x = a * quad[0].x + b * quad[1].x + c * quad[2].x;
83 }
84 if (&y) {
85 y = a * quad[0].y + b * quad[1].y + c * quad[2].y;
86 }
87}