Code

patch by Jasper for optimizing path data
[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"
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 };
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 :