Code

bba4c8473969b550d09e10505d96cb6cc6ffbb4a
[inkscape.git] / src / svg / path-string.h
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 };
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 :