Code

72bf422e77dc1de9a7fac179ec8d0fac2b50b4bd
[inkscape.git] / src / 2geom / sbasis.h
1 /**
2  * \file
3  * \brief Defines S-power basis function class
4  *
5  *  Authors:
6  *   Nathan Hurst <njh@mail.csse.monash.edu.au>
7  *   Michael Sloan <mgsloan@gmail.com>
8  *
9  * Copyright (C) 2006-2007 authors
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it either under the terms of the GNU Lesser General Public
13  * License version 2.1 as published by the Free Software Foundation
14  * (the "LGPL") or, at your option, under the terms of the Mozilla
15  * Public License Version 1.1 (the "MPL"). If you do not alter this
16  * notice, a recipient may use your version of this file under either
17  * the MPL or the LGPL.
18  *
19  * You should have received a copy of the LGPL along with this library
20  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  * You should have received a copy of the MPL along with this library
23  * in the file COPYING-MPL-1.1
24  *
25  * The contents of this file are subject to the Mozilla Public License
26  * Version 1.1 (the "License"); you may not use this file except in
27  * compliance with the License. You may obtain a copy of the License at
28  * http://www.mozilla.org/MPL/
29  *
30  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
31  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
32  * the specific language governing rights and limitations.
33  */
35 #ifndef SEEN_SBASIS_H
36 #define SEEN_SBASIS_H
37 #include <vector>
38 #include <cassert>
39 #include <iostream>
41 #include <2geom/linear.h>
42 #include <2geom/interval.h>
43 #include <2geom/utils.h>
44 #include <2geom/exception.h>
46 namespace Geom {
48 /*** An empty SBasis is identically 0. */
49 class SBasis : public std::vector<Linear>{
50 public:
51     SBasis() {}
52     explicit SBasis(double a) {
53         push_back(Linear(a,a));
54     }
55     SBasis(SBasis const & a) :
56         std::vector<Linear>(a)
57     {}
58     SBasis(Linear const & bo) {
59         push_back(bo);
60     }
61     SBasis(Linear* bo) {
62         push_back(*bo);
63     }
65     //IMPL: FragmentConcept
66     typedef double output_type;
67     inline bool isZero() const {
68         if(empty()) return true;
69         for(unsigned i = 0; i < size(); i++) {
70             if(!(*this)[i].isZero()) return false;
71         }
72         return true;
73     }
74     inline bool isConstant() const {
75         if (empty()) return true;
76         for (unsigned i = 0; i < size(); i++) {
77             if(!(*this)[i].isConstant()) return false;
78         }
79         return true;
80     }
82     bool isFinite() const;
83     inline double at0() const { 
84         if(empty()) return 0; else return (*this)[0][0];
85     }
86     inline double at1() const{
87         if(empty()) return 0; else return (*this)[0][1];
88     }
90     double valueAt(double t) const {
91         double s = t*(1-t);
92         double p0 = 0, p1 = 0;
93         for(unsigned k = size(); k > 0; k--) {
94             const Linear &lin = (*this)[k-1];
95             p0 = p0*s + lin[0];
96             p1 = p1*s + lin[1];
97         }
98         return (1-t)*p0 + t*p1;
99     }
100     //double valueAndDerivative(double t, double &der) const {
101     //}
102     double operator()(double t) const {
103         return valueAt(t);
104     }
106     std::vector<double> valueAndDerivatives(double t, unsigned n) const;
108     SBasis toSBasis() const { return SBasis(*this); }
110     double tailError(unsigned tail) const;
112 // compute f(g)
113     SBasis operator()(SBasis const & g) const;
115     Linear operator[](unsigned i) const {
116         assert(i < size());
117         return std::vector<Linear>::operator[](i);
118     }
120 //MUTATOR PRISON
121     Linear& operator[](unsigned i) { return this->at(i); }
123     //remove extra zeros
124     void normalize() {
125         while(!empty() && 0 == back()[0] && 0 == back()[1])
126             pop_back();
127     }
129     void truncate(unsigned k) { if(k < size()) resize(k); }
130 private:
131     void derive(); // in place version
132 };
134 //TODO: figure out how to stick this in linear, while not adding an sbasis dep
135 inline SBasis Linear::toSBasis() const { return SBasis(*this); }
137 //implemented in sbasis-roots.cpp
138 Interval bounds_exact(SBasis const &a);
139 Interval bounds_fast(SBasis const &a, int order = 0);
140 Interval bounds_local(SBasis const &a, const Interval &t, int order = 0);
142 /** Returns a function which reverses the domain of a.
143  \param a sbasis function
145 useful for reversing a parameteric curve.
146 */
147 inline SBasis reverse(SBasis const &a) {
148     SBasis result;
149     result.reserve(a.size());
150     for(unsigned k = 0; k < a.size(); k++)
151        result.push_back(reverse(a[k]));
152     return result;
155 //IMPL: ScalableConcept
156 inline SBasis operator-(const SBasis& p) {
157     if(p.isZero()) return SBasis();
158     SBasis result;
159     result.reserve(p.size());
160         
161     for(unsigned i = 0; i < p.size(); i++) {
162         result.push_back(-p[i]);
163     }
164     return result;
166 SBasis operator*(SBasis const &a, double k);
167 inline SBasis operator*(double k, SBasis const &a) { return a*k; }
168 inline SBasis operator/(SBasis const &a, double k) { return a*(1./k); }
169 SBasis& operator*=(SBasis& a, double b);
170 inline SBasis& operator/=(SBasis& a, double b) { return (a*=(1./b)); }
172 //IMPL: AddableConcept
173 SBasis operator+(const SBasis& a, const SBasis& b);
174 SBasis operator-(const SBasis& a, const SBasis& b);
175 SBasis& operator+=(SBasis& a, const SBasis& b);
176 SBasis& operator-=(SBasis& a, const SBasis& b);
178 //TODO: remove?
179 inline SBasis operator+(const SBasis & a, Linear const & b) {
180     if(b.isZero()) return a;
181     if(a.isZero()) return b;
182     SBasis result(a);
183     result[0] += b;
184     return result;
186 inline SBasis operator-(const SBasis & a, Linear const & b) {
187     if(b.isZero()) return a;
188     SBasis result(a);
189     result[0] -= b;
190     return result;
192 inline SBasis& operator+=(SBasis& a, const Linear& b) {
193     if(a.isZero())
194         a.push_back(b);
195     else
196         a[0] += b;
197     return a;
199 inline SBasis& operator-=(SBasis& a, const Linear& b) {
200     if(a.isZero())
201         a.push_back(-b);
202     else
203         a[0] -= b;
204     return a;
207 //IMPL: OffsetableConcept
208 inline SBasis operator+(const SBasis & a, double b) {
209     if(a.isZero()) return Linear(b, b);
210     SBasis result(a);
211     result[0] += b;
212     return result;
214 inline SBasis operator-(const SBasis & a, double b) {
215     if(a.isZero()) return Linear(-b, -b);
216     SBasis result(a);
217     result[0] -= b;
218     return result;
220 inline SBasis& operator+=(SBasis& a, double b) {
221     if(a.isZero())
222         a.push_back(Linear(b,b));
223     else
224         a[0] += b;
225     return a;
227 inline SBasis& operator-=(SBasis& a, double b) {
228     if(a.isZero())
229         a.push_back(Linear(-b,-b));
230     else
231         a[0] -= b;
232     return a;
235 SBasis shift(SBasis const &a, int sh);
236 SBasis shift(Linear const &a, int sh);
238 inline SBasis truncate(SBasis const &a, unsigned terms) {
239     SBasis c;
240     c.insert(c.begin(), a.begin(), a.begin() + std::min(terms, (unsigned)a.size()));
241     return c;
244 SBasis multiply(SBasis const &a, SBasis const &b);
245 // This performs a multiply and accumulate operation in about the same time as multiply.  return a*b + c
246 SBasis multiply_add(SBasis const &a, SBasis const &b, SBasis c);
248 SBasis integral(SBasis const &c);
249 SBasis derivative(SBasis const &a);
251 SBasis sqrt(SBasis const &a, int k);
253 // return a kth order approx to 1/a)
254 SBasis reciprocal(Linear const &a, int k);
255 SBasis divide(SBasis const &a, SBasis const &b, int k);
257 inline SBasis operator*(SBasis const & a, SBasis const & b) {
258     return multiply(a, b);
261 inline SBasis& operator*=(SBasis& a, SBasis const & b) {
262     a = multiply(a, b);
263     return a;
266 /** Returns the degree of the first non zero coefficient.
267  \param a sbasis function
268  \param tol largest abs val considered 0
269  \returns first non zero coefficient
270 */
271 inline unsigned 
272 valuation(SBasis const &a, double tol=0){
273     unsigned val=0;
274     while( val<a.size() &&
275            fabs(a[val][0])<tol &&
276            fabs(a[val][1])<tol ) 
277         val++;
278     return val;
281 // a(b(t))
282 SBasis compose(SBasis const &a, SBasis const &b);
283 SBasis compose(SBasis const &a, SBasis const &b, unsigned k);
284 SBasis inverse(SBasis a, int k);
285 //compose_inverse(f,g)=compose(f,inverse(g)), but is numerically more stable in some good cases...
286 //TODO: requires g(0)=0 & g(1)=1 atm. generalization should be obvious.
287 SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order=2, double tol=1e-3);
289 /** Returns the sbasis on domain [0,1] that was t on [from, to]
290  \param a sbasis function
291  \param from,to interval
292  \returns sbasis
294 */
295 inline SBasis portion(const SBasis &t, double from, double to) { return compose(t, Linear(from, to)); }
297 // compute f(g)
298 inline SBasis
299 SBasis::operator()(SBasis const & g) const {
300     return compose(*this, g);
302  
303 inline std::ostream &operator<< (std::ostream &out_file, const Linear &bo) {
304     out_file << "{" << bo[0] << ", " << bo[1] << "}";
305     return out_file;
308 inline std::ostream &operator<< (std::ostream &out_file, const SBasis & p) {
309     for(unsigned i = 0; i < p.size(); i++) {
310         out_file << p[i] << "s^" << i << " + ";
311     }
312     return out_file;
315 // These are deprecated, use sbasis-math.h versions if possible
316 SBasis sin(Linear bo, int k);
317 SBasis cos(Linear bo, int k);
319 std::vector<double> roots(SBasis const & s);
320 std::vector<std::vector<double> > multi_roots(SBasis const &f,
321                                  std::vector<double> const &levels,
322                                  double htol=1e-7,
323                                  double vtol=1e-7,
324                                  double a=0,
325                                  double b=1);
326     
329 /*
330   Local Variables:
331   mode:c++
332   c-file-style:"stroustrup"
333   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
334   indent-tabs-mode:nil
335   fill-column:99
336   End:
337 */
338 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
339 #endif