summaryrefslogtreecommitdiffstats
path: root/src/svg/path-string.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/svg/path-string.h')
-rw-r--r--src/svg/path-string.h266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/svg/path-string.h b/src/svg/path-string.h
new file mode 100644
index 0000000..53080ba
--- /dev/null
+++ b/src/svg/path-string.h
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * Inkscape::SVG::PathString - builder for SVG path strings
+ *//*
+ * Authors: see git history
+ *
+ * Copyright 2007 MenTaLguY <mental@rydia.net>
+ * Copyright 2008 Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
+ * Copyright 2013 Tavmjong Bah <tavmjong@free.fr>
+ * Copyright (C) 2014 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_SVG_PATH_STRING_H
+#define SEEN_INKSCAPE_SVG_PATH_STRING_H
+
+#include <2geom/point.h>
+#include <cstdio>
+#include <glibmm/ustring.h>
+#include <string>
+
+namespace Inkscape {
+
+namespace SVG {
+
+// Relative vs. absolute coordinates
+enum PATHSTRING_FORMAT {
+ PATHSTRING_ABSOLUTE, // Use only absolute coordinates
+ PATHSTRING_RELATIVE, // Use only relative coordinates
+ PATHSTRING_OPTIMIZE, // Optimize for path string length
+ PATHSTRING_FORMAT_SIZE
+};
+
+/**
+ * Builder for SVG path strings.
+ */
+class PathString {
+public:
+ PathString();
+
+ // default copy
+ // default assign
+
+ std::string const &string() {
+ std::string const &t = tail();
+ final.reserve(commonbase.size()+t.size());
+ final = commonbase;
+ final += tail();
+ // std::cout << " final: " << final << std::endl;
+ return final;
+ }
+
+ operator std::string const &() {
+ return string();
+ }
+
+ operator Glib::ustring const () const {
+ return commonbase + tail();
+ }
+
+ char const *c_str() {
+ return string().c_str();
+ }
+
+ PathString &moveTo(Geom::Coord x, Geom::Coord y) {
+ return moveTo(Geom::Point(x, y));
+ }
+
+ PathString &moveTo(Geom::Point p) {
+ _appendOp('M','m');
+ _appendPoint(p, true);
+
+ _initial_point = _current_point;
+ return *this;
+ }
+
+ PathString &lineTo(Geom::Coord x, Geom::Coord y) {
+ return lineTo(Geom::Point(x, y));
+ }
+
+ PathString &lineTo(Geom::Point p) {
+ _appendOp('L','l');
+ _appendPoint(p, true);
+ return *this;
+ }
+
+ PathString &horizontalLineTo(Geom::Coord x) {
+ _appendOp('H','h');
+ _appendX(x, true);
+ return *this;
+ }
+
+ PathString &verticalLineTo(Geom::Coord y) {
+ _appendOp('V','v');
+ _appendY(y, true);
+ return *this;
+ }
+
+ PathString &quadTo(Geom::Coord cx, Geom::Coord cy, Geom::Coord x, Geom::Coord y) {
+ return quadTo(Geom::Point(cx, cy), Geom::Point(x, y));
+ }
+
+ PathString &quadTo(Geom::Point c, Geom::Point p) {
+ _appendOp('Q','q');
+ _appendPoint(c, false);
+ _appendPoint(p, true);
+ return *this;
+ }
+
+ PathString &curveTo(Geom::Coord x0, Geom::Coord y0,
+ Geom::Coord x1, Geom::Coord y1,
+ Geom::Coord x, Geom::Coord y)
+ {
+ return curveTo(Geom::Point(x0, y0), Geom::Point(x1, y1), Geom::Point(x, y));
+ }
+
+ PathString &curveTo(Geom::Point c0, Geom::Point c1, Geom::Point p) {
+ _appendOp('C','c');
+ _appendPoint(c0, false);
+ _appendPoint(c1, false);
+ _appendPoint(p, true);
+ return *this;
+ }
+
+ /**
+ * \param rot the angle in degrees
+ */
+ PathString &arcTo(Geom::Coord rx, Geom::Coord ry, Geom::Coord rot,
+ bool large_arc, bool sweep,
+ Geom::Point p)
+ {
+ _appendOp('A','a');
+ _appendValue(Geom::Point(rx,ry));
+ _appendValue(rot);
+ _appendFlag(large_arc);
+ _appendFlag(sweep);
+ _appendPoint(p, true);
+ return *this;
+ }
+
+ PathString &closePath() {
+
+ _abs_state.appendOp('Z');
+ _rel_state.appendOp('z');
+
+ _current_point = _initial_point;
+ return *this;
+ }
+
+private:
+
+ void _appendOp(char abs_op, char rel_op);
+
+ void _appendFlag(bool flag) {
+ _abs_state.append(flag);
+ _rel_state.append(flag);
+ }
+
+ void _appendValue(Geom::Coord v) {
+ _abs_state.append(v);
+ _rel_state.append(v);
+ }
+
+ void _appendValue(Geom::Point p) {
+ _abs_state.append(p);
+ _rel_state.append(p);
+ }
+
+ void _appendX(Geom::Coord x, bool sc) {
+ double rx;
+ _abs_state.append(x, rx);
+ _rel_state.appendRelative(rx, _current_point[Geom::X]);
+ if (sc) _current_point[Geom::X] = rx;
+ }
+
+ void _appendY(Geom::Coord y, bool sc) {
+ double ry;
+ _abs_state.append(y, ry);
+ _rel_state.appendRelative(ry, _current_point[Geom::Y]);
+ if (sc) _current_point[Geom::Y] = ry;
+ }
+
+ void _appendPoint(Geom::Point p, bool sc) {
+ Geom::Point rp;
+ _abs_state.append(p, rp);
+ _rel_state.appendRelative(rp, _current_point);
+ if (sc) _current_point = rp;
+ }
+
+ struct State {
+ State() { prevop = 0; switches = 0; }
+
+ void appendOp(char op) {
+ if (prevop != 0) str += ' ';
+ str += op;
+ prevop = ( op == 'M' ? 'L' : op == 'm' ? 'l' : op );
+ }
+
+ void append(bool flag) {
+ str += ' ';
+ str += ( flag ? '1' : '0' );
+ }
+
+ void append(Geom::Coord v);
+ void append(Geom::Point v);
+ void append(Geom::Coord v, Geom::Coord& rv);
+ void append(Geom::Point p, Geom::Point& rp);
+ void appendRelative(Geom::Coord v, Geom::Coord r);
+ void appendRelative(Geom::Point p, Geom::Point r);
+
+ bool operator<=(const State& s) const {
+ if ( str.size() < s.str.size() ) return true;
+ if ( str.size() > s.str.size() ) return false;
+ if ( switches < s.switches ) return true;
+ if ( switches > s.switches ) return false;
+ return true;
+ }
+
+ // Note: changing this to Glib::ustring might cause problems in path-string.cpp because it assumes that
+ // size() returns the size of the string in BYTES (and Glib::ustring::resize is terribly slow)
+ std::string str;
+ unsigned int switches;
+ char prevop;
+
+ private:
+ void appendNumber(double v, int precision=numericprecision, int minexp=minimumexponent);
+ void appendNumber(double v, double &rv, int precision=numericprecision, int minexp=minimumexponent);
+ void appendRelativeCoord(Geom::Coord v, Geom::Coord r);
+ } _abs_state, _rel_state; // State with the last operator being an absolute/relative operator
+
+ Geom::Point _initial_point;
+ Geom::Point _current_point;
+
+ // If both states have a common prefix it is stored here.
+ // Separating out the common prefix prevents repeated copying between the states
+ // to cause a quadratic time complexity (in the number of characters/operators)
+ std::string commonbase;
+ std::string final;
+ std::string const &tail() const {
+ return ( (format == PATHSTRING_ABSOLUTE) ||
+ (format == PATHSTRING_OPTIMIZE && _abs_state <= _rel_state ) ?
+ _abs_state.str : _rel_state.str );
+ }
+
+ static PATHSTRING_FORMAT format;
+ bool const force_repeat_commands;
+ static int numericprecision;
+ static int minimumexponent;
+};
+
+}
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :