Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
sbasis.cpp
Go to the documentation of this file.
1/*
2 * sbasis.cpp - S-power basis function class + supporting classes
3 *
4 * Authors:
5 * Nathan Hurst <njh@mail.csse.monash.edu.au>
6 * Michael Sloan <mgsloan@gmail.com>
7 *
8 * Copyright (C) 2006-2007 authors
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it either under the terms of the GNU Lesser General Public
12 * License version 2.1 as published by the Free Software Foundation
13 * (the "LGPL") or, at your option, under the terms of the Mozilla
14 * Public License Version 1.1 (the "MPL"). If you do not alter this
15 * notice, a recipient may use your version of this file under either
16 * the MPL or the LGPL.
17 *
18 * You should have received a copy of the LGPL along with this library
19 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * You should have received a copy of the MPL along with this library
22 * in the file COPYING-MPL-1.1
23 *
24 * The contents of this file are subject to the Mozilla Public License
25 * Version 1.1 (the "License"); you may not use this file except in
26 * compliance with the License. You may obtain a copy of the License at
27 * http://www.mozilla.org/MPL/
28 *
29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
30 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
31 * the specific language governing rights and limitations.
32 */
33
34#include <cmath>
35
36#include <2geom/sbasis.h>
37#include <2geom/math-utils.h>
38
39namespace Geom {
40
41#ifndef M_PI
42# define M_PI 3.14159265358979323846
43#endif
44
49double SBasis::tailError(unsigned tail) const {
50 Interval bs = *bounds_fast(*this, tail);
51 return std::max(fabs(bs.min()),fabs(bs.max()));
52}
53
56bool SBasis::isFinite() const {
57 for(unsigned i = 0; i < size(); i++) {
58 if(!(*this)[i].isFinite())
59 return false;
60 }
61 return true;
62}
63
71std::vector<double> SBasis::valueAndDerivatives(double t, unsigned n) const {
72 std::vector<double> ret(n+1);
73 ret[0] = valueAt(t);
74 SBasis tmp = *this;
75 for(unsigned i = 1; i < n+1; i++) {
76 tmp.derive();
77 ret[i] = tmp.valueAt(t);
78 }
79 return ret;
80}
81
82
88SBasis operator+(const SBasis& a, const SBasis& b) {
89 const unsigned out_size = std::max(a.size(), b.size());
90 const unsigned min_size = std::min(a.size(), b.size());
91 SBasis result(out_size, Linear());
92
93 for(unsigned i = 0; i < min_size; i++) {
94 result[i] = a[i] + b[i];
95 }
96 for(unsigned i = min_size; i < a.size(); i++)
97 result[i] = a[i];
98 for(unsigned i = min_size; i < b.size(); i++)
99 result[i] = b[i];
100
101 assert(result.size() == out_size);
102 return result;
103}
104
110SBasis operator-(const SBasis& a, const SBasis& b) {
111 const unsigned out_size = std::max(a.size(), b.size());
112 const unsigned min_size = std::min(a.size(), b.size());
113 SBasis result(out_size, Linear());
114
115 for(unsigned i = 0; i < min_size; i++) {
116 result[i] = a[i] - b[i];
117 }
118 for(unsigned i = min_size; i < a.size(); i++)
119 result[i] = a[i];
120 for(unsigned i = min_size; i < b.size(); i++)
121 result[i] = -b[i];
122
123 assert(result.size() == out_size);
124 return result;
125}
126
133 const unsigned out_size = std::max(a.size(), b.size());
134 const unsigned min_size = std::min(a.size(), b.size());
135 a.resize(out_size);
136
137 for(unsigned i = 0; i < min_size; i++)
138 a[i] += b[i];
139 for(unsigned i = min_size; i < b.size(); i++)
140 a[i] = b[i];
141
142 assert(a.size() == out_size);
143 return a;
144}
145
152 const unsigned out_size = std::max(a.size(), b.size());
153 const unsigned min_size = std::min(a.size(), b.size());
154 a.resize(out_size);
155
156 for(unsigned i = 0; i < min_size; i++)
157 a[i] -= b[i];
158 for(unsigned i = min_size; i < b.size(); i++)
159 a[i] = -b[i];
160
161 assert(a.size() == out_size);
162 return a;
163}
164
170SBasis operator*(SBasis const &a, double k) {
171 SBasis c(a.size(), Linear());
172 for(unsigned i = 0; i < a.size(); i++)
173 c[i] = a[i] * k;
174 return c;
175}
176
182SBasis& operator*=(SBasis& a, double b) {
183 if (a.isZero()) return a;
184 if (b == 0)
185 a.clear();
186 else
187 for(auto & i : a)
188 i *= b;
189 return a;
190}
191
198SBasis shift(SBasis const &a, int sh) {
199 size_t n = a.size()+sh;
200 SBasis c(n, Linear());
201 size_t m = std::max(0, sh);
202
203 for(int i = 0; i < sh; i++)
204 c[i] = Linear(0,0);
205 for(size_t i = m, j = std::max(0,-sh); i < n; i++, j++)
206 c[i] = a[j];
207 return c;
208}
209
216SBasis shift(Linear const &a, int sh) {
217 size_t n = 1+sh;
218 SBasis c(n, Linear());
219
220 for(int i = 0; i < sh; i++)
221 c[i] = Linear(0,0);
222 if(sh >= 0)
223 c[sh] = a;
224 return c;
225}
226
227#if 0
228SBasis multiply(SBasis const &a, SBasis const &b) {
229 // c = {a0*b0 - shift(1, a.Tri*b.Tri), a1*b1 - shift(1, a.Tri*b.Tri)}
230
231 // shift(1, a.Tri*b.Tri)
232 SBasis c(a.size() + b.size(), Linear(0,0));
233 if(a.isZero() || b.isZero())
234 return c;
235 for(unsigned j = 0; j < b.size(); j++) {
236 for(unsigned i = j; i < a.size()+j; i++) {
237 double tri = b[j].tri()*a[i-j].tri();
238 c[i+1/*shift*/] += Linear(-tri);
239 }
240 }
241 for(unsigned j = 0; j < b.size(); j++) {
242 for(unsigned i = j; i < a.size()+j; i++) {
243 for(unsigned dim = 0; dim < 2; dim++)
244 c[i][dim] += b[j][dim]*a[i-j][dim];
245 }
246 }
247 c.normalize();
248 //assert(!(0 == c.back()[0] && 0 == c.back()[1]));
249 return c;
250}
251#else
252
259SBasis multiply_add(SBasis const &a, SBasis const &b, SBasis c) {
260 if(a.isZero() || b.isZero())
261 return c;
262 c.resize(a.size() + b.size(), Linear(0,0));
263 for(unsigned j = 0; j < b.size(); j++) {
264 for(unsigned i = j; i < a.size()+j; i++) {
265 double tri = b[j].tri()*a[i-j].tri();
266 c[i+1/*shift*/] += Linear(-tri);
267 }
268 }
269 for(unsigned j = 0; j < b.size(); j++) {
270 for(unsigned i = j; i < a.size()+j; i++) {
271 for(unsigned dim = 0; dim < 2; dim++)
272 c[i][dim] += b[j][dim]*a[i-j][dim];
273 }
274 }
275 c.normalize();
276 //assert(!(0 == c.back()[0] && 0 == c.back()[1]));
277 return c;
278}
279
285SBasis multiply(SBasis const &a, SBasis const &b) {
286 if(a.isZero() || b.isZero()) {
287 SBasis c(1, Linear(0,0));
288 return c;
289 }
290 SBasis c(a.size() + b.size(), Linear(0,0));
291 return multiply_add(a, b, c);
292}
293#endif
300 SBasis a;
301 a.resize(c.size() + 1, Linear(0,0));
302 a[0] = Linear(0,0);
303
304 for(unsigned k = 1; k < c.size() + 1; k++) {
305 double ahat = -c[k-1].tri()/(2*k);
306 a[k][0] = a[k][1] = ahat;
307 }
308 double aTri = 0;
309 for(int k = c.size()-1; k >= 0; k--) {
310 aTri = (c[k].hat() + (k+1)*aTri/2)/(2*k+1);
311 a[k][0] -= aTri/2;
312 a[k][1] += aTri/2;
313 }
314 a.normalize();
315 return a;
316}
317
324 SBasis c;
325 c.resize(a.size(), Linear(0,0));
326 if(a.isZero())
327 return c;
328
329 for(unsigned k = 0; k < a.size()-1; k++) {
330 double d = (2*k+1)*(a[k][1] - a[k][0]);
331
332 c[k][0] = d + (k+1)*a[k+1][0];
333 c[k][1] = d - (k+1)*a[k+1][1];
334 }
335 int k = a.size()-1;
336 double d = (2*k+1)*(a[k][1] - a[k][0]);
337 if (d == 0 && k > 0) {
338 c.pop_back();
339 } else {
340 c[k][0] = d;
341 c[k][1] = d;
342 }
343
344 return c;
345}
346
350void SBasis::derive() { // in place version
351 if(isZero()) return;
352 for(unsigned k = 0; k < size()-1; k++) {
353 double d = (2*k+1)*((*this)[k][1] - (*this)[k][0]);
354
355 (*this)[k][0] = d + (k+1)*(*this)[k+1][0];
356 (*this)[k][1] = d - (k+1)*(*this)[k+1][1];
357 }
358 int k = size()-1;
359 double d = (2*k+1)*((*this)[k][1] - (*this)[k][0]);
360 if (d == 0 && k > 0) {
361 pop_back();
362 } else {
363 (*this)[k][0] = d;
364 (*this)[k][1] = d;
365 }
366}
367
375SBasis sqrt(SBasis const &a, int k) {
376 SBasis c;
377 if(a.isZero() || k == 0)
378 return c;
379 c.resize(k, Linear(0,0));
380 c[0] = Linear(std::sqrt(a[0][0]), std::sqrt(a[0][1]));
381 SBasis r = a - multiply(c, c); // remainder
382
383 for(unsigned i = 1; i <= (unsigned)k && i<r.size(); i++) {
384 Linear ci(r[i][0]/(2*c[0][0]), r[i][1]/(2*c[0][1]));
385 SBasis cisi = shift(ci, i);
386 r -= multiply(shift((c*2 + cisi), i), SBasis(ci));
387 r.truncate(k+1);
388 c += cisi;
389 if(r.tailError(i) == 0) // if exact
390 break;
391 }
392
393 return c;
394}
395
402SBasis reciprocal(Linear const &a, int k) {
403 SBasis c;
404 assert(!a.isZero());
405 c.resize(k, Linear(0,0));
406 double r_s0 = (a.tri()*a.tri())/(-a[0]*a[1]);
407 double r_s0k = 1;
408 for(unsigned i = 0; i < (unsigned)k; i++) {
409 c[i] = Linear(r_s0k/a[0], r_s0k/a[1]);
410 r_s0k *= r_s0;
411 }
412 return c;
413}
414
421SBasis divide(SBasis const &a, SBasis const &b, int k) {
422 SBasis c;
423 assert(!a.isZero());
424 SBasis r = a; // remainder
425
426 k++;
427 r.resize(k, Linear(0,0));
428 c.resize(k, Linear(0,0));
429
430 for(unsigned i = 0; i < (unsigned)k; i++) {
431 Linear ci(r[i][0]/b[0][0], r[i][1]/b[0][1]); //H0
432 c[i] += ci;
433 r -= shift(multiply(ci,b), i);
434 r.truncate(k+1);
435 if(r.tailError(i) == 0) // if exact
436 break;
437 }
438
439 return c;
440}
441
448SBasis compose(SBasis const &a, SBasis const &b) {
449 SBasis s = multiply((SBasis(Linear(1,1))-b), b);
450 SBasis r;
451
452 for(int i = a.size()-1; i >= 0; i--) {
453 r = multiply_add(r, s, SBasis(Linear(a[i][0])) - b*a[i][0] + b*a[i][1]);
454 }
455 return r;
456}
457
464SBasis compose(SBasis const &a, SBasis const &b, unsigned k) {
465 SBasis s = multiply((SBasis(Linear(1,1))-b), b);
466 SBasis r;
467
468 for(int i = a.size()-1; i >= 0; i--) {
469 r = multiply_add(r, s, SBasis(Linear(a[i][0])) - b*a[i][0] + b*a[i][1]);
470 }
471 r.truncate(k);
472 return r;
473}
474
475SBasis portion(const SBasis &t, double from, double to) {
476 double fv = t.valueAt(from);
477 double tv = t.valueAt(to);
478 SBasis ret = compose(t, Linear(from, to));
479 ret.at0() = fv;
480 ret.at1() = tv;
481 return ret;
482}
483
484/*
485Inversion algorithm. The notation is certainly very misleading. The
486pseudocode should say:
487
488c(v) := 0
489r(u) := r_0(u) := u
490for i:=0 to k do
491 c_i(v) := H_0(r_i(u)/(t_1)^i; u)
492 c(v) := c(v) + c_i(v)*t^i
493 r(u) := r(u) ? c_i(u)*(t(u))^i
494endfor
495*/
496
497//#define DEBUG_INVERSION 1
498
506 assert(a.size() > 0);
507 double a0 = a[0][0];
508 if(a0 != 0) {
509 a -= a0;
510 }
511 double a1 = a[0][1];
512 assert(a1 != 0); // not invertable.
513
514 if(a1 != 1) {
515 a /= a1;
516 }
517 SBasis c(k, Linear()); // c(v) := 0
518 if(a.size() >= 2 && k == 2) {
519 c[0] = Linear(0,1);
520 Linear t1(1+a[1][0], 1-a[1][1]); // t_1
521 c[1] = Linear(-a[1][0]/t1[0], -a[1][1]/t1[1]);
522 } else if(a.size() >= 2) { // non linear
523 SBasis r = Linear(0,1); // r(u) := r_0(u) := u
524 Linear t1(1./(1+a[1][0]), 1./(1-a[1][1])); // 1./t_1
525 Linear one(1,1);
526 Linear t1i = one; // t_1^0
527 SBasis one_minus_a = SBasis(one) - a;
528 SBasis t = multiply(one_minus_a, a); // t(u)
529 SBasis ti(one); // t(u)^0
530#ifdef DEBUG_INVERSION
531 std::cout << "a=" << a << std::endl;
532 std::cout << "1-a=" << one_minus_a << std::endl;
533 std::cout << "t1=" << t1 << std::endl;
534 //assert(t1 == t[1]);
535#endif
536
537 //c.resize(k+1, Linear(0,0));
538 for(unsigned i = 0; i < (unsigned)k; i++) { // for i:=0 to k do
539#ifdef DEBUG_INVERSION
540 std::cout << "-------" << i << ": ---------" <<std::endl;
541 std::cout << "r=" << r << std::endl
542 << "c=" << c << std::endl
543 << "ti=" << ti << std::endl
544 << std::endl;
545#endif
546 if(r.size() <= i) // ensure enough space in the remainder, probably not needed
547 r.resize(i+1, Linear(0,0));
548 Linear ci(r[i][0]*t1i[0], r[i][1]*t1i[1]); // c_i(v) := H_0(r_i(u)/(t_1)^i; u)
549#ifdef DEBUG_INVERSION
550 std::cout << "t1i=" << t1i << std::endl;
551 std::cout << "ci=" << ci << std::endl;
552#endif
553 for(int dim = 0; dim < 2; dim++) // t1^-i *= 1./t1
554 t1i[dim] *= t1[dim];
555 c[i] = ci; // c(v) := c(v) + c_i(v)*t^i
556 // change from v to u parameterisation
557 SBasis civ = one_minus_a*ci[0] + a*ci[1];
558 // r(u) := r(u) - c_i(u)*(t(u))^i
559 // We can truncate this to the number of final terms, as no following terms can
560 // contribute to the result.
561 r -= multiply(civ,ti);
562 r.truncate(k);
563 if(r.tailError(i) == 0)
564 break; // yay!
565 ti = multiply(ti,t);
566 }
567#ifdef DEBUG_INVERSION
568 std::cout << "##########################" << std::endl;
569#endif
570 } else
571 c = Linear(0,1); // linear
572 c -= a0; // invert the offset
573 c /= a1; // invert the slope
574 return c;
575}
576
583SBasis sin(Linear b, int k) {
584 SBasis s(k+2, Linear());
585 s[0] = Linear(std::sin(b[0]), std::sin(b[1]));
586 double tr = s[0].tri();
587 double t2 = b.tri();
588 s[1] = Linear(std::cos(b[0])*t2 - tr, -std::cos(b[1])*t2 + tr);
589
590 t2 *= t2;
591 for(int i = 0; i < k; i++) {
592 Linear bo(4*(i+1)*s[i+1][0] - 2*s[i+1][1],
593 -2*s[i+1][0] + 4*(i+1)*s[i+1][1]);
594 bo -= s[i]*(t2/(i+1));
595
596
597 s[i+2] = bo/double(i+2);
598 }
599
600 return s;
601}
602
609SBasis cos(Linear bo, int k) {
610 return sin(Linear(bo[0] + M_PI/2,
611 bo[1] + M_PI/2),
612 k);
613}
614
623SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double zero){
624 SBasis result(order, Linear(0.)); //result
625 SBasis r=f; //remainder
626 SBasis Pk=Linear(1)-g,Qk=g,sg=Pk*Qk;
627 Pk.truncate(order);
628 Qk.truncate(order);
629 Pk.resize(order,Linear(0.));
630 Qk.resize(order,Linear(0.));
631 r.resize(order,Linear(0.));
632
633 int vs = valuation(sg,zero);
634 if (vs == 0) { // to prevent infinite loop
635 return result;
636 }
637
638 for (unsigned k=0; k<order; k+=vs){
639 double p10 = Pk.at(k)[0];// we have to solve the linear system:
640 double p01 = Pk.at(k)[1];//
641 double q10 = Qk.at(k)[0];// p10*a + q10*b = r10
642 double q01 = Qk.at(k)[1];// &
643 double r10 = r.at(k)[0];// p01*a + q01*b = r01
644 double r01 = r.at(k)[1];//
645 double a,b;
646 double det = p10*q01-p01*q10;
647
648 //TODO: handle det~0!!
649 if (fabs(det)<zero){
650 a=b=0;
651 }else{
652 a=( q01*r10-q10*r01)/det;
653 b=(-p01*r10+p10*r01)/det;
654 }
655 result[k] = Linear(a,b);
656 r=r-Pk*a-Qk*b;
657
658 Pk=Pk*sg;
659 Qk=Qk*sg;
660
661 Pk.resize(order,Linear(0.)); // truncates if too high order, expands with zeros if too low
662 Qk.resize(order,Linear(0.));
663 r.resize(order,Linear(0.));
664
665 }
666 result.normalize();
667 return result;
668}
669
670}
671
672/*
673 Local Variables:
674 mode:c++
675 c-file-style:"stroustrup"
676 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
677 indent-tabs-mode:nil
678 fill-column:99
679 End:
680*/
681// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Range of real numbers that is never empty.
Definition interval.h:59
Function that interpolates linearly between two values.
Definition linear.h:55
bool isZero(Coord eps=EPSILON) const
Definition linear.h:73
double tri() const
Definition linear.h:102
double tailError(unsigned tail) const
Definition sbasis-of.h:134
std::vector< double > valueAndDerivatives(double t, unsigned n) const
The size of the returned vector equals n+1.
Definition sbasis-of.h:121
Polynomial in symmetric power basis.
Definition sbasis.h:70
size_t size() const
Definition sbasis.h:76
bool isZero(double eps=EPSILON) const
Definition sbasis.h:195
void normalize()
Definition sbasis.h:247
Linear & at(unsigned i)
Definition sbasis.h:107
Coord at1() const
Definition sbasis.h:214
std::vector< Linear > d
Definition sbasis.h:71
double tailError(unsigned tail) const
bound the error from term truncation
Definition sbasis.cpp:49
void resize(unsigned n)
Definition sbasis.h:98
void clear()
Definition sbasis.h:101
void pop_back()
Definition sbasis.h:90
void derive()
Compute the derivative of this inplace (Exact)
Definition sbasis.cpp:350
Coord at0() const
Definition sbasis.h:212
double valueAt(double t) const
Definition sbasis.h:219
void truncate(unsigned k)
Definition sbasis.h:252
Css & result
double c[8][4]
const unsigned order
Low level math functions and compatibility wrappers.
Various utility functions.
Definition affine.h:22
SBasisN< n > cos(LinearN< n > bo, int k)
Geom::SBasisOf< double > SBasis
Definition sbasis-of.h:54
SBasisN< n > divide(SBasisN< n > const &a, SBasisN< n > const &b, int k)
SBasisN< n > compose_inverse(SBasisN< n > const &f, SBasisN< n > const &g, unsigned order=2, double tol=1e-3)
Geom::LinearOf< double > Linear
Definition linear-of.h:71
SBasisN< n > inverse(SBasisN< n > a, int k)
Bezier multiply(Bezier const &f, Bezier const &g)
Definition bezier.h:337
SBasisN< n > reciprocal(LinearN< n > const &a, int k)
D2< T > operator+=(D2< T > &a, D2< T > const &b)
Definition d2.h:219
D2< T > operator-(D2< T > const &a, D2< T > const &b)
Definition d2.h:209
D2< T > operator*=(D2< T > &a, Point const &b)
Definition d2.h:268
SBasisN< n > sqrt(SBasisN< n > const &a, int k)
SBasisOf< T > shift(SBasisOf< T > const &a, int sh)
Definition sbasis-of.h:435
Bezier operator*(Bezier const &f, Bezier const &g)
Definition bezier.cpp:221
D2< T > operator-=(D2< T > &a, D2< T > const &b)
Definition d2.h:228
D2< T > compose(D2< T > const &a, T const &b)
Definition d2.h:405
Bezier portion(const Bezier &a, double from, double to)
Definition bezier.cpp:250
SBasisOf< T > multiply_add(SBasisOf< T > const &a, SBasisOf< T > const &b, SBasisOf< T > c)
Definition sbasis-of.h:463
Bezier integral(Bezier const &a)
Definition bezier.cpp:294
Bezier derivative(Bezier const &a)
Definition bezier.cpp:282
D2< T > operator+(D2< T > const &a, D2< T > const &b)
Definition d2.h:199
OptInterval bounds_fast(Bezier const &b)
Definition bezier.cpp:305
static double det(Point a, Point b)
Definition conicsec.cpp:56
unsigned valuation(SBasisN< n > const &a, double tol=0)
Returns the degree of the first non zero coefficient.
Definition sbasisN.h:1038
SBasisN< n > sin(LinearN< n > bo, int k)
unsigned long bs
Definition quantize.cpp:38
Polynomial in symmetric power basis (S-basis)