Code

patch by Jasper for optimizing path data
authorbuliabyak <buliabyak@users.sourceforge.net>
Tue, 18 Mar 2008 04:53:42 +0000 (04:53 +0000)
committerbuliabyak <buliabyak@users.sourceforge.net>
Tue, 18 Mar 2008 04:53:42 +0000 (04:53 +0000)
src/preferences-skeleton.h
src/svg/Makefile_insert
src/svg/path-string.cpp [new file with mode: 0644]
src/svg/path-string.h
src/svg/svg-path.cpp

index ab8c29f428187bd6529b3a7438b28456ca96da13..225d572b064402e5c52233f78b86c5bff21c200b 100644 (file)
@@ -254,7 +254,7 @@ static char const preferences_skeleton[] =
 "           images=\"4278190335\"" //ff0000ff
 "           clips=\"16711935\"" // 00ff00ff
 "           masks=\"65535\"/>\n" // 0x0000ffff
-"    <group id=\"svgoutput\" usenamedcolors=\"0\" numericprecision=\"8\" minimumexponent=\"-8\" inlineattrs=\"0\" indent=\"2\"/>\n"
+"    <group id=\"svgoutput\" usenamedcolors=\"0\" numericprecision=\"8\" minimumexponent=\"-8\" inlineattrs=\"0\" indent=\"2\" allowrelativecoordinates=\"1\" allowshorthands=\"1\" forcerepeatcommands=\"0\"/>\n"
 "    <group id=\"forkgradientvectors\" value=\"1\"/>\n"
 "    <group id=\"grids\""
 "      no_emphasize_when_zoomedout=\"0\">\n"
index 5c723dfac6bd8f39d745f2b2ebd1254527351dac..5e57c7068c8b2c72986c451e807d19cdeb71ca31 100644 (file)
@@ -20,6 +20,7 @@ svg_libspsvg_a_SOURCES =      \
        svg/gnome-canvas-bpath-util.h   \
        svg/itos.cpp    \
        svg/path-string.h       \
+       svg/path-string.cpp \
        svg/round.cpp   \
        svg/stringstream.h      \
        svg/stringstream.cpp    \
diff --git a/src/svg/path-string.cpp b/src/svg/path-string.cpp
new file mode 100644 (file)
index 0000000..4cf790a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Inkscape::SVG::PathString - builder for SVG path strings
+ *
+ * Copyright 2008 Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See the file COPYING for details.
+ *
+ */
+
+#include "svg/path-string.h"
+#include "prefs-utils.h"
+
+Inkscape::SVG::PathString::PathString() :
+    allow_relative_coordinates(0 != prefs_get_int_attribute("options.svgoutput", "allowrelativecoordinates", 1)),
+    allow_shorthands(0 != prefs_get_int_attribute("options.svgoutput", "allowshorthands", 1)),
+    force_repeat_commands(0 != prefs_get_int_attribute("options.svgoutput", "forcerepeatcommands", 0))
+{}
+
+void Inkscape::SVG::PathString::_appendOp(char abs_op, char rel_op) {
+    bool abs_op_repeated = _abs_state.prevop == abs_op && !force_repeat_commands;
+    bool rel_op_repeated = _rel_state.prevop == rel_op && !force_repeat_commands;
+    unsigned int const abs_added_size = abs_op_repeated ? 0 : 2;
+    unsigned int const rel_added_size = rel_op_repeated ? 0 : 2;
+    if ( _rel_state.str.size()+2 < _abs_state.str.size()+abs_added_size && allow_relative_coordinates ) {
+        // Copy rel to abs
+        _abs_state = _rel_state;
+        _abs_state.switches++;
+        abs_op_repeated = false;
+        // We do not have to copy abs to rel:
+        //   _rel_state.str.size()+2 < _abs_state.str.size()+abs_added_size
+        //   _rel_state.str.size()+rel_added_size < _abs_state.str.size()+2
+        //   _abs_state.str.size()+2 > _rel_state.str.size()+rel_added_size
+    } else if ( _abs_state.str.size()+2 < _rel_state.str.size()+rel_added_size ) {
+        // Copy abs to rel
+        _rel_state = _abs_state;
+        _abs_state.switches++;
+        rel_op_repeated = false;
+    }
+    if ( !abs_op_repeated ) _abs_state.appendOp(abs_op);
+    if ( !rel_op_repeated ) _rel_state.appendOp(rel_op);
+}
+
+/*
+  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:encoding=utf-8:textwidth=99 :
index 3139466ef56854e155d763ae1ece73bf49652204..e90e110486780550a80de5754592cf1d67891d03 100644 (file)
@@ -2,6 +2,7 @@
  * Inkscape::SVG::PathString - builder for SVG path strings
  *
  * Copyright 2007 MenTaLguY <mental@rydia.net>
+ * Copyright 2008 Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -17,6 +18,7 @@
 
 #include <glibmm/ustring.h>
 #include "libnr/nr-point.h"
+#include "libnr/nr-point-ops.h"
 #include "svg/stringstream.h"
 
 namespace Inkscape {
@@ -25,13 +27,13 @@ namespace SVG {
 
 class PathString {
 public:
-    PathString() {}
+    PathString();
 
     // default copy
     // default assign
 
     Glib::ustring const &ustring() const {
-        return _str;
+        return (_abs_state <= _rel_state || !allow_relative_coordinates) ? _abs_state.str : _rel_state.str;
     }
 
     operator Glib::ustring const &() const {
@@ -39,7 +41,7 @@ public:
     }
 
     char const *c_str() const {
-        return _str.c_str();
+        return ustring().c_str();
     }
 
     PathString &moveTo(NR::Coord x, NR::Coord y) {
@@ -47,8 +49,10 @@ public:
     }
 
     PathString &moveTo(NR::Point p) {
-        _appendOp('M');
-        _append(p);
+        _appendOp('M','m');
+        _appendPoint(p);
+
+        _current_point = _initial_point = p;
         return *this;
     }
 
@@ -57,8 +61,10 @@ public:
     }
 
     PathString &lineTo(NR::Point p) {
-        _appendOp('L');
-        _append(p);
+        _appendOp('L','l');
+        _appendPoint(p);
+
+        _current_point = p;
         return *this;
     }
 
@@ -67,9 +73,11 @@ public:
     }
 
     PathString &quadTo(NR::Point c, NR::Point p) {
-        _appendOp('Q');
-        _append(c);
-        _append(p);
+        _appendOp('Q','q');
+        _appendPoint(c);
+        _appendPoint(p);
+
+        _current_point = p;
         return *this;
     }
 
@@ -79,13 +87,14 @@ public:
     {
         return curveTo(NR::Point(x0, y0), NR::Point(x1, y1), NR::Point(x, y));
     }
-    
 
     PathString &curveTo(NR::Point c0, NR::Point c1, NR::Point p) {
-        _appendOp('C');
-        _append(c0);
-        _append(c1);
-        _append(p);
+        _appendOp('C','c');
+        _appendPoint(c0);
+        _appendPoint(c1);
+        _appendPoint(p);
+
+        _current_point = p;
         return *this;
     }
 
@@ -93,46 +102,103 @@ public:
                       bool large_arc, bool sweep,
                       NR::Point p)
     {
-        _appendOp('A');
-        _append(NR::Point(rx, ry));
-        _append(rot);
-        _append(large_arc);
-        _append(sweep);
-        _append(p);
+        _appendOp('A','a');
+        _appendValue(NR::Point(rx,ry));
+        _appendValue(rot);
+        _appendFlag(large_arc);
+        _appendFlag(sweep);
+        _appendPoint(p);
+
+        _current_point = p;
         return *this;
     }
 
     PathString &closePath() {
-      _appendOp('z');
-      return *this;
+        _abs_state.appendOp('z');
+        _rel_state.appendOp('z');
+        _current_point = _initial_point;
+        return *this;
     }
 
 private:
-    void _appendOp(char op) {
-        if (!_str.empty()) {
-          _str.append(1, ' ');
-        }
-        _str.append(1, op);
+
+    void _appendOp(char abs_op, char rel_op);
+
+    void _appendFlag(bool flag) {
+        _abs_state.append(flag);
+        _rel_state.append(flag);
+    }
+
+    void _appendValue(NR::Coord v) {
+        _abs_state.append(v);
+        _rel_state.append(v);
     }
 
-    void _append(bool flag) {
-        _str.append(1, ' ');
-        _str.append(1, ( flag ? '1' : '0' ));
+    void _appendValue(NR::Point p) {
+        _abs_state.append(p);
+        _rel_state.append(p);
     }
 
-    void _append(NR::Coord v) {
-        SVGOStringStream os;
-        os << ' ' << v;
-        _str.append(os.str());
+    void _appendX(NR::Coord x) {
+        _abs_state.append(x);
+        _rel_state.append(x-_current_point[NR::X]);
     }
 
-    void _append(NR::Point p) {
-        SVGOStringStream os;
-        os << ' ' << p[NR::X] << ',' << p[NR::Y];
-        _str.append(os.str());
+    void _appendY(NR::Coord y) {
+        _abs_state.append(y);
+        _rel_state.append(y-_current_point[NR::Y]);
     }
 
-    Glib::ustring _str;
+    void _appendPoint(NR::Point p) {
+        _abs_state.append(p);
+        _rel_state.append(p-_current_point);
+    }
+
+    struct State {
+        State() { prevop = 0; switches = 0; }
+
+        void appendOp(char op) {
+            if (!str.empty()) str.append(1, ' ');
+            str.append(1, op);
+            prevop = op == 'M' ? 'L' : op == 'm' ? 'l' : op;
+        }
+
+        void append(bool flag) {
+            str.append(1, ' ');
+            str.append(1, ( flag ? '1' : '0' ));
+        }
+
+        void append(NR::Coord v) {
+            SVGOStringStream os;
+            os << ' ' << v;
+            str.append(os.str());
+        }
+
+        void append(NR::Point p) {
+            SVGOStringStream os;
+            os << ' ' << p[NR::X] << ',' << p[NR::Y];
+            str.append(os.str());
+        }
+
+        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;
+        }
+
+        Glib::ustring str;
+        unsigned int switches;
+        char prevop;
+    } _abs_state, _rel_state; // State with the last operator being an absolute/relative operator
+
+    NR::Point _initial_point;
+    NR::Point _current_point;
+
+    bool const allow_relative_coordinates;
+    bool const allow_shorthands;
+    bool const force_repeat_commands;
 };
 
 }
index 0239d2ae0cd843d32c916982ff9170fdee0d5007..30b259fa851142fae25d898f3dab343febcb8260 100644 (file)
@@ -664,7 +664,9 @@ gchar *sp_svg_write_path(NArtBpath const *bpath)
     for (int i = 0; bpath[i].code != NR_END; i++){
         switch (bpath [i].code){
         case NR_LINETO:
-            str.lineTo(bpath[i].x3, bpath[i].y3);
+            if (!closed || bpath[i+1].code == NR_LINETO || bpath[i+1].code == NR_CURVETO) {
+                str.lineTo(bpath[i].x3, bpath[i].y3);
+            }
             break;
 
         case NR_CURVETO: