1 /** 2 * \file 3 * \brief callback interface for SVG path data 4 *//* 5 * Copyright 2007 MenTaLguY <mental@rydia.net> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it either under the terms of the GNU Lesser General Public 9 * License version 2.1 as published by the Free Software Foundation 10 * (the "LGPL") or, at your option, under the terms of the Mozilla 11 * Public License Version 1.1 (the "MPL"). If you do not alter this 12 * notice, a recipient may use your version of this file under either 13 * the MPL or the LGPL. 14 * 15 * You should have received a copy of the LGPL along with this library 16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * You should have received a copy of the MPL along with this library 19 * in the file COPYING-MPL-1.1 20 * 21 * The contents of this file are subject to the Mozilla Public License 22 * Version 1.1 (the "License"); you may not use this file except in 23 * compliance with the License. You may obtain a copy of the License at 24 * http://www.mozilla.org/MPL/ 25 * 26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY 27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for 28 * the specific language governing rights and limitations. 29 * 30 */ 31 32 #ifndef LIB2GEOM_SEEN_PATH_SINK_H 33 #define LIB2GEOM_SEEN_PATH_SINK_H 34 35 #include <2geom/forward.h> 36 #include <2geom/pathvector.h> 37 #include <2geom/curves.h> 38 #include <iterator> 39 40 namespace Geom { 41 42 43 /** @brief Callback interface for processing path data. 44 * 45 * PathSink provides an interface that allows one to easily write 46 * code which processes path data, for instance when converting 47 * between path formats used by different graphics libraries. 48 * It is also useful for writing algorithms which must do something 49 * for each curve in the path. 50 * 51 * To store a path in a new format, implement the virtual methods 52 * for segments in a derived class and call feed(). 53 * 54 * @ingroup Paths 55 */ 56 class PathSink { 57 public: 58 /** @brief Move to a different point without creating a segment. 59 * Usually starts a new subpath. */ 60 virtual void moveTo(Point const &p) = 0; 61 /// Output a line segment. 62 virtual void lineTo(Point const &p) = 0; 63 /// Output a quadratic Bezier segment. 64 virtual void curveTo(Point const &c0, Point const &c1, Point const &p) = 0; 65 /// Output a cubic Bezier segment. 66 virtual void quadTo(Point const &c, Point const &p) = 0; 67 /** @brief Output an elliptical arc segment. 68 * See the EllipticalArc class for the documentation of parameters. */ 69 virtual void arcTo(Coord rx, Coord ry, Coord angle, 70 bool large_arc, bool sweep, Point const &p) = 0; 71 72 /// Close the current path with a line segment. 73 virtual void closePath() = 0; 74 /** @brief Flush any internal state of the generator. 75 * This call should implicitly finish the current subpath. 76 * Calling this method should be idempotent, because the default 77 * implementations of path() and pathvector() will call it 78 * multiple times in a row. */ 79 virtual void flush() = 0; 80 // Get the current point, e.g. where the initial point of the next segment will be. 81 //virtual Point currentPoint() const = 0; 82 83 /** @brief Undo the last segment. 84 * This method is optional. 85 * @return true true if a segment was erased, false otherwise. */ backspace()86 virtual bool backspace() { return false; } 87 88 // these have a default implementation 89 virtual void feed(Curve const &c, bool moveto_initial = true); 90 /** @brief Output a subpath. 91 * Calls the appropriate segment methods according to the contents 92 * of the passed subpath. You can override this function. 93 * NOTE: if you override only some of the feed() functions, 94 * always write this in the derived class: 95 * @code 96 using PathSink::feed; 97 @endcode 98 * Otherwise the remaining methods will be hidden. */ 99 virtual void feed(Path const &p); 100 /** @brief Output a path. 101 * Calls feed() on each path in the vector. You can override this function. */ 102 virtual void feed(PathVector const &v); 103 /// Output an axis-aligned rectangle, using moveTo, lineTo and closePath. 104 virtual void feed(Rect const &); 105 /// Output a circle as two elliptical arcs. 106 virtual void feed(Circle const &e); 107 /// Output an ellipse as two elliptical arcs. 108 virtual void feed(Ellipse const &e); 109 ~PathSink()110 virtual ~PathSink() {} 111 }; 112 113 /** @brief Store paths to an output iterator 114 * @ingroup Paths */ 115 template <typename OutputIterator> 116 class PathIteratorSink : public PathSink { 117 public: PathIteratorSink(OutputIterator out)118 explicit PathIteratorSink(OutputIterator out) 119 : _in_path(false), _out(out) {} 120 moveTo(Point const & p)121 void moveTo(Point const &p) override { 122 flush(); 123 _path.start(p); 124 _start_p = p; 125 _in_path = true; 126 } 127 //TODO: what if _in_path = false? 128 129 /** @brief Detect if the builder is in a path and thus will NOT 130 create a new moveTo command when given the next line 131 @return true if the builder is inside a subpath. 132 */ inPath()133 bool inPath() const { 134 return _in_path; 135 } 136 lineTo(Point const & p)137 void lineTo(Point const &p) override { 138 // check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z" 139 if (!_in_path) { 140 moveTo(_start_p); 141 } 142 _path.template appendNew<LineSegment>(p); 143 } 144 quadTo(Point const & c,Point const & p)145 void quadTo(Point const &c, Point const &p) override { 146 // check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z" 147 if (!_in_path) { 148 moveTo(_start_p); 149 } 150 _path.template appendNew<QuadraticBezier>(c, p); 151 } 152 curveTo(Point const & c0,Point const & c1,Point const & p)153 void curveTo(Point const &c0, Point const &c1, Point const &p) override { 154 // check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z" 155 if (!_in_path) { 156 moveTo(_start_p); 157 } 158 _path.template appendNew<CubicBezier>(c0, c1, p); 159 } 160 arcTo(Coord rx,Coord ry,Coord angle,bool large_arc,bool sweep,Point const & p)161 void arcTo(Coord rx, Coord ry, Coord angle, 162 bool large_arc, bool sweep, Point const &p) override 163 { 164 // check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z" 165 if (!_in_path) { 166 moveTo(_start_p); 167 } 168 _path.template appendNew<EllipticalArc>(rx, ry, angle, 169 large_arc, sweep, p); 170 } 171 backspace()172 bool backspace() override 173 { 174 if (_in_path && _path.size() > 0) { 175 _path.erase_last(); 176 return true; 177 } 178 return false; 179 } 180 append(Path const & other)181 void append(Path const &other) 182 { 183 if (!_in_path) { 184 moveTo(other.initialPoint()); 185 } 186 _path.append(other); 187 } 188 closePath()189 void closePath() override { 190 if (_in_path) { 191 _path.close(); 192 flush(); 193 } 194 } 195 flush()196 void flush() override { 197 if (_in_path) { 198 _in_path = false; 199 *_out++ = _path; 200 _path.clear(); 201 } 202 } 203 setStitching(bool s)204 void setStitching(bool s) { 205 _path.setStitching(s); 206 } 207 208 using PathSink::feed; feed(Path const & other)209 void feed(Path const &other) override 210 { 211 flush(); 212 *_out++ = other; 213 } 214 215 protected: 216 bool _in_path; 217 OutputIterator _out; 218 Path _path; 219 Point _start_p; 220 }; 221 222 typedef std::back_insert_iterator<PathVector> SubpathInserter; 223 224 /** @brief Store paths to a PathVector 225 * @ingroup Paths */ 226 class PathBuilder : public PathIteratorSink<SubpathInserter> { 227 private: 228 PathVector _pathset; 229 public: 230 /// Create a builder that outputs to an internal pathvector. PathBuilder()231 PathBuilder() : PathIteratorSink<SubpathInserter>(SubpathInserter(_pathset)) {} 232 /// Create a builder that outputs to pathvector given by reference. PathBuilder(PathVector & pv)233 PathBuilder(PathVector &pv) : PathIteratorSink<SubpathInserter>(SubpathInserter(pv)) {} 234 235 /// Retrieve the path peek()236 PathVector const &peek() const {return _pathset;} 237 /// Clear the stored path vector clear()238 void clear() { _pathset.clear(); } 239 }; 240 241 } 242 243 #endif 244 /* 245 Local Variables: 246 mode:c++ 247 c-file-style:"stroustrup" 248 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) 249 indent-tabs-mode:nil 250 fill-column:99 251 End: 252 */ 253 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : 254