Code

make spcurve::first_point and last_point boost::optional
[inkscape.git] / src / 2geom / sbasis-2d.h
1 #ifndef SEEN_SBASIS_2D_H
2 #define SEEN_SBASIS_2D_H
3 #include <vector>
4 #include <cassert>
5 #include <algorithm>
6 #include <2geom/d2.h>
7 #include <2geom/sbasis.h>
8 #include <iostream>
10 namespace Geom{
12 class Linear2d{
13 public:
14     /*  
15         u 0,1
16         v 0,2
17     */
18     double a[4];
19     Linear2d() {}
20     Linear2d(double aa) {
21         for(unsigned i = 0 ; i < 4; i ++) 
22             a[i] = aa;
23     }
24     Linear2d(double a00, double a01, double a10, double a11) 
25     {
26         a[0] = a00; 
27         a[1] = a01;
28         a[2] = a10; 
29         a[3] = a11; 
30     }
32     double operator[](const int i) const {
33         assert(i >= 0);
34         assert(i < 4);
35         return a[i];
36     }
37     double& operator[](const int i) {
38         assert(i >= 0);
39         assert(i < 4);
40         return a[i];
41     }
42     double apply(double u, double v) {
43         return (a[0]*(1-u)*(1-v) +
44                 a[1]*u*(1-v) +
45                 a[2]*(1-u)*v +
46                 a[3]*u*v);
47     }
48 };
50 inline Linear extract_u(Linear2d const &a, double u) {
51     return Linear(a[0]*(1-u) +
52                   a[1]*u,
53                   a[2]*(1-u) +
54                   a[3]*u);
55 }
56 inline Linear extract_v(Linear2d const &a, double v) {
57     return Linear(a[0]*(1-v) +
58                   a[2]*v,
59                   a[1]*(1-v) +
60                   a[3]*v);
61 }
62 inline Linear2d operator-(Linear2d const &a) {
63     return Linear2d(-a.a[0], -a.a[1],
64                     -a.a[2], -a.a[3]);
65 }
66 inline Linear2d operator+(Linear2d const & a, Linear2d const & b) {
67     return Linear2d(a[0] + b[0], 
68                   a[1] + b[1],
69                   a[2] + b[2], 
70                   a[3] + b[3]);
71 }
72 inline Linear2d operator-(Linear2d const & a, Linear2d const & b) {
73     return Linear2d(a[0] - b[0],
74                   a[1] - b[1],
75                   a[2] - b[2],
76                   a[3] - b[3]);
77 }
78 inline Linear2d& operator+=(Linear2d & a, Linear2d const & b) {
79     for(unsigned i = 0; i < 4; i++)
80         a[i] += b[i];
81     return a;
82 }
83 inline Linear2d& operator-=(Linear2d & a, Linear2d const & b) {
84     for(unsigned i = 0; i < 4; i++)
85         a[i] -= b[i];
86     return a;
87 }
88 inline Linear2d& operator*=(Linear2d & a, double b) {
89     for(unsigned i = 0; i < 4; i++)
90         a[i] *= b;
91     return a;
92 }
94 inline bool operator==(Linear2d const & a, Linear2d const & b) {
95     for(unsigned i = 0; i < 4; i++)
96         if(a[i] != b[i])
97             return false;
98     return true;
99 }
100 inline bool operator!=(Linear2d const & a, Linear2d const & b) {
101     for(unsigned i = 0; i < 4; i++)
102         if(a[i] == b[i])
103             return false;
104     return true;
106 inline Linear2d operator*(double const a, Linear2d const & b) {
107     return Linear2d(a*b[0], a*b[1],
108                   a*b[2], a*b[3]);
111 class SBasis2d : public std::vector<Linear2d>{
112 public:
113     // vector in u,v
114     unsigned us, vs; // number of u terms, v terms
115     SBasis2d() {}
116     SBasis2d(Linear2d const & bo) 
117         : us(1), vs(1) {
118         push_back(bo);
119     }
120     SBasis2d(SBasis2d const & a) 
121         : std::vector<Linear2d>(a), us(a.us), vs(a.vs) {}
122     
123     Linear2d& index(unsigned ui, unsigned vi) {
124         assert(ui < us);
125         assert(vi < vs);
126         return (*this)[ui + vi*us];        
127     }
128     
129     Linear2d index(unsigned ui, unsigned vi) const {
130         if(ui >= us) 
131             return Linear2d(0);
132         if(vi >= vs)
133             return Linear2d(0);
134         return (*this)[ui + vi*us];        
135     }
136     
137     double apply(double u, double v) const {
138         double s = u*(1-u);
139         double t = v*(1-v);
140         Linear2d p;
141         double tk = 1;
142 // XXX rewrite as horner
143         for(unsigned vi = 0; vi < vs; vi++) {
144             double sk = 1;
145             for(unsigned ui = 0; ui < us; ui++) {
146                 p += (sk*tk)*index(ui, vi);
147                 sk *= s;
148             }
149             tk *= t;
150         }
151         return p.apply(u,v);
152     }
154     void clear() {
155         fill(begin(), end(), Linear2d(0));
156     }
157     
158     void normalize(); // remove extra zeros
160     double tail_error(unsigned tail) const;
161     
162     void truncate(unsigned k);
163 };
165 inline SBasis2d operator-(const SBasis2d& p) {
166     SBasis2d result;
167     result.reserve(p.size());
168         
169     for(unsigned i = 0; i < p.size(); i++) {
170         result.push_back(-p[i]);
171     }
172     return result;
175 inline SBasis2d operator+(const SBasis2d& a, const SBasis2d& b) {
176     SBasis2d result;
177     result.us = std::max(a.us, b.us);
178     result.vs = std::max(a.vs, b.vs);
179     const unsigned out_size = result.us*result.vs;
180     result.resize(out_size);
181         
182     for(unsigned vi = 0; vi < result.vs; vi++) {
183         for(unsigned ui = 0; ui < result.us; ui++) {
184             Linear2d bo;
185             if(ui < a.us && vi < a.vs)
186                 bo += a.index(ui, vi);
187             if(ui < b.us && vi < b.vs)
188                 bo += b.index(ui, vi);
189             result.index(ui, vi) = bo;
190         }
191     }
192     return result;
195 inline SBasis2d operator-(const SBasis2d& a, const SBasis2d& b) {
196     SBasis2d result;
197     result.us = std::max(a.us, b.us);
198     result.vs = std::max(a.vs, b.vs);
199     const unsigned out_size = result.us*result.vs;
200     result.resize(out_size);
201         
202     for(unsigned vi = 0; vi < result.vs; vi++) {
203         for(unsigned ui = 0; ui < result.us; ui++) {
204             Linear2d bo;
205             if(ui < a.us && vi < a.vs)
206                 bo += a.index(ui, vi);
207             if(ui < b.us && vi < b.vs)
208                 bo -= b.index(ui, vi);
209             result.index(ui, vi) = bo;
210         }
211     }
212     return result;
216 inline SBasis2d& operator+=(SBasis2d& a, const Linear2d& b) {
217     if(a.size() < 1)
218         a.push_back(b);
219     else
220         a[0] += b;
221     return a;
224 inline SBasis2d& operator-=(SBasis2d& a, const Linear2d& b) {
225     if(a.size() < 1)
226         a.push_back(-b);
227     else
228         a[0] -= b;
229     return a;
232 inline SBasis2d& operator+=(SBasis2d& a, double b) {
233     if(a.size() < 1)
234         a.push_back(Linear2d(b));
235     else {
236         for(unsigned i = 0; i < 4; i++)
237             a[0] += double(b);
238     }
239     return a;
242 inline SBasis2d& operator-=(SBasis2d& a, double b) {
243     if(a.size() < 1)
244         a.push_back(Linear2d(-b));
245     else {
246         a[0] -= b;
247     }
248     return a;
251 inline SBasis2d& operator*=(SBasis2d& a, double b) {
252     for(unsigned i = 0; i < a.size(); i++)
253         a[i] *= b;
254     return a;
257 inline SBasis2d& operator/=(SBasis2d& a, double b) {
258     for(unsigned i = 0; i < a.size(); i++)
259         a[i] *= (1./b);
260     return a;
263 SBasis2d operator*(double k, SBasis2d const &a);
264 SBasis2d operator*(SBasis2d const &a, SBasis2d const &b);
266 SBasis2d shift(SBasis2d const &a, int sh);
268 SBasis2d shift(Linear2d const &a, int sh);
270 SBasis2d truncate(SBasis2d const &a, unsigned terms);
272 SBasis2d multiply(SBasis2d const &a, SBasis2d const &b);
274 SBasis2d integral(SBasis2d const &c);
276 SBasis2d derivative(SBasis2d const &a);
278 SBasis2d sqrt(SBasis2d const &a, int k);
280 // return a kth order approx to 1/a)
281 SBasis2d reciprocal(Linear2d const &a, int k);
283 SBasis2d divide(SBasis2d const &a, SBasis2d const &b, int k);
285 // a(b(t))
286 SBasis2d compose(SBasis2d const &a, SBasis2d const &b);
287 SBasis2d compose(SBasis2d const &a, SBasis2d const &b, unsigned k);
288 SBasis2d inverse(SBasis2d const &a, int k);
290 // these two should probably be replaced with compose
291 SBasis extract_u(SBasis2d const &a, double u);
292 SBasis extract_v(SBasis2d const &a, double v);
294 SBasis compose(Linear2d const &a, D2<SBasis> const &p);
296 SBasis compose(SBasis2d const &fg, D2<SBasis> const &p);
298 D2<SBasis> compose_each(D2<SBasis2d> const &fg, D2<SBasis> const &p);
300 inline std::ostream &operator<< (std::ostream &out_file, const Linear2d &bo) {
301     out_file << "{" << bo[0] << ", " << bo[1] << "}, ";
302     out_file << "{" << bo[2] << ", " << bo[3] << "}";
303     return out_file;
306 inline std::ostream &operator<< (std::ostream &out_file, const SBasis2d & p) {
307     for(unsigned i = 0; i < p.size(); i++) {
308         out_file << p[i] << "s^" << i << " + ";
309     }
310     return out_file;
313 };
315 /*
316   Local Variables:
317   mode:c++
318   c-file-style:"stroustrup"
319   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
320   indent-tabs-mode:nil
321   fill-column:99
322   End:
323 */
324 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
325 #endif