~valavanisalex/ubuntu/oneiric/inkscape/inkscape_0.48.1-2ubuntu4

« back to all changes in this revision

Viewing changes to src/live_effects/n-art-bpath-2geom.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook, Kees Cook, Ted Gould
  • Date: 2008-02-10 14:20:16 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20080210142016-vcnb2zqyhszu0xvb
Tags: 0.46~pre1-0ubuntu1
[ Kees Cook ]
* debian/control:
  - add libgtkspell-dev build-dep to gain GtkSpell features (LP: #183547).
  - update Standards version (no changes needed).
  - add Vcs and Homepage fields.
  - switch to new python-lxml dep.
* debian/{control,rules}: switch from dpatch to quilt for more sanity.
* debian/patches/20_fix_glib_and_gxx43_ftbfs.patch:
  - merged against upstream fixes.
  - added additional fixes for newly written code.
* debian/rules: enable parallel building.

[ Ted Gould ]
* Updating POTFILES.in to make it so things build correctly.
* debian/control:
  - add ImageMagick++ and libboost-dev to build-deps

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define SEEN_LIBNR_N_ART_BPATH_2GEOM_CPP
 
2
 
 
3
/** \file
 
4
 * Contains functions to convert from NArtBpath to 2geom's Path
 
5
 *
 
6
 * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
 
7
 *
 
8
 * Released under GNU GPL, read the file 'COPYING' for more information
 
9
 */
 
10
 
 
11
 
 
12
#include "live_effects/n-art-bpath-2geom.h"
 
13
#include "svg/svg.h"
 
14
#include <glib.h>
 
15
#include <2geom/path.h>
 
16
#include <2geom/svg-path.h>
 
17
#include <2geom/svg-path-parser.h>
 
18
#include <2geom/sbasis-to-bezier.h>
 
19
 
 
20
#define LPE_USE_2GEOM_CONVERSION
 
21
 
 
22
//##########################################################
 
23
 
 
24
#include <iostream>
 
25
#include <sstream>
 
26
#include <string>
 
27
#include <boost/format.hpp>
 
28
 
 
29
static void curve_to_svgd(std::ostream & f, Geom::Curve const* c) {
 
30
    if(Geom::LineSegment const *line_segment = dynamic_cast<Geom::LineSegment const  *>(c)) {
 
31
        f << boost::format("L %g,%g ") % (*line_segment)[1][0] % (*line_segment)[1][1];
 
32
    }
 
33
    else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast<Geom::QuadraticBezier const  *>(c)) {
 
34
        f << boost::format("Q %g,%g %g,%g ") % (*quadratic_bezier)[1][0] % (*quadratic_bezier)[1][0]  
 
35
                % (*quadratic_bezier)[2][0] % (*quadratic_bezier)[2][1];
 
36
    }
 
37
    else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast<Geom::CubicBezier const  *>(c)) {
 
38
        f << boost::format("C %g,%g %g,%g %g,%g ") 
 
39
                % (*cubic_bezier)[1][0] % (*cubic_bezier)[1][1] 
 
40
                % (*cubic_bezier)[2][0] % (*cubic_bezier)[2][1] 
 
41
                % (*cubic_bezier)[3][0] % (*cubic_bezier)[3][1];
 
42
    }
 
43
//    else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::SVGEllipticalArc *>(c)) {
 
44
//        //get at the innards and spit them out as svgd
 
45
//    }
 
46
    else { 
 
47
        //this case handles sbasis as well as all other curve types
 
48
        Geom::Path sbasis_path = Geom::path_from_sbasis(c->toSBasis(), 0.1);
 
49
 
 
50
        //recurse to convert the new path resulting from the sbasis to svgd
 
51
        for(Geom::Path::iterator iter = sbasis_path.begin(); iter != sbasis_path.end(); ++iter) {
 
52
            curve_to_svgd(f, &(*iter));
 
53
        }
 
54
    }
 
55
}
 
56
 
 
57
static void write_svgd(std::ostream & f, Geom::Path const &p) {
 
58
    if(f == NULL) {
 
59
        f << "ERRRRRRORRRRR";
 
60
        return;
 
61
    }
 
62
 
 
63
    f << boost::format("M %g,%g ") % p.initialPoint()[0] % p.initialPoint()[1];
 
64
    
 
65
    for(Geom::Path::const_iterator iter(p.begin()), end(p.end()); iter != end; ++iter) {
 
66
        curve_to_svgd(f, &(*iter));
 
67
    }
 
68
    if(p.closed())
 
69
        f << "Z ";
 
70
}
 
71
 
 
72
static void write_svgd(std::ostream & f, std::vector<Geom::Path> const &p) {
 
73
    std::vector<Geom::Path>::const_iterator it(p.begin());
 
74
    for(; it != p.end(); it++) {
 
75
        write_svgd(f, *it);
 
76
    }
 
77
}
 
78
 
 
79
//##########################################################
 
80
#ifndef LPE_USE_2GEOM_CONVERSION
 
81
 
 
82
static
 
83
Geom::Point point(double *nums, int ix) {
 
84
    return Geom::Point(nums[ix], nums[ix + 1]);
 
85
}
 
86
 
 
87
using namespace Geom;
 
88
 
 
89
class OldPathBuilder {
 
90
public:
 
91
    OldPathBuilder(double const &c = Geom_EPSILON) : _current_path(NULL) {
 
92
        _continuity_tollerance = c;
 
93
    }
 
94
 
 
95
    void startPathRel(Point const &p0) { startPath(p0 + _current_point); }
 
96
    void startPath(Point const &p0) {
 
97
        _pathset.push_back(Geom::Path());
 
98
        _current_path = &_pathset.back();
 
99
        _initial_point = _current_point = p0;
 
100
    }
 
101
 
 
102
    void pushLineRel(Point const &p0) { pushLine(p0 + _current_point); }
 
103
    void pushLine(Point const &p1) {
 
104
        if (!_current_path) startPath(_current_point);
 
105
        _current_path->appendNew<LineSegment>(p1);
 
106
        _current_point = p1;
 
107
    }
 
108
 
 
109
    void pushLineRel(Point const &p0, Point const &p1) { pushLine(p0 + _current_point, p1 + _current_point); }
 
110
    void pushLine(Point const &p0, Point const &p1) {
 
111
        if(p0 != _current_point) startPath(p0);
 
112
        pushLine(p1);
 
113
    }
 
114
 
 
115
    void pushHorizontalRel(Coord y) { pushHorizontal(y + _current_point[1]); }
 
116
    void pushHorizontal(Coord y) {
 
117
        if (!_current_path) startPath(_current_point);
 
118
        pushLine(Point(_current_point[0], y));
 
119
    }
 
120
 
 
121
    void pushVerticalRel(Coord x) { pushVertical(x + _current_point[0]); }
 
122
    void pushVertical(Coord x) {
 
123
        if (!_current_path) startPath(_current_point);
 
124
        pushLine(Point(x, _current_point[1]));
 
125
    }
 
126
 
 
127
    void pushQuadraticRel(Point const &p1, Point const &p2) { pushQuadratic(p1 + _current_point, p2 + _current_point); }
 
128
    void pushQuadratic(Point const &p1, Point const &p2) {
 
129
        if (!_current_path) startPath(_current_point);
 
130
        _current_path->appendNew<QuadraticBezier>(p1, p2);
 
131
        _current_point = p2;
 
132
    }
 
133
 
 
134
    void pushQuadraticRel(Point const &p0, Point const &p1, Point const &p2) {
 
135
        pushQuadratic(p0 + _current_point, p1 + _current_point, p2 + _current_point);
 
136
    }
 
137
    void pushQuadratic(Point const &p0, Point const &p1, Point const &p2) {
 
138
        if(p0 != _current_point) startPath(p0);
 
139
        pushQuadratic(p1, p2);
 
140
    }
 
141
 
 
142
    void pushCubicRel(Point const &p1, Point const &p2, Point const &p3) {
 
143
        pushCubic(p1 + _current_point, p2 + _current_point, p3 + _current_point);
 
144
    }
 
145
    void pushCubic(Point const &p1, Point const &p2, Point const &p3) {
 
146
        if (!_current_path) startPath(_current_point);
 
147
        _current_path->appendNew<CubicBezier>(p1, p2, p3);
 
148
        _current_point = p3;
 
149
    }
 
150
 
 
151
    void pushCubicRel(Point const &p0, Point const &p1, Point const &p2, Point const &p3) {
 
152
        pushCubic(p0 + _current_point, p1 + _current_point, p2 + _current_point, p3 + _current_point);
 
153
    }
 
154
    void pushCubic(Point const &p0, Point const &p1, Point const &p2, Point const &p3) {
 
155
        if(p0 != _current_point) startPath(p0);
 
156
        pushCubic(p1, p2, p3);
 
157
    }
 
158
/*
 
159
    void pushEllipseRel(Point const &radii, double rotation, bool large, bool sweep, Point const &end) {
 
160
        pushEllipse(radii, rotation, large, sweep, end + _current_point);
 
161
    }
 
162
    void pushEllipse(Point const &radii, double rotation, bool large, bool sweep, Point const &end) {
 
163
        if (!_current_path) startPath(_current_point);
 
164
        _current_path->append(SVGEllipticalArc(_current_point, radii[0], radii[1], rotation, large, sweep, end));
 
165
        _current_point = end;
 
166
    }
 
167
 
 
168
    void pushEllipseRel(Point const &initial, Point const &radii, double rotation, bool large, bool sweep, Point const &end) {
 
169
        pushEllipse(initial + _current_point, radii, rotation, large, sweep, end + _current_point);
 
170
    }
 
171
    void pushEllipse(Point const &initial, Point const &radii, double rotation, bool large, bool sweep, Point const &end) {
 
172
        if(initial != _current_point) startPath(initial);
 
173
        pushEllipse(radii, rotation, large, sweep, end);
 
174
    }*/
 
175
    
 
176
    void pushSBasis(SBasisCurve &sb) {
 
177
        pushSBasis(sb.sbasis());
 
178
    }
 
179
    void pushSBasis(D2<SBasis> sb) {
 
180
        Point initial = Point(sb[X][0][0], sb[Y][0][0]);
 
181
        if (!_current_path) startPath(_current_point);
 
182
        if (distance(initial, _current_point) > _continuity_tollerance) {
 
183
            startPath(initial);
 
184
        } else if (_current_point != initial) {
 
185
            /* in this case there are three possible options
 
186
               1. connect the points with tiny line segments
 
187
                  this may well translate into bug reports from
 
188
                  users claiming "duplicate or extraneous nodes"
 
189
               2. fudge the initial point of the multidimsb
 
190
                  we've chosen to do this here but question the 
 
191
                  numerical stability of this decision
 
192
               3. translate the whole sbasis so that initial is coincident
 
193
                  with _current_point. this could very well lead
 
194
                  to an accumulation of error for paths that expect 
 
195
                  to meet in the end.
 
196
               perhaps someday an option could be made to allow 
 
197
               the user to choose between these alternatives
 
198
               if the need arises
 
199
            */
 
200
            sb[X][0][0] = _current_point[X];
 
201
            sb[Y][0][0] = _current_point[Y]; 
 
202
        }
 
203
        _current_path->append(sb);
 
204
    }
 
205
    
 
206
    void closePath() {
 
207
        if (_current_path) {
 
208
            _current_path->close(true);
 
209
            _current_path = NULL;
 
210
        }
 
211
        _current_point = _initial_point = Point();
 
212
    }
 
213
 
 
214
    std::vector<Path> const &peek() const { return _pathset; }
 
215
 
 
216
private:
 
217
    std::vector<Path> _pathset;
 
218
    Path *_current_path;
 
219
    Point _current_point;
 
220
    Point _initial_point;
 
221
    double _continuity_tollerance;
 
222
};
 
223
 
 
224
static
 
225
std::vector<Geom::Path>
 
226
read_svgd(std::istringstream & s) {
 
227
    assert(s);
 
228
 
 
229
    OldPathBuilder builder;
 
230
 
 
231
    char mode = 0;
 
232
 
 
233
    double nums[7];
 
234
    int cur = 0;
 
235
    while(!s.eof()) {
 
236
        char ch;
 
237
        s >> ch;
 
238
        if((ch >= 'A' and ch <= 'Z') or (ch >= 'a' and ch <= 'z')) {
 
239
            mode = ch;
 
240
            cur = 0;
 
241
        } else if (ch == ' ' or ch == '\t' or ch == '\n' or ch == '\r' or ch == ',')
 
242
            continue;
 
243
        else if ((ch >= '0' and ch <= '9') or ch == '-' or ch == '.' or ch == '+') {
 
244
            s.unget();
 
245
            //TODO: use something else, perhaps.  Unless the svg path number spec matches scan.
 
246
            s >> nums[cur];
 
247
            cur++;
 
248
        }
 
249
        
 
250
        switch(mode) {
 
251
        //FIXME: "If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands."
 
252
        case 'm':
 
253
            if(cur >= 2) {
 
254
                builder.startPathRel(point(nums, 0));
 
255
                cur = 0;
 
256
            }
 
257
            break;
 
258
        case 'M':
 
259
            if(cur >= 2) {
 
260
                builder.startPath(point(nums, 0));
 
261
                cur = 0;
 
262
            }
 
263
            break;
 
264
        case 'l':
 
265
            if(cur >= 2) {
 
266
                builder.pushLineRel(point(nums, 0));
 
267
                cur = 0;
 
268
            }
 
269
            break;
 
270
        case 'L':
 
271
            if(cur >= 2) {
 
272
                builder.pushLine(point(nums, 0));
 
273
                cur = 0;
 
274
            }
 
275
            break;
 
276
        case 'h':
 
277
            if(cur >= 1) {
 
278
                builder.pushHorizontalRel(nums[0]);
 
279
                cur = 0;
 
280
            }
 
281
            break;
 
282
        case 'H':
 
283
            if(cur >= 1) {
 
284
                builder.pushHorizontal(nums[0]);
 
285
                cur = 0;
 
286
            }
 
287
            break;
 
288
        case 'v':
 
289
            if(cur >= 1) {
 
290
                builder.pushVerticalRel(nums[0]);
 
291
                cur = 0;
 
292
            }
 
293
            break;
 
294
        case 'V':
 
295
            if(cur >= 1) {
 
296
                builder.pushVertical(nums[0]);
 
297
                cur = 0;
 
298
            }
 
299
            break;
 
300
        case 'c':
 
301
            if(cur >= 6) {
 
302
                builder.pushCubicRel(point(nums, 0), point(nums, 2), point(nums, 4));
 
303
                cur = 0;
 
304
            }
 
305
            break;
 
306
        case 'C':
 
307
            if(cur >= 6) {
 
308
                builder.pushCubic(point(nums, 0), point(nums, 2), point(nums, 4));
 
309
                cur = 0;
 
310
            }
 
311
            break;
 
312
        case 'q':
 
313
            if(cur >= 4) {
 
314
                builder.pushQuadraticRel(point(nums, 0), point(nums, 2));
 
315
                cur = 0;
 
316
            }
 
317
            break;
 
318
        case 'Q':
 
319
            if(cur >= 4) {
 
320
                builder.pushQuadratic(point(nums, 0), point(nums, 2));
 
321
                cur = 0;
 
322
            }
 
323
            break;
 
324
        case 'a':
 
325
            if(cur >= 7) {
 
326
                //builder.pushEllipseRel(point(nums, 0), nums[2], nums[3] > 0, nums[4] > 0, point(nums, 5));
 
327
                cur = 0;
 
328
            }
 
329
            break;
 
330
        case 'A':
 
331
            if(cur >= 7) {
 
332
                //builder.pushEllipse(point(nums, 0), nums[2], nums[3] > 0, nums[4] > 0, point(nums, 5));
 
333
                cur = 0;
 
334
            }
 
335
            break;
 
336
        case 'z':
 
337
        case 'Z':
 
338
            builder.closePath();
 
339
            break;
 
340
        }
 
341
    }
 
342
    return builder.peek();
 
343
}
 
344
 
 
345
 
 
346
#endif 
 
347
//##########################################################
 
348
 
 
349
std::vector<Geom::Path>  
 
350
SVGD_to_2GeomPath (char const *svgd)
 
351
{
 
352
    std::vector<Geom::Path> pathv;
 
353
#ifdef LPE_USE_2GEOM_CONVERSION
 
354
    try {
 
355
        pathv = Geom::parse_svg_path(svgd);
 
356
    }
 
357
    catch (std::runtime_error e) {
 
358
        g_warning("SVGPathParseError: %s", e.what());
 
359
    }
 
360
#else
 
361
    std::istringstream ss;
 
362
    std::string svgd_string = svgd;
 
363
    ss.str(svgd_string);
 
364
    pathv = read_svgd(ss);
 
365
#endif
 
366
    return pathv;
 
367
}
 
368
 
 
369
 
 
370
std::vector<Geom::Path>
 
371
BPath_to_2GeomPath(NArtBpath const * bpath)
 
372
{
 
373
    std::vector<Geom::Path> pathv;
 
374
    char *svgpath = sp_svg_write_path(bpath);
 
375
    if (!svgpath) {
 
376
        g_warning("BPath_to_2GeomPath - empty path returned");
 
377
        return pathv;
 
378
    }
 
379
    pathv = SVGD_to_2GeomPath(svgpath);
 
380
    g_free(svgpath);
 
381
    return pathv;
 
382
}
 
383
 
 
384
char *
 
385
SVGD_from_2GeomPath(std::vector<Geom::Path> const & path)
 
386
{
 
387
    std::ostringstream ss;
 
388
    write_svgd(ss, path);
 
389
    ss.flush();
 
390
    std::string str = ss.str();
 
391
    char * svgd = g_strdup(str.c_str());
 
392
    return svgd;
 
393
}
 
394
 
 
395
NArtBpath *
 
396
BPath_from_2GeomPath(std::vector<Geom::Path> const & path)
 
397
{
 
398
    char * svgd = SVGD_from_2GeomPath(path);
 
399
    NArtBpath *bpath = sp_svg_read_path(svgd);
 
400
    g_free(svgd);
 
401
    return bpath;
 
402
}
 
403
 
 
404
 
 
405
 
 
406
/*
 
407
  Local Variables:
 
408
  mode:c++
 
409
  c-file-style:"stroustrup"
 
410
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
411
  indent-tabs-mode:nil
 
412
  fill-column:99
 
413
  End:
 
414
*/
 
415
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :