Code

ok. so NOW the new effect is committed...
authorjohanengelen <johanengelen@users.sourceforge.net>
Tue, 30 Oct 2007 22:44:42 +0000 (22:44 +0000)
committerjohanengelen <johanengelen@users.sourceforge.net>
Tue, 30 Oct 2007 22:44:42 +0000 (22:44 +0000)
src/live_effects/Makefile_insert
src/live_effects/lpe-pathalongpath.cpp [new file with mode: 0644]
src/live_effects/lpe-pathalongpath.h [new file with mode: 0644]

index fcce5721e11490f81fa2b978c1a9803ad71dadb7..2c9192468cf222c08b268ffd4a83b4584d19e815 100644 (file)
@@ -16,6 +16,8 @@ live_effects_liblive_effects_a_SOURCES = \
        live_effects/n-art-bpath-2geom.h        \\r
        live_effects/lpe-skeletalstrokes.cpp    \\r
        live_effects/lpe-skeletalstrokes.h      \\r
+       live_effects/lpe-pathalongpath.cpp      \\r
+       live_effects/lpe-pathalongpath.h        \\r
        live_effects/lpe-curvestitch.cpp        \\r
        live_effects/lpe-curvestitch.h  \\r
        live_effects/lpe-gears.cpp      \\r
diff --git a/src/live_effects/lpe-pathalongpath.cpp b/src/live_effects/lpe-pathalongpath.cpp
new file mode 100644 (file)
index 0000000..0e9be8f
--- /dev/null
@@ -0,0 +1,195 @@
+#define INKSCAPE_LPE_PATHALONGPATH_CPP\r
+\r
+/*\r
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+\r
+#include "live_effects/lpe-pathalongpath.h"\r
+#include "sp-shape.h"\r
+#include "sp-item.h"\r
+#include "display/curve.h"\r
+#include <libnr/n-art-bpath.h>\r
+#include <libnr/nr-matrix-fns.h>\r
+#include "live_effects/n-art-bpath-2geom.h"\r
+#include "svg/svg.h"\r
+#include "ui/widget/scalar.h"\r
+\r
+#include <2geom/sbasis.h>\r
+#include <2geom/sbasis-geometric.h>\r
+#include <2geom/bezier-to-sbasis.h>\r
+#include <2geom/sbasis-to-bezier.h>\r
+#include <2geom/d2.h>\r
+#include <2geom/piecewise.h>\r
+\r
+#include <algorithm>\r
+using std::vector;\r
+\r
+\r
+/* Theory in e-mail from J.F. Barraud\r
+Let B be the skeleton path, and P the pattern (the path to be deformed).\r
+\r
+P is a map t --> P(t) = ( x(t), y(t) ).\r
+B is a map t --> B(t) = ( a(t), b(t) ).\r
+\r
+The first step is to re-parametrize B by its arc length: this is the parametrization in which a point p on B is located by its distance s from start. One obtains a new map s --> U(s) = (a'(s),b'(s)), that still describes the same path B, but where the distance along B from start to\r
+U(s) is s itself.\r
+\r
+We also need a unit normal to the path. This can be obtained by computing a unit tangent vector, and rotate it by 90°. Call this normal vector N(s).\r
+\r
+The basic deformation associated to B is then given by:\r
+\r
+   (x,y) --> U(x)+y*N(x)\r
+\r
+(i.e. we go for distance x along the path, and then for distance y along the normal)\r
+\r
+Of course this formula needs some minor adaptations (as is it depends on the absolute position of P for instance, so a little translation is needed\r
+first) but I think we can first forget about them.\r
+*/\r
+\r
+namespace Inkscape {\r
+namespace LivePathEffect {\r
+\r
+static const Util::EnumData<PAPCopyType> PAPCopyTypeData[PAPCT_END] = {\r
+    {PAPCT_SINGLE,               N_("Single"),               "single"},\r
+    {PAPCT_SINGLE_STRETCHED,     N_("Single, stretched"),    "single_stretched"},\r
+    {PAPCT_REPEATED,             N_("Repeated"),             "repeated"},\r
+    {PAPCT_REPEATED_STRETCHED,   N_("Repeated, stretched"),  "repeated_stretched"}\r
+};\r
+static const Util::EnumDataConverter<PAPCopyType> PAPCopyTypeConverter(PAPCopyTypeData, PAPCT_END);\r
+\r
+LPEPathAlongPath::LPEPathAlongPath(LivePathEffectObject *lpeobject) :\r
+    Effect(lpeobject),\r
+    bend_path(_("Bend path"), _("Path along which to bend the original path"), "bendpath", &wr, this, "M0,0 L1,0"),\r
+    copytype(_("Path copies"), _("How many copies to place along the skeleton path"), "copytype", PAPCopyTypeConverter, &wr, this, PAPCT_SINGLE_STRETCHED),\r
+    prop_scale(_("Width"), _("Width of the path"), "prop_scale", &wr, this, 1),\r
+    scale_y_rel(_("Width in units of length"), _("Scale the width of the path in units of its length"), "scale_y_rel", &wr, this, false),\r
+    spacing(_("Spacing"), _("Space between copies of the path"), "spacing", &wr, this, 0),\r
+    normal_offset(_("Normal offset"), "", "normal_offset", &wr, this, 0),\r
+    tang_offset(_("Tangential offset"), "", "tang_offset", &wr, this, 0),\r
+    vertical_pattern(_("Original path is vertical"), "", "vertical", &wr, this, false)\r
+{\r
+    registerParameter( dynamic_cast<Parameter *>(&bend_path) );\r
+    registerParameter( dynamic_cast<Parameter *>(&copytype) );\r
+    registerParameter( dynamic_cast<Parameter *>(&prop_scale) );\r
+    registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) );\r
+//These parameters have not been implemented yet:\r
+//    registerParameter( dynamic_cast<Parameter *>(&spacing) );\r
+//    registerParameter( dynamic_cast<Parameter *>(&normal_offset) );\r
+//    registerParameter( dynamic_cast<Parameter *>(&tang_offset) );\r
+    registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) );\r
+\r
+    prop_scale.param_set_digits(3);\r
+    prop_scale.param_set_increments(0.01, 0.10);\r
+}\r
+\r
+LPEPathAlongPath::~LPEPathAlongPath()\r
+{\r
+\r
+}\r
+\r
+\r
+Geom::Piecewise<Geom::D2<Geom::SBasis> >\r
+LPEPathAlongPath::doEffect (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)\r
+{\r
+    using namespace Geom;\r
+\r
+/* Much credit should go to jfb and mgsloan of lib2geom development for the code below! */\r
+\r
+    PAPCopyType type = copytype.get_value();\r
+\r
+    Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(Piecewise<D2<SBasis> >(bend_path),2,.1);\r
+    uskeleton = remove_short_cuts(uskeleton,.01);\r
+    Piecewise<D2<SBasis> > n = rot90(derivative(uskeleton));\r
+    n = force_continuity(remove_short_cuts(n,.1));\r
+\r
+    D2<Piecewise<SBasis> > patternd2 = make_cuts_independant(pwd2_in);\r
+    Piecewise<SBasis> x = vertical_pattern.get_value() ? Piecewise<SBasis>(patternd2[1]) : Piecewise<SBasis>(patternd2[0]);\r
+    Piecewise<SBasis> y = vertical_pattern.get_value() ? Piecewise<SBasis>(patternd2[0]) : Piecewise<SBasis>(patternd2[1]);\r
+    Interval pattBnds = bounds_exact(x);\r
+    x -= pattBnds.min();\r
+    Interval pattBndsY = bounds_exact(y);\r
+    y -= (pattBndsY.max()+pattBndsY.min())/2;\r
+\r
+    int nbCopies = int(uskeleton.cuts.back()/pattBnds.extent());\r
+    double scaling = 1;\r
+\r
+    switch(type) {\r
+        case PAPCT_REPEATED:\r
+            break;\r
+\r
+        case PAPCT_SINGLE:\r
+            nbCopies = (nbCopies > 0) ? 1 : 0;\r
+            break;\r
+\r
+        case PAPCT_SINGLE_STRETCHED:\r
+            nbCopies = 1;\r
+            scaling = uskeleton.cuts.back()/pattBnds.extent();\r
+            break;\r
+\r
+        case PAPCT_REPEATED_STRETCHED:\r
+             scaling = uskeleton.cuts.back()/(((double)nbCopies)*pattBnds.extent());\r
+            break;\r
+\r
+        default:\r
+            return pwd2_in;\r
+    };\r
+\r
+    double pattWidth = pattBnds.extent() * scaling;\r
+\r
+    if (scaling != 1.0) {\r
+        x*=scaling;\r
+    }\r
+    if ( scale_y_rel.get_value() ) {\r
+        y*=(scaling*prop_scale);\r
+    } else {\r
+        if (prop_scale != 1.0) y *= prop_scale;\r
+    }\r
+\r
+    double offs = 0;\r
+    Piecewise<D2<SBasis> > output;\r
+    for (int i=0; i<nbCopies; i++){\r
+        output.concat(compose(uskeleton,x+offs)+y*compose(n,x+offs));\r
+        offs+=pattWidth;\r
+    }\r
+    return output;\r
+}\r
+\r
+void\r
+LPEPathAlongPath::resetDefaults(SPItem * item)\r
+{\r
+    using namespace Geom;\r
+\r
+    // set the bend path to run horizontally in the middle of the bounding box of the original path\r
+    Piecewise<D2<SBasis> > pwd2;\r
+    std::vector<Path> temppath = SVGD_to_2GeomPath( SP_OBJECT_REPR(item)->attribute("inkscape:original-d"));\r
+    for (unsigned int i=0; i < temppath.size(); i++) {\r
+        pwd2.concat( temppath[i].toPwSb() );\r
+    }\r
+\r
+    D2<Piecewise<SBasis> > d2pw = make_cuts_independant(pwd2);\r
+    Interval bndsX = bounds_exact(d2pw[0]);\r
+    Interval bndsY = bounds_exact(d2pw[1]);\r
+    Point start(bndsX.min(), (bndsY.max()+bndsY.min())/2);\r
+    Point end(bndsX.max(), (bndsY.max()+bndsY.min())/2);\r
+\r
+    Geom::Path path;\r
+    path.start( start );\r
+    path.appendNew<Geom::LineSegment>( end );\r
+    bend_path.param_set_and_write_new_value( path.toPwSb() );\r
+}\r
+\r
+} // namespace LivePathEffect\r
+} /* namespace Inkscape */\r
+\r
+/*\r
+  Local Variables:\r
+  mode:c++\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
diff --git a/src/live_effects/lpe-pathalongpath.h b/src/live_effects/lpe-pathalongpath.h
new file mode 100644 (file)
index 0000000..8cc2251
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef INKSCAPE_LPE_PATHALONGPATH_H\r
+#define INKSCAPE_LPE_PATHALONGPATH_H\r
+\r
+/*\r
+ * Inkscape::LPEPathAlongPath\r
+ *\r
+* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+\r
+#include "live_effects/effect.h"\r
+#include "live_effects/parameter/path.h"\r
+#include "live_effects/parameter/enum.h"\r
+#include "live_effects/parameter/bool.h"\r
+\r
+namespace Inkscape {\r
+namespace LivePathEffect {\r
+\r
+enum PAPCopyType {\r
+    PAPCT_SINGLE = 0,\r
+    PAPCT_SINGLE_STRETCHED,\r
+    PAPCT_REPEATED,\r
+    PAPCT_REPEATED_STRETCHED,\r
+    PAPCT_END // This must be last\r
+};\r
+\r
+class LPEPathAlongPath : public Effect {\r
+public:\r
+    LPEPathAlongPath(LivePathEffectObject *lpeobject);\r
+    ~LPEPathAlongPath();\r
+\r
+    Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in);\r
+\r
+    void resetDefaults(SPItem * item);\r
+\r
+private:\r
+    PathParam  bend_path;\r
+    EnumParam<PAPCopyType> copytype;\r
+    ScalarParam  prop_scale;\r
+    BoolParam scale_y_rel;\r
+    ScalarParam  spacing;\r
+    ScalarParam  normal_offset;\r
+    ScalarParam  tang_offset;\r
+    BoolParam    vertical_pattern;\r
+\r
+    void on_pattern_pasted();\r
+\r
+    LPEPathAlongPath(const LPEPathAlongPath&);\r
+    LPEPathAlongPath& operator=(const LPEPathAlongPath&);\r
+};\r
+\r
+}; //namespace LivePathEffect\r
+}; //namespace Inkscape\r
+\r
+#endif\r