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"
22 #include "svg/stringstream.h"
24 namespace Inkscape {
26 namespace SVG {
28 class PathString {
29 public:
30 PathString();
32 // default copy
33 // default assign
35 Glib::ustring const &ustring() const {
36 return (_abs_state <= _rel_state || !allow_relative_coordinates) ? _abs_state.str : _rel_state.str;
37 }
39 operator Glib::ustring const &() const {
40 return ustring();
41 }
43 char const *c_str() const {
44 return ustring().c_str();
45 }
47 PathString &moveTo(NR::Coord x, NR::Coord y) {
48 return moveTo(NR::Point(x, y));
49 }
51 PathString &moveTo(NR::Point p) {
52 _appendOp('M','m');
53 _appendPoint(p);
55 _current_point = _initial_point = p;
56 return *this;
57 }
59 PathString &lineTo(NR::Coord x, NR::Coord y) {
60 return lineTo(NR::Point(x, y));
61 }
63 PathString &lineTo(NR::Point p) {
64 _appendOp('L','l');
65 _appendPoint(p);
67 _current_point = p;
68 return *this;
69 }
71 PathString &quadTo(NR::Coord cx, NR::Coord cy, NR::Coord x, NR::Coord y) {
72 return quadTo(NR::Point(cx, cy), NR::Point(x, y));
73 }
75 PathString &quadTo(NR::Point c, NR::Point p) {
76 _appendOp('Q','q');
77 _appendPoint(c);
78 _appendPoint(p);
80 _current_point = p;
81 return *this;
82 }
84 PathString &curveTo(NR::Coord x0, NR::Coord y0,
85 NR::Coord x1, NR::Coord y1,
86 NR::Coord x, NR::Coord y)
87 {
88 return curveTo(NR::Point(x0, y0), NR::Point(x1, y1), NR::Point(x, y));
89 }
91 PathString &curveTo(NR::Point c0, NR::Point c1, NR::Point p) {
92 _appendOp('C','c');
93 _appendPoint(c0);
94 _appendPoint(c1);
95 _appendPoint(p);
97 _current_point = p;
98 return *this;
99 }
101 PathString &arcTo(NR::Coord rx, NR::Coord ry, NR::Coord rot,
102 bool large_arc, bool sweep,
103 NR::Point p)
104 {
105 _appendOp('A','a');
106 _appendValue(NR::Point(rx,ry));
107 _appendValue(rot);
108 _appendFlag(large_arc);
109 _appendFlag(sweep);
110 _appendPoint(p);
112 _current_point = p;
113 return *this;
114 }
116 PathString &closePath() {
117 _abs_state.appendOp('z');
118 _rel_state.appendOp('z');
119 _current_point = _initial_point;
120 return *this;
121 }
123 private:
125 void _appendOp(char abs_op, char rel_op);
127 void _appendFlag(bool flag) {
128 _abs_state.append(flag);
129 _rel_state.append(flag);
130 }
132 void _appendValue(NR::Coord v) {
133 _abs_state.append(v);
134 _rel_state.append(v);
135 }
137 void _appendValue(NR::Point p) {
138 _abs_state.append(p);
139 _rel_state.append(p);
140 }
142 void _appendX(NR::Coord x) {
143 _abs_state.append(x);
144 _rel_state.append(x-_current_point[NR::X]);
145 }
147 void _appendY(NR::Coord y) {
148 _abs_state.append(y);
149 _rel_state.append(y-_current_point[NR::Y]);
150 }
152 void _appendPoint(NR::Point p) {
153 _abs_state.append(p);
154 _rel_state.append(p-_current_point);
155 }
157 struct State {
158 State() { prevop = 0; switches = 0; }
160 void appendOp(char op) {
161 if (!str.empty()) str.append(1, ' ');
162 str.append(1, op);
163 prevop = op == 'M' ? 'L' : op == 'm' ? 'l' : op;
164 }
166 void append(bool flag) {
167 str.append(1, ' ');
168 str.append(1, ( flag ? '1' : '0' ));
169 }
171 void append(NR::Coord v) {
172 SVGOStringStream os;
173 os << ' ' << v;
174 str.append(os.str());
175 }
177 void append(NR::Point p) {
178 SVGOStringStream os;
179 os << ' ' << p[NR::X] << ',' << p[NR::Y];
180 str.append(os.str());
181 }
183 bool operator<=(const State& s) const {
184 if ( str.size() < s.str.size() ) return true;
185 if ( str.size() > s.str.size() ) return false;
186 if ( switches < s.switches ) return true;
187 if ( switches > s.switches ) return false;
188 return true;
189 }
191 Glib::ustring str;
192 unsigned int switches;
193 char prevop;
194 } _abs_state, _rel_state; // State with the last operator being an absolute/relative operator
196 NR::Point _initial_point;
197 NR::Point _current_point;
199 bool const allow_relative_coordinates;
200 bool const allow_shorthands;
201 bool const force_repeat_commands;
202 };
204 }
206 }
208 #endif
209 /*
210 Local Variables:
211 mode:c++
212 c-file-style:"stroustrup"
213 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
214 indent-tabs-mode:nil
215 fill-column:99
216 End:
217 */
218 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :