blob: 95be90a460c4ffa35474301ae305fb263dc8ea4e [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;
caryclark@google.com235f56a2012-09-14 14:19:30 +000031 if (approximately_negative(square)) {
32 if (!approximately_positive(square)) {
33 return 0;
34 }
35 square = 0;
caryclark@google.com27accef2012-01-25 18:57:23 +000036 }
37 double squareRt = sqrt(square);
38 double Q = (B + (B < 0 ? -squareRt : squareRt)) / -2;
39 int foundRoots = 0;
caryclark@google.com03f97062012-08-21 13:13:52 +000040 double ratio = Q / A;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000041 if (approximately_zero_or_more(ratio) && approximately_one_or_less(ratio)) {
42 if (approximately_less_than_zero(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +000043 ratio = 0;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000044 } else if (approximately_greater_than_one(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +000045 ratio = 1;
caryclark@google.com78e17132012-04-17 11:40:34 +000046 }
caryclark@google.coma7e483d2012-08-28 20:44:43 +000047 t[0] = ratio;
48 ++foundRoots;
caryclark@google.com27accef2012-01-25 18:57:23 +000049 }
caryclark@google.com03f97062012-08-21 13:13:52 +000050 ratio = C / Q;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000051 if (approximately_zero_or_more(ratio) && approximately_one_or_less(ratio)) {
52 if (approximately_less_than_zero(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +000053 ratio = 0;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000054 } else if (approximately_greater_than_one(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +000055 ratio = 1;
caryclark@google.com78e17132012-04-17 11:40:34 +000056 }
caryclark@google.coma7e483d2012-08-28 20:44:43 +000057 if (foundRoots == 0 || !approximately_negative(ratio - t[0])) {
caryclark@google.comc899ad92012-08-23 15:24:42 +000058 t[foundRoots++] = ratio;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000059 } else if (!approximately_negative(t[0] - ratio)) {
60 t[foundRoots++] = t[0];
61 t[0] = ratio;
caryclark@google.comc899ad92012-08-23 15:24:42 +000062 }
caryclark@google.com27accef2012-01-25 18:57:23 +000063 }
64 return foundRoots;
65}
caryclark@google.com8dcf1142012-07-02 20:27:02 +000066
67void dxdy_at_t(const Quadratic& quad, double t, double& x, double& y) {
68 double a = t - 1;
69 double b = 1 - 2 * t;
70 double c = t;
71 if (&x) {
72 x = a * quad[0].x + b * quad[1].x + c * quad[2].x;
73 }
74 if (&y) {
75 y = a * quad[0].y + b * quad[1].y + c * quad[2].y;
76 }
77}
78
79void xy_at_t(const Quadratic& quad, double t, double& x, double& y) {
80 double one_t = 1 - t;
81 double a = one_t * one_t;
82 double b = 2 * one_t * t;
83 double c = t * t;
84 if (&x) {
85 x = a * quad[0].x + b * quad[1].x + c * quad[2].x;
86 }
87 if (&y) {
88 y = a * quad[0].y + b * quad[1].y + c * quad[2].y;
89 }
90}