Code

Merge from fe-moved
[inkscape.git] / src / 2geom / d2-sbasis.cpp
1 #include <2geom/d2.h>
2 /* One would think that we would include d2-sbasis.h, however,
3  * you cannot actually include it in anything - only d2 may import it.
4  * This is due to the trickinesses of template submatching. */
6 namespace Geom {
8 SBasis L2(D2<SBasis> const & a, unsigned k) { return sqrt(dot(a, a), k); }
10 D2<SBasis> multiply(Linear const & a, D2<SBasis> const & b) {
11     return D2<SBasis>(multiply(a, b[X]), multiply(a, b[Y]));
12 }
14 D2<SBasis> multiply(SBasis const & a, D2<SBasis> const & b) {
15     return D2<SBasis>(multiply(a, b[X]), multiply(a, b[Y]));
16 }
18 D2<SBasis> truncate(D2<SBasis> const & a, unsigned terms) {
19     return D2<SBasis>(truncate(a[X], terms), truncate(a[Y], terms));
20 }
22 unsigned sbasis_size(D2<SBasis> const & a) {
23     return std::max((unsigned) a[0].size(), (unsigned) a[1].size());
24 }
26 //TODO: Is this sensical? shouldn't it be like pythagorean or something?
27 double tail_error(D2<SBasis> const & a, unsigned tail) {
28     return std::max(a[0].tailError(tail), a[1].tailError(tail));
29 }
31 Piecewise<D2<SBasis> > sectionize(D2<Piecewise<SBasis> > const &a) {
32     Piecewise<SBasis> x = partition(a[0], a[1].cuts), y = partition(a[1], a[0].cuts);
33     assert(x.size() == y.size());
34     Piecewise<D2<SBasis> > ret;
35     for(unsigned i = 0; i < x.size(); i++)
36         ret.push_seg(D2<SBasis>(x[i], y[i]));
37     ret.cuts.insert(ret.cuts.end(), x.cuts.begin(), x.cuts.end());
38     return ret;
39 }
41 D2<Piecewise<SBasis> > make_cuts_independent(Piecewise<D2<SBasis> > const &a) {
42     D2<Piecewise<SBasis> > ret;
43     for(unsigned d = 0; d < 2; d++) {
44         for(unsigned i = 0; i < a.size(); i++)
45             ret[d].push_seg(a[i][d]);
46         ret[d].cuts.insert(ret[d].cuts.end(), a.cuts.begin(), a.cuts.end());
47     }
48     return ret;
49 }
51 Piecewise<D2<SBasis> > rot90(Piecewise<D2<SBasis> > const &M){
52   Piecewise<D2<SBasis> > result;
53   if (M.empty()) return M;
54   result.push_cut(M.cuts[0]);
55   for (unsigned i=0; i<M.size(); i++){
56     result.push(rot90(M[i]),M.cuts[i+1]);
57   }
58   return result;
59 }
61 Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, 
62                       Piecewise<D2<SBasis> > const &b){
63   Piecewise<SBasis > result;
64   if (a.empty() || b.empty()) return result;
65   Piecewise<D2<SBasis> > aa = partition(a,b.cuts);
66   Piecewise<D2<SBasis> > bb = partition(b,a.cuts);
68   result.push_cut(aa.cuts.front());
69   for (unsigned i=0; i<aa.size(); i++){
70     result.push(dot(aa.segs[i],bb.segs[i]),aa.cuts[i+1]);
71   }
72   return result;
73 }
75 Piecewise<SBasis> cross(Piecewise<D2<SBasis> > const &a, 
76                         Piecewise<D2<SBasis> > const &b){
77   Piecewise<SBasis > result;
78   if (a.empty() || b.empty()) return result;
79   Piecewise<D2<SBasis> > aa = partition(a,b.cuts);
80   Piecewise<D2<SBasis> > bb = partition(b,a.cuts);
82   result.push_cut(aa.cuts.front());
83   for (unsigned i=0; i<a.size(); i++){
84     result.push(cross(aa.segs[i],bb.segs[i]),aa.cuts[i+1]);
85   }
86   return result;
87 }
89 Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Matrix const &m) {
90   Piecewise<D2<SBasis> > result;
91   if(a.empty()) return result;
92   result.push_cut(a.cuts[0]);
93   for (unsigned i = 0; i < a.size(); i++) {
94     result.push(a[i] * m, a.cuts[i+1]);
95   }
96   return result;
97 }
99 //if tol>0, only force continuity where the jump is smaller than tol.
100 Piecewise<D2<SBasis> > force_continuity(Piecewise<D2<SBasis> > const &f, double tol, bool closed)
102     if (f.size()==0) return f;
103     Piecewise<D2<SBasis> > result=f;
104     unsigned cur   = (closed)? 0:1;
105     unsigned prev  = (closed)? f.size()-1:0;
106     while(cur<f.size()){
107         Point pt0 = f.segs[prev].at1();
108         Point pt1 = f.segs[cur ].at0();
109         if (tol<=0 || L2sq(pt0-pt1)<tol*tol){
110             pt0 = (pt0+pt1)/2;
111             for (unsigned dim=0; dim<2; dim++){
112                 SBasis &prev_sb=result.segs[prev][dim];
113                 SBasis &cur_sb =result.segs[cur][dim];
114                 Coord const c=pt0[dim];
115                 if (prev_sb.empty()) {
116                   prev_sb.push_back(Linear(0.0, c));
117                 } else {
118                   prev_sb[0][1] = c;
119                 }
120                 if (cur_sb.empty()) {
121                   cur_sb.push_back(Linear(c, 0.0));
122                 } else {
123                   cur_sb[0][0] = c;
124                 }
125             }
126         }
127         prev = cur++;
128     }
129     return result;
132 std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > 
133 split_at_discontinuities (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwsbin, double tol)
135     using namespace Geom;
136     std::vector<Piecewise<D2<SBasis> > > ret;
137     unsigned piece_start = 0;
138     for (unsigned i=0; i<pwsbin.segs.size(); i++){
139         if (i==(pwsbin.segs.size()-1) || L2(pwsbin.segs[i].at1()- pwsbin.segs[i+1].at0()) > tol){
140             Piecewise<D2<SBasis> > piece;
141             piece.cuts.push_back(pwsbin.cuts[piece_start]);
142             for (unsigned j = piece_start; j<i+1; j++){
143                 piece.segs.push_back(pwsbin.segs[j]);
144                 piece.cuts.push_back(pwsbin.cuts[j+1]);
145             }
146             ret.push_back(piece);
147             piece_start = i+1;
148         }
149     }
150     return ret;
153 static void set_first_point(Piecewise<D2<SBasis> > &f, Point a){
154     if ( f.empty() ){
155         f.concat(Piecewise<D2<SBasis> >(D2<SBasis>(Linear(a[X]),Linear(a[Y]))));
156         return;
157     }
158     for (unsigned dim=0; dim<2; dim++){
159         if (f.segs.front()[dim].size() == 0){
160             f.segs.front()[dim].push_back(Linear(a[dim],0));
161         }else{
162             f.segs.front()[dim][0][0] = a[dim];
163         }
164     }
166 static void set_last_point(Piecewise<D2<SBasis> > &f, Point a){
167     if ( f.empty() ){
168         f.concat(Piecewise<D2<SBasis> >(D2<SBasis>(Linear(a[X]),Linear(a[Y]))));
169         return;
170     }
171     for (unsigned dim=0; dim<2; dim++){
172         if (f.segs.back()[dim].size() == 0){
173             f.segs.back()[dim].push_back(Linear(0,a[dim]));
174         }else{
175             f.segs.back()[dim][0][1] = a[dim];
176         }
177     }
180 std::vector<Piecewise<D2<SBasis> > > fuse_nearby_ends(std::vector<Piecewise<D2<SBasis> > > const &f, double tol){
182     if ( f.size()==0 ) return f;
183     std::vector<Piecewise<D2<SBasis> > > result;
184     std::vector<std::vector<unsigned> > pre_result;
185     for (unsigned i=0; i<f.size(); i++){
186         bool inserted = false;
187         Point a = f[i].firstValue();
188         Point b = f[i].lastValue();
189         for (unsigned j=0; j<pre_result.size(); j++){
190             Point aj = f.at(pre_result[j].back()).lastValue();
191             Point bj = f.at(pre_result[j].front()).firstValue();
192             if ( L2(a-aj) < tol ) {
193                 pre_result[j].push_back(i);
194                 inserted = true;
195                 break;
196             }
197             if ( L2(b-bj) < tol ) {
198                 pre_result[j].insert(pre_result[j].begin(),i);
199                 inserted = true;
200                 break;
201             }
202         }
203         if (!inserted) {
204             pre_result.push_back(std::vector<unsigned>());
205             pre_result.back().push_back(i);
206         }
207     }
208     for (unsigned i=0; i<pre_result.size(); i++){
209         Piecewise<D2<SBasis> > comp;
210         for (unsigned j=0; j<pre_result[i].size(); j++){
211             Piecewise<D2<SBasis> > new_comp = f.at(pre_result[i][j]);
212             if ( j>0 ){
213                 set_first_point( new_comp, comp.segs.back().at1() );
214             }
215             comp.concat(new_comp);
216         }
217         if ( L2(comp.firstValue()-comp.lastValue()) < tol ){
218             //TODO: check sizes!!!
219             set_last_point( comp, comp.segs.front().at0() ); 
220         }
221         result.push_back(comp);
222     }
223     return result;
224     return f;
228 }  // namespace Geom
231 /*
232   Local Variables:
233   mode:c++
234   c-file-style:"stroustrup"
235   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
236   indent-tabs-mode:nil
237   fill-column:99
238   End:
239 */
240 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :