d09d43b9da0f282cf82b9194c5984a645068867b
1 /*
2 * Inkscape::SVG::PathString - builder for SVG path strings
3 *
4 * Copyright 2007 MenTaLguY <mental@rydia.net>
5 * Copyright 2008 Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * See the file COPYING for details.
13 *
14 */
16 #ifndef SEEN_INKSCAPE_SVG_PATH_STRING_H
17 #define SEEN_INKSCAPE_SVG_PATH_STRING_H
19 #include <glibmm/ustring.h>
20 #include <string>
21 #include <stdio.h>
22 #include "libnr/nr-point.h"
23 #include "libnr/nr-point-ops.h"
25 namespace Inkscape {
27 namespace SVG {
29 class PathString {
30 public:
31 PathString();
33 // default copy
34 // default assign
36 std::string const &string() {
37 std::string const &t = tail();
38 final.reserve(commonbase.size()+t.size());
39 final = commonbase;
40 final += tail();
41 return final;
42 }
44 operator std::string const &() {
45 return string();
46 }
48 operator Glib::ustring const () const {
49 return commonbase + tail();
50 }
52 char const *c_str() {
53 return string().c_str();
54 }
56 PathString &moveTo(NR::Coord x, NR::Coord y) {
57 return moveTo(NR::Point(x, y));
58 }
60 PathString &moveTo(NR::Point p) {
61 _appendOp('M','m');
62 _appendPoint(p, true);
64 _initial_point = _current_point;
65 return *this;
66 }
68 PathString &lineTo(NR::Coord x, NR::Coord y) {
69 return lineTo(NR::Point(x, y));
70 }
72 PathString &lineTo(NR::Point p) {
73 _appendOp('L','l');
74 _appendPoint(p, true);
75 return *this;
76 }
78 PathString &horizontalLineTo(NR::Coord x) {
79 _appendOp('H','h');
80 _appendX(x, true);
81 return *this;
82 }
84 PathString &verticalLineTo(NR::Coord y) {
85 _appendOp('V','v');
86 _appendY(y, true);
87 return *this;
88 }
90 PathString &quadTo(NR::Coord cx, NR::Coord cy, NR::Coord x, NR::Coord y) {
91 return quadTo(NR::Point(cx, cy), NR::Point(x, y));
92 }
94 PathString &quadTo(NR::Point c, NR::Point p) {
95 _appendOp('Q','q');
96 _appendPoint(c, false);
97 _appendPoint(p, true);
98 return *this;
99 }
101 PathString &curveTo(NR::Coord x0, NR::Coord y0,
102 NR::Coord x1, NR::Coord y1,
103 NR::Coord x, NR::Coord y)
104 {
105 return curveTo(NR::Point(x0, y0), NR::Point(x1, y1), NR::Point(x, y));
106 }
108 PathString &curveTo(NR::Point c0, NR::Point c1, NR::Point p) {
109 _appendOp('C','c');
110 _appendPoint(c0, false);
111 _appendPoint(c1, false);
112 _appendPoint(p, true);
113 return *this;
114 }
116 PathString &arcTo(NR::Coord rx, NR::Coord ry, NR::Coord rot,
117 bool large_arc, bool sweep,
118 NR::Point p)
119 {
120 _appendOp('A','a');
121 _appendValue(NR::Point(rx,ry));
122 _appendValue(rot);
123 _appendFlag(large_arc);
124 _appendFlag(sweep);
125 _appendPoint(p, true);
126 return *this;
127 }
129 PathString &closePath() {
130 _abs_state.appendOp('z');
131 _rel_state.appendOp('z');
132 _current_point = _initial_point;
133 return *this;
134 }
136 private:
138 void _appendOp(char abs_op, char rel_op);
140 void _appendFlag(bool flag) {
141 _abs_state.append(flag);
142 _rel_state.append(flag);
143 }
145 void _appendValue(NR::Coord v) {
146 _abs_state.append(v);
147 _rel_state.append(v);
148 }
150 void _appendValue(NR::Point p) {
151 _abs_state.append(p);
152 _rel_state.append(p);
153 }
155 void _appendX(NR::Coord x, bool sc) {
156 double rx;
157 _abs_state.append(x, rx);
158 _rel_state.appendRelative(rx, _current_point[NR::X]);
159 if (sc) _current_point[NR::X] = rx;
160 }
162 void _appendY(NR::Coord y, bool sc) {
163 double ry;
164 _abs_state.append(y, ry);
165 _rel_state.appendRelative(ry, _current_point[NR::Y]);
166 if (sc) _current_point[NR::Y] = ry;
167 }
169 void _appendPoint(NR::Point p, bool sc) {
170 NR::Point rp;
171 _abs_state.append(p, rp);
172 _rel_state.appendRelative(rp, _current_point);
173 if (sc) _current_point = rp;
174 }
176 struct State {
177 State() { prevop = 0; switches = 0; }
179 void appendOp(char op) {
180 if (prevop != 0) str += ' ';
181 str += op;
182 prevop = ( op == 'M' ? 'L' : op == 'm' ? 'l' : op );
183 }
185 void append(bool flag) {
186 str += ' ';
187 str += ( flag ? '1' : '0' );
188 }
190 void append(NR::Coord v);
191 void append(NR::Point v);
192 void append(NR::Coord v, NR::Coord& rv);
193 void append(NR::Point p, NR::Point& rp);
194 void appendRelative(NR::Coord v, NR::Coord r);
195 void appendRelative(NR::Point p, NR::Point r);
197 bool operator<=(const State& s) const {
198 if ( str.size() < s.str.size() ) return true;
199 if ( str.size() > s.str.size() ) return false;
200 if ( switches < s.switches ) return true;
201 if ( switches > s.switches ) return false;
202 return true;
203 }
205 // Note: changing this to Glib::ustring might cause problems in path-string.cpp because it assumes that
206 // size() returns the size of the string in BYTES (and Glib::ustring::resize is terribly slow)
207 std::string str;
208 unsigned int switches;
209 char prevop;
211 private:
212 void appendNumber(double v, int precision=numericprecision, int minexp=minimumexponent);
213 void appendNumber(double v, double &rv, int precision=numericprecision, int minexp=minimumexponent);
214 void appendRelativeCoord(NR::Coord v, NR::Coord r);
215 } _abs_state, _rel_state; // State with the last operator being an absolute/relative operator
217 NR::Point _initial_point;
218 NR::Point _current_point;
220 // If both states have a common prefix it is stored here.
221 // Separating out the common prefix prevents repeated copying between the states
222 // to cause a quadratic time complexity (in the number of characters/operators)
223 std::string commonbase;
224 std::string final;
225 std::string const &tail() const { return ((_abs_state <= _rel_state || !allow_relative_coordinates) ? _abs_state.str : _rel_state.str); }
227 bool const allow_relative_coordinates;
228 bool const force_repeat_commands;
229 static int numericprecision;
230 static int minimumexponent;
231 };
233 }
235 }
237 #endif
238 /*
239 Local Variables:
240 mode:c++
241 c-file-style:"stroustrup"
242 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
243 indent-tabs-mode:nil
244 fill-column:99
245 End:
246 */
247 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :