1
#define SEEN_LIBNR_N_ART_BPATH_2GEOM_CPP
4
* Contains functions to convert from NArtBpath to 2geom's Path
6
* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
8
* Released under GNU GPL, read the file 'COPYING' for more information
12
#include "live_effects/n-art-bpath-2geom.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>
20
#define LPE_USE_2GEOM_CONVERSION
22
//##########################################################
27
#include <boost/format.hpp>
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];
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];
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];
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
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);
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));
57
static void write_svgd(std::ostream & f, Geom::Path const &p) {
63
f << boost::format("M %g,%g ") % p.initialPoint()[0] % p.initialPoint()[1];
65
for(Geom::Path::const_iterator iter(p.begin()), end(p.end()); iter != end; ++iter) {
66
curve_to_svgd(f, &(*iter));
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++) {
79
//##########################################################
80
#ifndef LPE_USE_2GEOM_CONVERSION
83
Geom::Point point(double *nums, int ix) {
84
return Geom::Point(nums[ix], nums[ix + 1]);
89
class OldPathBuilder {
91
OldPathBuilder(double const &c = Geom_EPSILON) : _current_path(NULL) {
92
_continuity_tollerance = c;
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;
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);
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);
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));
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]));
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);
134
void pushQuadraticRel(Point const &p0, Point const &p1, Point const &p2) {
135
pushQuadratic(p0 + _current_point, p1 + _current_point, p2 + _current_point);
137
void pushQuadratic(Point const &p0, Point const &p1, Point const &p2) {
138
if(p0 != _current_point) startPath(p0);
139
pushQuadratic(p1, p2);
142
void pushCubicRel(Point const &p1, Point const &p2, Point const &p3) {
143
pushCubic(p1 + _current_point, p2 + _current_point, p3 + _current_point);
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);
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);
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);
159
void pushEllipseRel(Point const &radii, double rotation, bool large, bool sweep, Point const &end) {
160
pushEllipse(radii, rotation, large, sweep, end + _current_point);
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;
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);
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);
176
void pushSBasis(SBasisCurve &sb) {
177
pushSBasis(sb.sbasis());
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) {
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
196
perhaps someday an option could be made to allow
197
the user to choose between these alternatives
200
sb[X][0][0] = _current_point[X];
201
sb[Y][0][0] = _current_point[Y];
203
_current_path->append(sb);
208
_current_path->close(true);
209
_current_path = NULL;
211
_current_point = _initial_point = Point();
214
std::vector<Path> const &peek() const { return _pathset; }
217
std::vector<Path> _pathset;
219
Point _current_point;
220
Point _initial_point;
221
double _continuity_tollerance;
225
std::vector<Geom::Path>
226
read_svgd(std::istringstream & s) {
229
OldPathBuilder builder;
238
if((ch >= 'A' and ch <= 'Z') or (ch >= 'a' and ch <= 'z')) {
241
} else if (ch == ' ' or ch == '\t' or ch == '\n' or ch == '\r' or ch == ',')
243
else if ((ch >= '0' and ch <= '9') or ch == '-' or ch == '.' or ch == '+') {
245
//TODO: use something else, perhaps. Unless the svg path number spec matches scan.
251
//FIXME: "If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands."
254
builder.startPathRel(point(nums, 0));
260
builder.startPath(point(nums, 0));
266
builder.pushLineRel(point(nums, 0));
272
builder.pushLine(point(nums, 0));
278
builder.pushHorizontalRel(nums[0]);
284
builder.pushHorizontal(nums[0]);
290
builder.pushVerticalRel(nums[0]);
296
builder.pushVertical(nums[0]);
302
builder.pushCubicRel(point(nums, 0), point(nums, 2), point(nums, 4));
308
builder.pushCubic(point(nums, 0), point(nums, 2), point(nums, 4));
314
builder.pushQuadraticRel(point(nums, 0), point(nums, 2));
320
builder.pushQuadratic(point(nums, 0), point(nums, 2));
326
//builder.pushEllipseRel(point(nums, 0), nums[2], nums[3] > 0, nums[4] > 0, point(nums, 5));
332
//builder.pushEllipse(point(nums, 0), nums[2], nums[3] > 0, nums[4] > 0, point(nums, 5));
342
return builder.peek();
347
//##########################################################
349
std::vector<Geom::Path>
350
SVGD_to_2GeomPath (char const *svgd)
352
std::vector<Geom::Path> pathv;
353
#ifdef LPE_USE_2GEOM_CONVERSION
355
pathv = Geom::parse_svg_path(svgd);
357
catch (std::runtime_error e) {
358
g_warning("SVGPathParseError: %s", e.what());
361
std::istringstream ss;
362
std::string svgd_string = svgd;
364
pathv = read_svgd(ss);
370
std::vector<Geom::Path>
371
BPath_to_2GeomPath(NArtBpath const * bpath)
373
std::vector<Geom::Path> pathv;
374
char *svgpath = sp_svg_write_path(bpath);
376
g_warning("BPath_to_2GeomPath - empty path returned");
379
pathv = SVGD_to_2GeomPath(svgpath);
385
SVGD_from_2GeomPath(std::vector<Geom::Path> const & path)
387
std::ostringstream ss;
388
write_svgd(ss, path);
390
std::string str = ss.str();
391
char * svgd = g_strdup(str.c_str());
396
BPath_from_2GeomPath(std::vector<Geom::Path> const & path)
398
char * svgd = SVGD_from_2GeomPath(path);
399
NArtBpath *bpath = sp_svg_read_path(svgd);
409
c-file-style:"stroustrup"
410
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
415
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :