~lib2geom-hackers/lib2geom/trunk

« back to all changes in this revision

Viewing changes to path.cpp

  • Committer: njh
  • Date: 2006-05-22 11:50:24 UTC
  • Revision ID: svn-v4:4601daaa-0314-0410-9a8b-c964a3c23b6b:trunk/lib2geom:1
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "path.h"
 
2
#include "cubic_bez_util.h"
 
3
 
 
4
namespace Geom{
 
5
 
 
6
Maybe<Rect> Path::bbox() const {
 
7
// needs work for other elements.
 
8
    if(handles.size() > 0) {
 
9
        Rect r(handles[0], handles[0]);
 
10
        
 
11
        for(std::vector<Geom::Point>::const_iterator h(handles.begin()), e(handles.end());
 
12
            h != e; ++h) {
 
13
            r.expandTo(*h);
 
14
        }
 
15
        return Maybe<Rect>(r);
 
16
    }
 
17
    return Nothing();
 
18
}
 
19
 
 
20
/*** push_back 
 
21
 * append e to this
 
22
 * note that this operation modifies the path.
 
23
 */
 
24
 
 
25
void Path::push_back(PathElem e) {
 
26
    assert(e.begin() != e.end());
 
27
    if(!handles.empty() && *e.begin() != handles.back()) {
 
28
        cmd.push_back(Geom::moveto);
 
29
        handles.push_back(*e.begin());
 
30
    }
 
31
    cmd.push_back(e.op);
 
32
    // inelegant
 
33
    if(e.op == moveto)
 
34
        handles.insert(handles.end(), e.begin(), e.end());
 
35
    else
 
36
        handles.insert(handles.end(), e.begin()+1, e.end());
 
37
}
 
38
 
 
39
 
 
40
/*** Path::insert
 
41
 * copy elements from [s,e) to before before (as per vector.insert)
 
42
 * note that this operation modifies the path.
 
43
 * 
 
44
 */
 
45
void Path::insert(PathConstIter before, PathConstIter s, PathConstIter e) {
 
46
    assert(0);
 
47
/*
 
48
    if((*s).begin()[0] != ) {
 
49
        cmd.push_back(Geom::moveto);
 
50
        handles.push_back(*e.begin());
 
51
    }
 
52
    cmd.push_back(e.op);
 
53
    handles.insert(handles.end(), e.begin(), e.end());
 
54
*/
 
55
}
 
56
 
 
57
 
 
58
/*Path Path::insert_node(PathLocation at) {
 
59
    Path p;
 
60
    
 
61
    p.insert(p.end(), begin(), at.it); // begining of path
 
62
    }*/
 
63
 
 
64
Geom::Point Geom::Path::PathElem::point_at(double t) {
 
65
    switch(op) {
 
66
    case Geom::moveto: // these four could be merged by a smarter person
 
67
        return s[0];
 
68
    case Geom::lineto:
 
69
        return Lerp(t, s[0], s[1]);
 
70
    case Geom::quadto:
 
71
    {
 
72
        Geom::Point mid[2];
 
73
        for(int i = 0; i < 2; i++)
 
74
            mid[i] = Lerp(t, s[i], s[i+1]);
 
75
        return Lerp(t, mid[0], mid[1]);
 
76
    }
 
77
    case Geom::cubicto:
 
78
    {
 
79
        Geom::Point mid[3];
 
80
        for(int i = 0; i < 3; i++)
 
81
            mid[i] = Lerp(t, s[i], s[i+1]);
 
82
        Geom::Point midmid[2];
 
83
        for(int i = 0; i < 2; i++)
 
84
            midmid[i] = Lerp(t, mid[i], mid[i+1]);
 
85
        return Lerp(t, midmid[0], midmid[1]);
 
86
    }
 
87
    default:
 
88
        break;
 
89
    }
 
90
}
 
91
 
 
92
void
 
93
Geom::Path::PathElem::point_tangent_acc_at(double t, 
 
94
                                           Geom::Point &pos, 
 
95
                                           Geom::Point &tgt,
 
96
                                           Geom::Point &acc) {
 
97
    switch(op) {
 
98
    case Geom::moveto: // these four could be merged by a smarter person
 
99
        pos = s[0];
 
100
        break;
 
101
    case Geom::lineto:
 
102
        pos = Lerp(t, s[0], s[1]);
 
103
        tgt = s[1] - s[0];
 
104
        acc = Point(0,0);
 
105
        break;
 
106
    case Geom::quadto:
 
107
    {
 
108
        Geom::Point mid[2];
 
109
        for(int i = 0; i < 2; i++)
 
110
            mid[i] = Lerp(t, s[i], s[i+1]);
 
111
        pos = Lerp(t, mid[0], mid[1]);
 
112
        break;
 
113
    }
 
114
    case Geom::cubicto:
 
115
    {
 
116
        Geom::Point pc[4];
 
117
        for(int i = 0; i < 4; i++)
 
118
            pc[i] = Point(0,0);
 
119
        
 
120
        cubic_bezier_poly_coeff(s, pc);
 
121
        pos = t*t*t*pc[3] + t*t*pc[2] + t*pc[1] + pc[0];
 
122
        tgt = 3*t*t*pc[3] + 2*t*pc[2] + pc[1];
 
123
        acc = 6*t*pc[3] + 2*pc[2];
 
124
        break;
 
125
    }
 
126
    default:
 
127
        break;
 
128
    }
 
129
}
 
130
 
 
131
 
 
132
Point Path::point_at(PathLocation at) {
 
133
    return (*at.it).point_at(at.t);
 
134
}
 
135
 
 
136
void Path::point_tangent_acc_at(PathLocation at, Point &pos, Point & tgt, Point &acc) {
 
137
    (*at.it).point_tangent_acc_at(at.t, pos, tgt, acc);
 
138
}
 
139
 
 
140
#include "nearestpoint.cpp"
 
141
 
 
142
bool Path::PathElem::nearest_location(Point p, double& dist, double& tt) {
 
143
    double new_dist, new_t;
 
144
    switch(op) {
 
145
    case Geom::moveto:
 
146
        new_dist = L2(p - s[0]);
 
147
        new_t = 0; // not meaningful
 
148
        break;
 
149
  // For the rest we can assume that start has already been tried.
 
150
    case Geom::lineto:
 
151
    {
 
152
        new_dist = L2(p - s[1]);
 
153
        new_t = 1;
 
154
        double t = dot(p - s[0], (s[1] - s[0])) / dot(s[1] - s[0], s[1] - s[0]);
 
155
        if((t > 0) && (t < 1)) {
 
156
            new_t = t;
 
157
            new_dist = fabs(dot(p - s[0], unit_vector(rot90(s[1] - s[0]))));
 
158
        }
 
159
        break;
 
160
    }
 
161
    case Geom::cubicto:
 
162
    {
 
163
        Point hnd[4];
 
164
        for(int i = 0; i < 4; i++) 
 
165
            hnd[i] = (*this)[i];// fixme
 
166
        new_t = NearestPointOnCurve(p, hnd);
 
167
        new_dist = L2(p - point_at(new_t));
 
168
        break;
 
169
    }
 
170
    default:
 
171
        return false;
 
172
    }
 
173
    if(new_dist < dist) {
 
174
        dist = new_dist;
 
175
        tt = new_t;
 
176
        return true;
 
177
    }
 
178
    return false;
 
179
}
 
180
 
 
181
Path::PathLocation Path::nearest_location(Point p, double &dist) {
 
182
    PathLocation pl(begin(), 0);
 
183
    dist = INFINITY;
 
184
    double t = 0;
 
185
    int i = 0;
 
186
    for(PathConstIter elm = begin();
 
187
        elm != end();
 
188
       ) {
 
189
        ++elm;
 
190
        if((*elm).nearest_location(p, dist, t)) {
 
191
            pl = PathLocation(elm, t);
 
192
        }
 
193
        i++;
 
194
    }
 
195
    return pl;
 
196
}
 
197
 
 
198
Path Path::subpath(PathConstIter begin, PathConstIter end) {
 
199
    Path result;
 
200
    for(PathConstIter iter(begin); iter != end; ++iter) {
 
201
        result.push_back(*iter);
 
202
    }
 
203
    return result;
 
204
}
 
205
 
 
206
 
 
207
 
 
208
};
 
209
 
 
210
#ifdef UNIT_TEST
 
211
int main(int argc, char **argv) {
 
212
    
 
213
}
 
214
#endif
 
215
 
 
216
 
 
217
/*
 
218
  Local Variables:
 
219
  mode:c++
 
220
  c-file-style:"stroustrup"
 
221
  c-file-offsets:((innamespace . 0)(substatement-open . 0))
 
222
  indent-tabs-mode:nil
 
223
  c-brace-offset:0
 
224
  fill-column:99
 
225
  End:
 
226
  vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
 
227
*/
 
228