blob: 7d86f7f5924342d1641fd99385731c60b71d547f [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.comc6825902012-02-03 22:07:47 +00007#include "CurveIntersection.h"
caryclark@google.com639df892012-01-10 21:46:10 +00008#include "QuadraticUtilities.h"
9
10/* from http://tom.cs.byu.edu/~tom/papers/cvgip84.pdf 4.1
11 *
rmistry@google.comd6176b02012-08-23 18:14:13 +000012 * This paper proves that Syvester's method can compute the implicit form of
caryclark@google.comc6825902012-02-03 22:07:47 +000013 * the quadratic from the parameterized form.
caryclark@google.com639df892012-01-10 21:46:10 +000014 *
15 * Given x = a*t*t + b*t + c (the parameterized form)
16 * y = d*t*t + e*t + f
17 *
18 * we want to find an equation of the implicit form:
19 *
20 * A*x*x + B*x*y + C*y*y + D*x + E*y + F = 0
21 *
22 * The implicit form can be expressed as a 4x4 determinant, as shown.
23 *
24 * The resultant obtained by Syvester's method is
25 *
26 * | a b (c - x) 0 |
27 * | 0 a b (c - x) |
28 * | d e (f - y) 0 |
29 * | 0 d e (f - y) |
30 *
31 * which expands to
32 *
33 * d*d*x*x + -2*a*d*x*y + a*a*y*y
34 * + (-2*c*d*d + b*e*d - a*e*e + 2*a*f*d)*x
35 * + (-2*f*a*a + e*b*a - d*b*b + 2*d*c*a)*y
36 * +
37 * | a b c 0 |
38 * | 0 a b c | == 0.
39 * | d e f 0 |
40 * | 0 d e f |
41 *
42 * Expanding the constant determinant results in
43 *
44 * | a b c | | b c 0 |
45 * a*| e f 0 | + d*| a b c | ==
46 * | d e f | | d e f |
47 *
48 * a*(a*f*f + c*e*e - c*f*d - b*e*f) + d*(b*b*f + c*c*d - c*a*f - c*e*b)
49 *
50 */
51
52enum {
53 xx_coeff,
54 xy_coeff,
55 yy_coeff,
56 x_coeff,
57 y_coeff,
58 c_coeff,
59 coeff_count
60};
61
62static bool straight_forward = true;
63
64static void implicit_coefficients(const Quadratic& q, double p[coeff_count]) {
65 double a, b, c;
66 set_abc(&q[0].x, a, b, c);
67 double d, e, f;
68 set_abc(&q[0].y, d, e, f);
69 // compute the implicit coefficients
70 if (straight_forward) { // 42 muls, 13 adds
71 p[xx_coeff] = d * d;
72 p[xy_coeff] = -2 * a * d;
73 p[yy_coeff] = a * a;
74 p[x_coeff] = -2*c*d*d + b*e*d - a*e*e + 2*a*f*d;
75 p[y_coeff] = -2*f*a*a + e*b*a - d*b*b + 2*d*c*a;
76 p[c_coeff] = a*(a*f*f + c*e*e - c*f*d - b*e*f)
77 + d*(b*b*f + c*c*d - c*a*f - c*e*b);
78 } else { // 26 muls, 11 adds
79 double aa = a * a;
80 double ad = a * d;
81 double dd = d * d;
82 p[xx_coeff] = dd;
83 p[xy_coeff] = -2 * ad;
84 p[yy_coeff] = aa;
85 double be = b * e;
86 double bde = be * d;
87 double cdd = c * dd;
88 double ee = e * e;
89 p[x_coeff] = -2*cdd + bde - a*ee + 2*ad*f;
90 double aaf = aa * f;
91 double abe = a * be;
92 double ac = a * c;
93 double bb_2ac = b*b - 2*ac;
94 p[y_coeff] = -2*aaf + abe - d*bb_2ac;
95 p[c_coeff] = aaf*f + ac*ee + d*f*bb_2ac - abe*f + c*cdd - c*bde;
96 }
97}
98
99 /* Given a pair of quadratics, determine their parametric coefficients.
100 * If the scaled coefficients are nearly equal, then the part of the quadratics
101 * may be coincident.
102 * FIXME: optimization -- since comparison short-circuits on no match,
103 * lazily compute the coefficients, comparing the easiest to compute first.
104 * xx and yy first; then xy; and so on.
105 */
106bool implicit_matches(const Quadratic& one, const Quadratic& two) {
107 double p1[coeff_count]; // a'xx , b'xy , c'yy , d'x , e'y , f
108 double p2[coeff_count];
109 implicit_coefficients(one, p1);
110 implicit_coefficients(two, p2);
111 int first = 0;
112 for (int index = 0; index < coeff_count; ++index) {
113 if (approximately_zero(p1[index]) || approximately_zero(p2[index])) {
114 first += first == index;
115 continue;
116 }
117 if (first == index) {
118 continue;
119 }
120 if (!approximately_equal(p1[index] * p2[first],
121 p1[first] * p2[index])) {
122 return false;
123 }
124 }
125 return true;
126}
127
128static double tangent(const double* quadratic, double t) {
129 double a, b, c;
130 set_abc(quadratic, a, b, c);
131 return 2 * a * t + b;
132}
133
134void tangent(const Quadratic& quadratic, double t, _Point& result) {
135 result.x = tangent(&quadratic[0].x, t);
136 result.y = tangent(&quadratic[0].y, t);
137}
138
caryclark@google.com27accef2012-01-25 18:57:23 +0000139// unit test to return and validate parametric coefficients
140#include "QuadraticParameterization_TestUtility.cpp"