summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 42e9976)
raw | patch | inline | side by side (parent: 42e9976)
author | johanengelen <johanengelen@users.sourceforge.net> | |
Tue, 30 Oct 2007 22:44:42 +0000 (22:44 +0000) | ||
committer | johanengelen <johanengelen@users.sourceforge.net> | |
Tue, 30 Oct 2007 22:44:42 +0000 (22:44 +0000) |
src/live_effects/Makefile_insert | patch | blob | history | |
src/live_effects/lpe-pathalongpath.cpp | [new file with mode: 0644] | patch | blob |
src/live_effects/lpe-pathalongpath.h | [new file with mode: 0644] | patch | blob |
index fcce5721e11490f81fa2b978c1a9803ad71dadb7..2c9192468cf222c08b268ffd4a83b4584d19e815 100644 (file)
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
--- /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 *>(©type) );\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
--- /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