GCC Code Coverage Report


Directory: ./
File: src/2geom/bezier.cpp
Date: 2024-03-18 17:01:34
Exec Total Coverage
Lines: 177 211 83.9%
Functions: 22 23 95.7%
Branches: 143 262 54.6%

Line Branch Exec Source
1 /**
2 * @file
3 * @brief Bernstein-Bezier polynomial
4 *//*
5 * Authors:
6 * MenTaLguY <mental@rydia.net>
7 * Michael Sloan <mgsloan@gmail.com>
8 * Nathan Hurst <njh@njhurst.com>
9 * Krzysztof Kosiński <tweenk.pl@gmail.com>
10 *
11 * Copyright 2007-2015 Authors
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it either under the terms of the GNU Lesser General Public
15 * License version 2.1 as published by the Free Software Foundation
16 * (the "LGPL") or, at your option, under the terms of the Mozilla
17 * Public License Version 1.1 (the "MPL"). If you do not alter this
18 * notice, a recipient may use your version of this file under either
19 * the MPL or the LGPL.
20 *
21 * You should have received a copy of the LGPL along with this library
22 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * You should have received a copy of the MPL along with this library
25 * in the file COPYING-MPL-1.1
26 *
27 * The contents of this file are subject to the Mozilla Public License
28 * Version 1.1 (the "License"); you may not use this file except in
29 * compliance with the License. You may obtain a copy of the License at
30 * http://www.mozilla.org/MPL/
31 *
32 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
33 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
34 * the specific language governing rights and limitations.
35 *
36 */
37
38 #include <2geom/bezier.h>
39 #include <2geom/solver.h>
40 #include <2geom/concepts.h>
41 #include <2geom/choose.h>
42
43 // Workaround for GCC null-analyser false positives.
44 // See https://gitlab.com/inkscape/lib2geom/-/issues/64
45 #if defined(__GNUC__) && !defined(__clang__)
46 #pragma GCC diagnostic ignored "-Wnonnull"
47 #endif
48
49 namespace Geom {
50
51 279 std::vector<Coord> Bezier::valueAndDerivatives(Coord t, unsigned n_derivs) const {
52 /* This is inelegant, as it uses several extra stores. I think there might be a way to
53 * evaluate roughly in situ. */
54
55 // initialize return vector with zeroes, such that we only need to replace the non-zero derivs
56
1/2
✓ Branch 3 taken 279 times.
✗ Branch 4 not taken.
837 std::vector<Coord> val_n_der(n_derivs + 1, Coord(0.0));
57
58 // initialize temp storage variables
59
2/4
✓ Branch 2 taken 279 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 279 times.
✗ Branch 6 not taken.
279 std::valarray<Coord> d_(order()+1);
60
3/4
✓ Branch 1 taken 901 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 622 times.
✓ Branch 4 taken 279 times.
901 for(unsigned i = 0; i < size(); i++) {
61 622 d_[i] = c_[i];
62 }
63
64 279 unsigned nn = n_derivs + 1;
65
3/4
✓ Branch 1 taken 279 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 263 times.
✓ Branch 4 taken 16 times.
279 if(n_derivs > order()) {
66
1/2
✓ Branch 1 taken 263 times.
✗ Branch 2 not taken.
263 nn = order()+1; // only calculate the non zero derivs
67 }
68
2/2
✓ Branch 0 taken 622 times.
✓ Branch 1 taken 279 times.
901 for(unsigned di = 0; di < nn; di++) {
69 //val_n_der[di] = (casteljau_subdivision(t, &d_[0], NULL, NULL, order() - di));
70
1/2
✓ Branch 1 taken 622 times.
✗ Branch 2 not taken.
622 val_n_der[di] = bernstein_value_at(t, &d_[0], order() - di);
71
3/4
✓ Branch 1 taken 1046 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 424 times.
✓ Branch 4 taken 622 times.
1046 for(unsigned i = 0; i < order() - di; i++) {
72
1/2
✓ Branch 1 taken 424 times.
✗ Branch 2 not taken.
424 d_[i] = (order()-di)*(d_[i+1] - d_[i]);
73 }
74 }
75
76 558 return val_n_der;
77 279 }
78
79 62190 void Bezier::subdivide(Coord t, Bezier *left, Bezier *right) const
80 {
81
1/2
✓ Branch 0 taken 62190 times.
✗ Branch 1 not taken.
62190 if (left) {
82 62190 left->c_.resize(size());
83
1/2
✓ Branch 0 taken 62190 times.
✗ Branch 1 not taken.
62190 if (right) {
84 62190 right->c_.resize(size());
85 124380 casteljau_subdivision<double>(t, &c_[0],
86 62190 &left->c_[0], &right->c_[0], order());
87 } else {
88 casteljau_subdivision<double>(t, &c_[0],
89 &left->c_[0], nullptr, order());
90 }
91 } else if (right) {
92 right->c_.resize(size());
93 casteljau_subdivision<double>(t, &c_[0],
94 nullptr, &right->c_[0], order());
95 }
96 62190 }
97
98 62190 std::pair<Bezier, Bezier> Bezier::subdivide(Coord t) const
99 {
100 62190 std::pair<Bezier, Bezier> ret;
101
1/2
✓ Branch 1 taken 62190 times.
✗ Branch 2 not taken.
62190 subdivide(t, &ret.first, &ret.second);
102 62190 return ret;
103 }
104
105 67906 std::vector<Coord> Bezier::roots() const
106 {
107 67906 std::vector<Coord> solutions;
108
1/2
✓ Branch 1 taken 67906 times.
✗ Branch 2 not taken.
67906 find_bezier_roots(solutions, 0, 1);
109
1/2
✓ Branch 3 taken 67906 times.
✗ Branch 4 not taken.
67906 std::sort(solutions.begin(), solutions.end());
110 67906 return solutions;
111 }
112
113 22188 std::vector<Coord> Bezier::roots(Interval const &ivl) const
114 {
115 22188 std::vector<Coord> solutions;
116
2/4
✓ Branch 3 taken 22188 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 22188 times.
✗ Branch 8 not taken.
22188 find_bernstein_roots(&c_[0], order(), solutions, 0, ivl.min(), ivl.max());
117
1/2
✓ Branch 3 taken 22188 times.
✗ Branch 4 not taken.
22188 std::sort(solutions.begin(), solutions.end());
118 22188 return solutions;
119 }
120
121 2 Bezier Bezier::forward_difference(unsigned k) const
122 {
123
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 Bezier fd(Order(order() - k));
124
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 int n = fd.size();
125
126
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 for (int i = 0; i < n; i++) {
127 7 fd[i] = 0;
128
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
7 int b = (i & 1) ? -1 : 1; // b = (-1)^j binomial(n, j - i)
129
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 7 times.
23 for (int j = i; j < n; j++) {
130 16 fd[i] += c_[j] * b;
131 16 binomial_increment_k(b, n, j - i);
132 16 b = -b;
133 }
134 }
135 2 return fd;
136 }
137
138 88 Bezier Bezier::elevate_degree() const
139 {
140
2/4
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 88 times.
✗ Branch 7 not taken.
88 Bezier ed(Order(order()+1));
141
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 unsigned n = size();
142 88 ed[0] = c_[0];
143 88 ed[n] = c_[n-1];
144
2/2
✓ Branch 0 taken 536 times.
✓ Branch 1 taken 88 times.
624 for(unsigned i = 1; i < n; i++) {
145 536 ed[i] = (i*c_[i-1] + (n - i)*c_[i])/(n);
146 }
147 88 return ed;
148 }
149
150 Bezier Bezier::reduce_degree() const
151 {
152 if(order() == 0) return *this;
153 Bezier ed(Order(order()-1));
154 unsigned n = size();
155 ed[0] = c_[0];
156 ed[n-1] = c_[n]; // ensure exact endpoints
157 unsigned middle = n/2;
158 for(unsigned i = 1; i < middle; i++) {
159 ed[i] = (n*c_[i] - i*ed[i-1])/(n-i);
160 }
161 for(unsigned i = n-1; i >= middle; i--) {
162 ed[i] = (n*c_[i] - i*ed[n-i])/(i);
163 }
164 return ed;
165 }
166
167 22 Bezier Bezier::elevate_to_degree(unsigned newDegree) const
168 {
169 22 Bezier ed = *this;
170
3/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 87 times.
✓ Branch 4 taken 22 times.
109 for(unsigned i = degree(); i < newDegree; i++) {
171
2/4
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 87 times.
✗ Branch 6 not taken.
87 ed = ed.elevate_degree();
172 }
173 22 return ed;
174 }
175
176 40334 Bezier Bezier::deflate() const
177 {
178
2/6
✓ Branch 1 taken 40334 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 40334 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
40334 if(order() == 0) return *this;
179
1/2
✓ Branch 1 taken 40334 times.
✗ Branch 2 not taken.
40334 unsigned n = order();
180
1/2
✓ Branch 4 taken 40334 times.
✗ Branch 5 not taken.
40334 Bezier b(Order(n-1));
181
2/2
✓ Branch 0 taken 327734 times.
✓ Branch 1 taken 40334 times.
368068 for(unsigned i = 0; i < n; i++) {
182 327734 b[i] = (n*c_[i+1])/(i+1);
183 }
184
1/2
✓ Branch 1 taken 40334 times.
✗ Branch 2 not taken.
40334 return b;
185 40334 }
186
187 558 SBasis Bezier::toSBasis() const
188 {
189 558 SBasis sb;
190
1/2
✓ Branch 1 taken 558 times.
✗ Branch 2 not taken.
558 bezier_to_sbasis(sb, *this);
191 558 return sb;
192 //return bezier_to_sbasis(&c_[0], order());
193 }
194
195 40096 Bezier &Bezier::operator+=(Bezier const &other)
196 {
197
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 40088 times.
40096 if (c_.size() > other.size()) {
198
3/6
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
8 c_ += other.elevate_to_degree(degree()).c_;
199
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 40088 times.
40088 } else if (c_.size() < other.size()) {
200 *this = elevate_to_degree(other.degree());
201 c_ += other.c_;
202 } else {
203 40088 c_ += other.c_;
204 }
205 40096 return *this;
206 }
207
208 18 Bezier &Bezier::operator-=(Bezier const &other)
209 {
210
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
18 if (c_.size() > other.size()) {
211 c_ -= other.elevate_to_degree(degree()).c_;
212
2/2
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 9 times.
18 } else if (c_.size() < other.size()) {
213
3/6
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
9 *this = elevate_to_degree(other.degree());
214 9 c_ -= other.c_;
215 } else {
216 9 c_ -= other.c_;
217 }
218 18 return *this;
219 }
220
221 160 Bezier operator*(Bezier const &f, Bezier const &g)
222 {
223
1/2
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
160 int m = f.order();
224
1/2
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
160 int n = g.order();
225
1/2
✓ Branch 3 taken 160 times.
✗ Branch 4 not taken.
160 Bezier h(Bezier::Order(m+n));
226 // h_k = sum_(i+j=k) (m i)f_i (n j)g_j / (m+n k)
227
228 160 int mci = 1;
229
2/2
✓ Branch 0 taken 563 times.
✓ Branch 1 taken 160 times.
723 for (int i = 0; i <= m; i++) {
230 563 double const fi = mci * f[i];
231
232 563 int ncj = 1;
233
2/2
✓ Branch 0 taken 1827 times.
✓ Branch 1 taken 563 times.
2390 for (int j = 0; j <= n; j++) {
234 1827 h[i + j] += fi * ncj * g[j];
235 1827 binomial_increment_k(ncj, n, j);
236 }
237
238 563 binomial_increment_k(mci, m, i);
239 }
240
241 160 int mnck = 1;
242
2/2
✓ Branch 0 taken 873 times.
✓ Branch 1 taken 160 times.
1033 for (int k = 0; k <= m + n; k++) {
243 873 h[k] /= mnck;
244 873 binomial_increment_k(mnck, m + n, k);
245 }
246
247 320 return h;
248 }
249
250 40173 Bezier portion(Bezier const &a, double from, double to)
251 {
252 40173 Bezier ret(a);
253
254 40173 bool reverse_result = false;
255
2/2
✓ Branch 0 taken 20312 times.
✓ Branch 1 taken 19861 times.
40173 if (from > to) {
256 20312 std::swap(from, to);
257 20312 reverse_result = true;
258 }
259
260 do {
261
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 40067 times.
40173 if (from == 0) {
262
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 52 times.
106 if (to == 1) {
263 54 break;
264 }
265
2/4
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 52 times.
✗ Branch 7 not taken.
52 casteljau_subdivision<double>(to, &ret.c_[0], &ret.c_[0], nullptr, ret.order());
266 52 break;
267 }
268
2/4
✓ Branch 1 taken 40067 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 40067 times.
✗ Branch 7 not taken.
40067 casteljau_subdivision<double>(from, &ret.c_[0], NULL, &ret.c_[0], ret.order());
269
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 40023 times.
40067 if (to == 1) break;
270
2/4
✓ Branch 1 taken 40023 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 40023 times.
✗ Branch 7 not taken.
40023 casteljau_subdivision<double>((to - from) / (1 - from), &ret.c_[0], &ret.c_[0], NULL, ret.order());
271 // to protect against numerical inaccuracy in the above expression, we manually set
272 // the last coefficient to a value evaluated directly from the original polynomial
273
2/4
✓ Branch 1 taken 40023 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 40023 times.
✗ Branch 5 not taken.
40023 ret.c_[ret.order()] = a.valueAt(to);
274 } while(0);
275
276
2/2
✓ Branch 0 taken 20312 times.
✓ Branch 1 taken 19861 times.
40173 if (reverse_result) {
277
1/2
✓ Branch 4 taken 20312 times.
✗ Branch 5 not taken.
20312 std::reverse(&ret.c_[0], &ret.c_[0] + ret.c_.size());
278 }
279 40173 return ret;
280 }
281
282 22640 Bezier derivative(Bezier const &a)
283 {
284 //if(a.order() == 1) return Bezier(0.0);
285
4/6
✓ Branch 1 taken 22640 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 115 times.
✓ Branch 4 taken 22525 times.
✓ Branch 8 taken 115 times.
✗ Branch 9 not taken.
22640 if(a.order() == 1) return Bezier(a.c_[1]-a.c_[0]);
286
2/4
✓ Branch 3 taken 22525 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 22525 times.
✗ Branch 8 not taken.
22525 Bezier der(Bezier::Order(a.order()-1));
287
288
3/4
✓ Branch 1 taken 198266 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 175741 times.
✓ Branch 4 taken 22525 times.
198266 for(unsigned i = 0; i < a.order(); i++) {
289
1/2
✓ Branch 1 taken 175741 times.
✗ Branch 2 not taken.
175741 der.c_[i] = a.order()*(a.c_[i+1] - a.c_[i]);
290 }
291
1/2
✓ Branch 1 taken 22525 times.
✗ Branch 2 not taken.
22525 return der;
292 22525 }
293
294 1 Bezier integral(Bezier const &a)
295 {
296
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 Bezier inte(Bezier::Order(a.order()+1));
297
298 1 inte[0] = 0;
299
3/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
5 for(unsigned i = 0; i < inte.order(); i++) {
300
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 inte[i+1] = inte[i] + a[i]/(inte.order());
301 }
302 1 return inte;
303 }
304
305 1797516 OptInterval bounds_fast(Bezier const &b)
306 {
307
3/6
✓ Branch 2 taken 1797516 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1797516 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1797516 times.
✗ Branch 10 not taken.
3595032 return Interval::from_array(&b.c_[0], b.size());
308 }
309
310 318 OptInterval bounds_exact(Bezier const &b)
311 {
312
2/4
✓ Branch 1 taken 318 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 318 times.
✗ Branch 6 not taken.
318 OptInterval ret(b.at0(), b.at1());
313
2/4
✓ Branch 3 taken 318 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 318 times.
✗ Branch 7 not taken.
318 std::vector<Coord> r = derivative(b).roots();
314
2/2
✓ Branch 7 taken 122 times.
✓ Branch 8 taken 318 times.
440 for (double i : r) {
315
1/2
✓ Branch 2 taken 122 times.
✗ Branch 3 not taken.
122 ret->expandTo(b.valueAt(i));
316 }
317 318 return ret;
318 318 }
319
320 1 OptInterval bounds_local(Bezier const &b, OptInterval const &i)
321 {
322 //return bounds_local(b.toSBasis(), i);
323
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (i) {
324
2/4
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
2 return bounds_fast(portion(b, i->min(), i->max()));
325 } else {
326 return OptInterval();
327 }
328 }
329
330 /*
331 * The general bézier of degree n is
332 *
333 * p(t) = sum_{i = 0...n} binomial(n, i) t^i (1 - t)^(n - i) x[i]
334 *
335 * It can be written explicitly as a polynomial in t as
336 *
337 * p(t) = sum_{i = 0...n} binomial(n, i) t^i [ sum_{j = 0...i} binomial(i, j) (-1)^(i - j) x[j] ]
338 *
339 * Its derivative is
340 *
341 * p'(t) = n sum_{i = 1...n} binomial(n - 1, i - 1) t^(i - 1) [ sum_{j = 0...i} binomial(i, j) (-1)^(i - j) x[j] ]
342 *
343 * This is used by the various specialisations below as an optimisation for low degree n <= 3.
344 * In the remaining cases, the generic implementation is used which resorts to iteration.
345 */
346
347 100 void bezier_expand_to_image(Interval &range, Coord x0, Coord x1, Coord x2)
348 {
349 100 range.expandTo(x2);
350
351
2/2
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 30 times.
100 if (range.contains(x1)) {
352 // The interval contains all control points, and therefore the entire curve.
353 70 return;
354 }
355
356 // p'(t) / 2 = at + b
357 30 auto a = (x2 - x1) - (x1 - x0);
358 30 auto b = x1 - x0;
359
360 // t = -b / a
361
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 if (std::abs(a) > EPSILON) {
362 30 auto t = -b / a;
363
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
30 if (t > 0.0 && t < 1.0) {
364 30 auto s = 1.0 - t;
365 30 auto x = s * s * x0 + 2 * s * t * x1 + t * t * x2;
366 30 range.expandTo(x);
367 }
368 }
369 }
370
371 100 void bezier_expand_to_image(Interval &range, Coord x0, Coord x1, Coord x2, Coord x3)
372 {
373 100 range.expandTo(x3);
374
375
6/6
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 30 times.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 46 times.
✓ Branch 7 taken 54 times.
100 if (range.contains(x1) && range.contains(x2)) {
376 // The interval contains all control points, and therefore the entire curve.
377 46 return;
378 }
379
380 // p'(t) / 3 = at^2 + 2bt + c
381 54 auto a = (x3 - x0) - 3 * (x2 - x1);
382 54 auto b = (x2 - x1) - (x1 - x0);
383 54 auto c = x1 - x0;
384
385 54 auto expand = [&] (Coord t) {
386
3/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
104 if (t > 0.0 && t < 1.0) {
387 84 auto s = 1.0 - t;
388 84 auto x = s * s * s * x0 + 3 * s * s * t * x1 + 3 * t * t * s * x2 + t * t * t * x3;
389 84 range.expandTo(x);
390 }
391 158 };
392
393 // t = (-b ± sqrt(b^2 - ac)) / a
394
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
54 if (std::abs(a) < EPSILON) {
395 if (std::abs(b) > EPSILON) {
396 expand(-c / (2 * b));
397 }
398 } else {
399 54 auto d2 = b * b - a * c;
400
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 2 times.
54 if (d2 >= 0.0) {
401
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 auto bsign = b >= 0.0 ? 1 : -1;
402 52 auto tmp = -(b + bsign * std::sqrt(d2));
403
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 expand(tmp / a);
404
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 expand(c / tmp); // Using Vieta's formula: product of roots == c/a
405 }
406 }
407 }
408
409 } // namespace Geom
410
411 /*
412 Local Variables:
413 mode:c++
414 c-file-style:"stroustrup"
415 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
416 indent-tabs-mode:nil
417 fill-column:99
418 End:
419 */
420 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
421