bba4c8473969b550d09e10505d96cb6cc6ffbb4a
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 "libnr/nr-point.h"
21 #include "libnr/nr-point-ops.h"
23 namespace Inkscape {
25 namespace SVG {
27 class PathString {
28 public:
29 PathString();
31 // default copy
32 // default assign
34 Glib::ustring const &ustring() const {
35 return (_abs_state <= _rel_state || !allow_relative_coordinates) ? _abs_state.str : _rel_state.str;
36 }
38 operator Glib::ustring const &() const {
39 return ustring();
40 }
42 char const *c_str() const {
43 return ustring().c_str();
44 }
46 PathString &moveTo(NR::Coord x, NR::Coord y) {
47 return moveTo(NR::Point(x, y));
48 }
50 PathString &moveTo(NR::Point p) {
51 _appendOp('M','m');
52 _appendPoint(p, true);
54 _initial_point = _current_point;
55 return *this;
56 }
58 PathString &lineTo(NR::Coord x, NR::Coord y) {
59 return lineTo(NR::Point(x, y));
60 }
62 PathString &lineTo(NR::Point p) {
63 _appendOp('L','l');
64 _appendPoint(p, true);
65 return *this;
66 }
68 PathString &horizontalLineTo(NR::Coord x) {
69 _appendOp('H','h');
70 _appendX(x, true);
71 return *this;
72 }
74 PathString &verticalLineTo(NR::Coord y) {
75 _appendOp('V','v');
76 _appendY(y, true);
77 return *this;
78 }
80 PathString &quadTo(NR::Coord cx, NR::Coord cy, NR::Coord x, NR::Coord y) {
81 return quadTo(NR::Point(cx, cy), NR::Point(x, y));
82 }
84 PathString &quadTo(NR::Point c, NR::Point p) {
85 _appendOp('Q','q');
86 _appendPoint(c, false);
87 _appendPoint(p, true);
88 return *this;
89 }
91 PathString &curveTo(NR::Coord x0, NR::Coord y0,
92 NR::Coord x1, NR::Coord y1,
93 NR::Coord x, NR::Coord y)
94 {
95 return curveTo(NR::Point(x0, y0), NR::Point(x1, y1), NR::Point(x, y));
96 }
98 PathString &curveTo(NR::Point c0, NR::Point c1, NR::Point p) {
99 _appendOp('C','c');
100 _appendPoint(c0, false);
101 _appendPoint(c1, false);
102 _appendPoint(p, true);
103 return *this;
104 }
106 PathString &arcTo(NR::Coord rx, NR::Coord ry, NR::Coord rot,
107 bool large_arc, bool sweep,
108 NR::Point p)
109 {
110 _appendOp('A','a');
111 _appendValue(NR::Point(rx,ry));
112 _appendValue(rot);
113 _appendFlag(large_arc);
114 _appendFlag(sweep);
115 _appendPoint(p, true);
116 return *this;
117 }
119 PathString &closePath() {
120 _abs_state.appendOp('z');
121 _rel_state.appendOp('z');
122 _current_point = _initial_point;
123 return *this;
124 }
126 private:
128 void _appendOp(char abs_op, char rel_op);
130 void _appendFlag(bool flag) {
131 _abs_state.append(flag);
132 _rel_state.append(flag);
133 }
135 void _appendValue(NR::Coord v) {
136 _abs_state.append(v);
137 _rel_state.append(v);
138 }
140 void _appendValue(NR::Point p) {
141 _abs_state.append(p);
142 _rel_state.append(p);
143 }
145 void _appendX(NR::Coord x, bool sc) {
146 double rx;
147 _abs_state.append(x, rx);
148 _rel_state.appendRelative(rx, _current_point[NR::X]);
149 if (sc) _current_point[NR::X] = rx;
150 }
152 void _appendY(NR::Coord y, bool sc) {
153 double ry;
154 _abs_state.append(y, ry);
155 _rel_state.appendRelative(ry, _current_point[NR::Y]);
156 if (sc) _current_point[NR::Y] = ry;
157 }
159 void _appendPoint(NR::Point p, bool sc) {
160 NR::Point rp;
161 _abs_state.append(p, rp);
162 _rel_state.appendRelative(rp, _current_point);
163 if (sc) _current_point = rp;
164 }
166 struct State {
167 State() { prevop = 0; switches = 0; }
169 void appendOp(char op) {
170 if (!str.empty()) str.append(1, ' ');
171 str.append(1, op);
172 prevop = op == 'M' ? 'L' : op == 'm' ? 'l' : op;
173 }
175 void append(bool flag) {
176 str.append(1, ' ');
177 str.append(1, ( flag ? '1' : '0' ));
178 }
180 void append(NR::Coord v);
181 void append(NR::Point v);
182 void append(NR::Coord v, NR::Coord& rv);
183 void append(NR::Point p, NR::Point& rp);
184 void appendRelative(NR::Coord v, NR::Coord r);
185 void appendRelative(NR::Point p, NR::Point r);
187 bool operator<=(const State& s) const {
188 if ( str.size() < s.str.size() ) return true;
189 if ( str.size() > s.str.size() ) return false;
190 if ( switches < s.switches ) return true;
191 if ( switches > s.switches ) return false;
192 return true;
193 }
195 Glib::ustring str;
196 unsigned int switches;
197 char prevop;
198 } _abs_state, _rel_state; // State with the last operator being an absolute/relative operator
200 NR::Point _initial_point;
201 NR::Point _current_point;
203 bool const allow_relative_coordinates;
204 bool const force_repeat_commands;
205 };
207 }
209 }
211 #endif
212 /*
213 Local Variables:
214 mode:c++
215 c-file-style:"stroustrup"
216 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
217 indent-tabs-mode:nil
218 fill-column:99
219 End:
220 */
221 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :