~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, Ted Gould, Kees Cook
  • Date: 2009-06-24 14:00:43 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20090624140043-07stp20mry48hqup
Tags: 0.47~pre0-0ubuntu1
* New upstream release

[ Ted Gould ]
* debian/control: Adding libgsl0 and removing version specifics on boost

[ Kees Cook ]
* debian/watch: updated to run uupdate and mangle pre-release versions.
* Dropped patches that have been taken upstream:
  - 01_mips
  - 02-poppler-0.8.3
  - 03-chinese-inkscape
  - 05_fix_latex_patch
  - 06_gcc-4.4
  - 07_cdr2svg
  - 08_skip-bad-utf-on-pdf-import
  - 09_gtk-clist
  - 10_belarussian
  - 11_libpng
  - 12_desktop
  - 13_slider
  - 100_svg_import_improvements
  - 102_sp_pattern_painter_free
  - 103_bitmap_type_print

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 :