summaryrefslogtreecommitdiffstats
path: root/src/live_effects
diff options
context:
space:
mode:
Diffstat (limited to 'src/live_effects')
-rw-r--r--src/live_effects/CMakeLists.txt1
-rw-r--r--src/live_effects/Makefile_insert2
-rw-r--r--src/live_effects/effect-enum.h1
-rw-r--r--src/live_effects/effect.cpp6
-rw-r--r--src/live_effects/lpe-circle_3pts.cpp22
-rw-r--r--src/live_effects/lpe-circle_with_radius.cpp20
-rw-r--r--src/live_effects/lpe-powerstroke.cpp262
-rw-r--r--src/live_effects/lpe-powerstroke.h53
-rw-r--r--src/live_effects/parameter/CMakeLists.txt1
-rw-r--r--src/live_effects/parameter/Makefile_insert2
-rw-r--r--src/live_effects/parameter/array.cpp16
-rw-r--r--src/live_effects/parameter/array.h9
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.cpp173
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.h71
14 files changed, 599 insertions, 40 deletions
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt
index adf172247..70e8cbaf8 100644
--- a/src/live_effects/CMakeLists.txt
+++ b/src/live_effects/CMakeLists.txt
@@ -21,6 +21,7 @@ lpeobject-reference.cpp
lpe-patternalongpath.cpp
lpe-perp_bisector.cpp
lpe-perspective_path.cpp
+lpe-powerstroke.cpp
lpe-skeleton.cpp
lpe-sketch.cpp
lpe-spiro.cpp
diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert
index 1cc2e1b69..aacabc2db 100644
--- a/src/live_effects/Makefile_insert
+++ b/src/live_effects/Makefile_insert
@@ -67,6 +67,8 @@ ink_common_sources += \
live_effects/lpe-parallel.h \
live_effects/lpe-copy_rotate.cpp \
live_effects/lpe-copy_rotate.h \
+ live_effects/lpe-powerstroke.cpp \
+ live_effects/lpe-powerstroke.h \
live_effects/lpe-offset.cpp \
live_effects/lpe-offset.h \
live_effects/lpe-ruler.cpp \
diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h
index 6f1004ae5..535cc2564 100644
--- a/src/live_effects/effect-enum.h
+++ b/src/live_effects/effect-enum.h
@@ -48,6 +48,7 @@ enum EffectType {
DYNASTROKE,
RECURSIVE_SKELETON,
EXTRUDE,
+ POWERSTROKE,
INVALID_LPE // This must be last (I made it such that it is not needed anymore I think..., Don't trust on it being last. - johan)
};
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index 6266fade0..9dbd27b50 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -75,6 +75,7 @@
#include "live_effects/lpe-line_segment.h"
#include "live_effects/lpe-recursiveskeleton.h"
#include "live_effects/lpe-extrude.h"
+#include "live_effects/lpe-powerstroke.h"
namespace Inkscape {
@@ -100,6 +101,7 @@ const Util::EnumData<EffectType> LPETypeData[] = {
{PATH_LENGTH, N_("Path length"), "path_length"},
{PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"},
{PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"},
+ {POWERSTROKE, N_("Power stroke"), "powerstroke"},
{COPY_ROTATE, N_("Rotate copies"), "copy_rotate"},
{RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"},
{TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},
@@ -120,6 +122,7 @@ const Util::EnumData<EffectType> LPETypeData[] = {
{ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"},
{SKETCH, N_("Sketch"), "sketch"},
{RULER, N_("Ruler"), "ruler"},
+/* 0.49 */
};
const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
@@ -237,6 +240,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
case EXTRUDE:
neweffect = static_cast<Effect*> ( new LPEExtrude(lpeobj) );
break;
+ case POWERSTROKE:
+ neweffect = static_cast<Effect*> ( new LPEPowerStroke(lpeobj) );
+ break;
default:
g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr);
neweffect = NULL;
diff --git a/src/live_effects/lpe-circle_3pts.cpp b/src/live_effects/lpe-circle_3pts.cpp
index d600ef046..951a3b7c8 100644
--- a/src/live_effects/lpe-circle_3pts.cpp
+++ b/src/live_effects/lpe-circle_3pts.cpp
@@ -17,6 +17,7 @@
// You might need to include other 2geom files. You can add them here:
#include <2geom/path.h>
+#include <2geom/circle.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -30,24 +31,6 @@ LPECircle3Pts::~LPECircle3Pts()
{
}
-static void _circle(Geom::Point center, double radius, std::vector<Geom::Path> &path_out) {
- using namespace Geom;
-
- Geom::Path pb;
-
- D2<SBasis> B;
- Linear bo = Linear(0, 2 * M_PI);
-
- B[0] = cos(bo,4);
- B[1] = sin(bo,4);
-
- B = B * radius + center;
-
- pb.append(SBasisCurve(B));
-
- path_out.push_back(pb);
-}
-
static void _circle3(Geom::Point const &A, Geom::Point const &B, Geom::Point const &C, std::vector<Geom::Path> &path_out) {
using namespace Geom;
@@ -64,7 +47,8 @@ static void _circle3(Geom::Point const &A, Geom::Point const &B, Geom::Point con
Point M = D + v * lambda;
double radius = L2(M - A);
- _circle(M, radius, path_out);
+ Geom::Circle c(M, radius);
+ c.getPath(path_out);
}
std::vector<Geom::Path>
diff --git a/src/live_effects/lpe-circle_with_radius.cpp b/src/live_effects/lpe-circle_with_radius.cpp
index 574a9c004..71611e18b 100644
--- a/src/live_effects/lpe-circle_with_radius.cpp
+++ b/src/live_effects/lpe-circle_with_radius.cpp
@@ -18,6 +18,7 @@
#include <2geom/sbasis.h>
#include <2geom/bezier-to-sbasis.h>
#include <2geom/d2.h>
+#include <2geom/circle.h>
using namespace Geom;
@@ -38,22 +39,6 @@ LPECircleWithRadius::~LPECircleWithRadius()
}
-void _circle(Geom::Point center, double radius, std::vector<Geom::Path> &path_out) {
- Geom::Path pb;
-
- D2<SBasis> B;
- Linear bo = Linear(0, 2 * M_PI);
-
- B[0] = cos(bo,4);
- B[1] = sin(bo,4);
-
- B = B * radius + center;
-
- pb.append(SBasisCurve(B));
-
- path_out.push_back(pb);
-}
-
std::vector<Geom::Path>
LPECircleWithRadius::doEffect_path (std::vector<Geom::Path> const & path_in)
{
@@ -64,7 +49,8 @@ LPECircleWithRadius::doEffect_path (std::vector<Geom::Path> const & path_in)
double radius = Geom::L2(pt - center);
- _circle(center, radius, path_out);
+ Geom::Circle c(center, radius);
+ c.getPath(path_out);
return path_out;
}
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
new file mode 100644
index 000000000..6109ea498
--- /dev/null
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -0,0 +1,262 @@
+#define INKSCAPE_LPE_POWERSTROKE_CPP
+/** \file
+ * @brief PowerStroke LPE implementation. Creates curves with modifiable stroke width.
+ */
+/* Authors:
+ * Johan Engelen <j.b.c.engelen@utwente.nl>
+ *
+ * Copyright (C) 2010 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/lpe-powerstroke.h"
+
+#include "sp-shape.h"
+#include "display/curve.h"
+
+#include <2geom/path.h>
+#include <2geom/piecewise.h>
+#include <2geom/sbasis-geometric.h>
+#include <2geom/transforms.h>
+#include <2geom/bezier-utils.h>
+
+
+/// @TODO Move this to 2geom
+namespace Geom {
+namespace Interpolate {
+
+class Interpolator {
+public:
+ Interpolator() {};
+ virtual ~Interpolator() {};
+
+// virtual Piecewise<D2<SBasis> > interpolateToPwD2Sb(std::vector<Point> points) = 0;
+ virtual Path interpolateToPath(std::vector<Point> points) = 0;
+
+private:
+ Interpolator(const Interpolator&);
+ Interpolator& operator=(const Interpolator&);
+};
+
+class Linear : public Interpolator {
+public:
+ Linear() {};
+ virtual ~Linear() {};
+
+ virtual Path interpolateToPath(std::vector<Point> points) {
+ Path path;
+ path.start( points.at(0) );
+ for (unsigned int i = 1 ; i < points.size(); ++i) {
+ path.appendNew<Geom::LineSegment>(points.at(i));
+ }
+ return path;
+ };
+
+private:
+ Linear(const Linear&);
+ Linear& operator=(const Linear&);
+};
+
+// this class is terrible
+class CubicBezierFit : public Interpolator {
+public:
+ CubicBezierFit() {};
+ virtual ~CubicBezierFit() {};
+
+ virtual Path interpolateToPath(std::vector<Point> points) {
+ unsigned int n_points = points.size();
+ // worst case gives us 2 segment per point
+ int max_segs = 8*n_points;
+ Geom::Point * b = g_new(Geom::Point, max_segs);
+ Geom::Point * points_array = g_new(Geom::Point, 4*n_points);
+ for (unsigned i = 0; i < n_points; ++i) {
+ points_array[i] = points.at(i);
+ }
+
+ double tolerance_sq = 0; // this value is just a random guess
+
+ int const n_segs = Geom::bezier_fit_cubic_r(b, points_array, n_points,
+ tolerance_sq, max_segs);
+
+ Geom::Path fit;
+ if ( n_segs > 0)
+ {
+ fit.start(b[0]);
+ for (int c = 0; c < n_segs; c++) {
+ fit.appendNew<Geom::CubicBezier>(b[4*c+1], b[4*c+2], b[4*c+3]);
+ }
+ }
+ g_free(b);
+ g_free(points_array);
+ return fit;
+ };
+
+private:
+ CubicBezierFit(const CubicBezierFit&);
+ CubicBezierFit& operator=(const CubicBezierFit&);
+};
+
+/// @todo invent name for this class
+class CubicBezierJohan : public Interpolator {
+public:
+ CubicBezierJohan() {};
+ virtual ~CubicBezierJohan() {};
+
+ virtual Path interpolateToPath(std::vector<Point> points) {
+ Path fit;
+ fit.start(points.at(0));
+ for (unsigned int i = 1; i < points.size(); ++i) {
+ Point p0 = points.at(i-1);
+ Point p1 = points.at(i);
+ Point dx = Point(p1[X] - p0[X], 0);
+ fit.appendNew<CubicBezier>(p0+0.2*dx, p1-0.2*dx, p1);
+ }
+ return fit;
+ };
+
+private:
+ CubicBezierJohan(const CubicBezierJohan&);
+ CubicBezierJohan& operator=(const CubicBezierJohan&);
+};
+
+} //namespace Interpolate
+} //namespace Geom
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) :
+ Effect(lpeobject),
+ offset_points(_("Offset points"), _("Offset points"), "offset_points", &wr, this),
+ sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve."), "sort_points", &wr, this, true)
+{
+ show_orig_path = true;
+
+ /// @todo offset_points are initialized with empty path, is that bug-save?
+
+ registerParameter( dynamic_cast<Parameter *>(&offset_points) );
+ registerParameter( dynamic_cast<Parameter *>(&sort_points) );
+}
+
+LPEPowerStroke::~LPEPowerStroke()
+{
+
+}
+
+
+void
+LPEPowerStroke::doOnApply(SPLPEItem *lpeitem)
+{
+ std::vector<Geom::Point> points;
+ Geom::Path::size_type size = SP_SHAPE(lpeitem)->curve->get_pathvector().front().size_open();
+ points.push_back( Geom::Point(0,0) );
+ points.push_back( Geom::Point(0.5*size,0) );
+ points.push_back( Geom::Point(size,0) );
+ offset_points.param_set_and_write_new_value(points);
+}
+
+static bool compare_offsets (Geom::Point first, Geom::Point second)
+{
+ return first[Geom::X] < second[Geom::X];
+}
+
+
+Geom::Piecewise<Geom::D2<Geom::SBasis> >
+LPEPowerStroke::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
+{
+ using namespace Geom;
+
+ offset_points.set_pwd2(pwd2_in);
+
+ Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in));
+ Piecewise<D2<SBasis> > n = rot90(der);
+ offset_points.set_pwd2_normal(n);
+
+ // see if we should treat the path as being closed.
+ bool closed_path = false;
+ if ( are_near(pwd2_in.firstValue(), pwd2_in.lastValue()) ) {
+ closed_path = true;
+ }
+
+ Piecewise<D2<SBasis> > output;
+ if (!closed_path) {
+ // perhaps use std::list instead of std::vector?
+ std::vector<Geom::Point> ts(offset_points.data().size() + 2);
+ // first and last point coincide with input path (for now at least)
+ ts.front() = Point(pwd2_in.domain().min(),0);
+ ts.back() = Point(pwd2_in.domain().max(),0);
+ for (unsigned int i = 0; i < offset_points.data().size(); ++i) {
+ ts.at(i+1) = offset_points.data().at(i);
+ }
+
+ if (sort_points) {
+ sort(ts.begin(), ts.end(), compare_offsets);
+ }
+
+ // create stroke path where points (x,y) := (t, offset)
+ Geom::Interpolate::CubicBezierJohan interpolator;
+ Path strokepath = interpolator.interpolateToPath(ts);
+ Path mirroredpath = strokepath.reverse() * Geom::Scale(1,-1);
+
+ strokepath.append(mirroredpath, Geom::Path::STITCH_DISCONTINUOUS);
+ strokepath.close();
+
+ D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb());
+ Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]);
+ Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]);
+
+ output = compose(pwd2_in,x) + y*compose(n,x);
+ } else {
+ // path is closed
+
+ // perhaps use std::list instead of std::vector?
+ std::vector<Geom::Point> ts = offset_points.data();
+ if (sort_points) {
+ sort(ts.begin(), ts.end(), compare_offsets);
+ }
+ // add extra points for interpolation between first and last point
+ Point first_point = ts.front();
+ Point last_point = ts.back();
+ ts.insert(ts.begin(), last_point - Point(pwd2_in.domain().extent() ,0));
+ ts.push_back( first_point + Point(pwd2_in.domain().extent() ,0) );
+ // create stroke path where points (x,y) := (t, offset)
+ Geom::Interpolate::CubicBezierJohan interpolator;
+ Path strokepath = interpolator.interpolateToPath(ts);
+
+ // output 2 separate paths
+ D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb());
+ Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]);
+ Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]);
+ // find time values for which x lies outside path domain
+ // and only take portion of x and y that lies within those time values
+ std::vector< double > rtsmin = roots (x - pwd2_in.domain().min());
+ std::vector< double > rtsmax = roots (x - pwd2_in.domain().max());
+ if ( !rtsmin.empty() && !rtsmax.empty() ) {
+ x = portion(x, rtsmin.at(0), rtsmax.at(0));
+ y = portion(y, rtsmin.at(0), rtsmax.at(0));
+ }
+ output = compose(pwd2_in,x) + y*compose(n,x);
+ x = reverse(x);
+ y = reverse(y);
+ output.concat(compose(pwd2_in,x) - y*compose(n,x));
+ }
+
+ return output;
+}
+
+/* ######################## */
+
+} //namespace LivePathEffect
+} /* namespace Inkscape */
+
+/*
+ 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 :
diff --git a/src/live_effects/lpe-powerstroke.h b/src/live_effects/lpe-powerstroke.h
new file mode 100644
index 000000000..6c208fda4
--- /dev/null
+++ b/src/live_effects/lpe-powerstroke.h
@@ -0,0 +1,53 @@
+/** @file
+ * @brief PowerStroke LPE effect, see lpe-powerstroke.cpp.
+ */
+/* Authors:
+ * Johan Engelen <j.b.c.engelen@utwente.nl>
+ *
+ * Copyright (C) 2010 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef INKSCAPE_LPE_POWERSTROKE_H
+#define INKSCAPE_LPE_POWERSTROKE_H
+
+#include "live_effects/effect.h"
+#include "live_effects/parameter/bool.h"
+#include "live_effects/parameter/powerstrokepointarray.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+class LPEPowerStroke : public Effect {
+public:
+ LPEPowerStroke(LivePathEffectObject *lpeobject);
+ virtual ~LPEPowerStroke();
+
+ virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
+
+ virtual void doOnApply(SPLPEItem *lpeitem);
+
+private:
+ PowerStrokePointArrayParam offset_points;
+ BoolParam sort_points;
+
+ LPEPowerStroke(const LPEPowerStroke&);
+ LPEPowerStroke& operator=(const LPEPowerStroke&);
+};
+
+} //namespace LivePathEffect
+} //namespace Inkscape
+
+#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:encoding=utf-8:textwidth=99 :
diff --git a/src/live_effects/parameter/CMakeLists.txt b/src/live_effects/parameter/CMakeLists.txt
index 2fa0d5bc6..8657b2bec 100644
--- a/src/live_effects/parameter/CMakeLists.txt
+++ b/src/live_effects/parameter/CMakeLists.txt
@@ -5,6 +5,7 @@ parameter.cpp
path.cpp
path-reference.cpp
point.cpp
+powerstrokepointarray.cpp
random.cpp
text.cpp
unit.cpp
diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert
index 74b166e8b..99cd88d62 100644
--- a/src/live_effects/parameter/Makefile_insert
+++ b/src/live_effects/parameter/Makefile_insert
@@ -16,6 +16,8 @@ ink_common_sources += \
live_effects/parameter/path-reference.h \
live_effects/parameter/path.cpp \
live_effects/parameter/path.h \
+ live_effects/parameter/powerstrokepointarray.cpp \
+ live_effects/parameter/powerstrokepointarray.h \
live_effects/parameter/text.cpp \
live_effects/parameter/text.h \
live_effects/parameter/unit.cpp \
diff --git a/src/live_effects/parameter/array.cpp b/src/live_effects/parameter/array.cpp
index c576bedd5..d1c30edf7 100644
--- a/src/live_effects/parameter/array.cpp
+++ b/src/live_effects/parameter/array.cpp
@@ -12,6 +12,7 @@
#include "svg/stringstream.h"
#include <2geom/coord.h>
+#include <2geom/point.h>
namespace Inkscape {
@@ -35,6 +36,21 @@ ArrayParam<float>::readsvg(const gchar * str)
return newx;
}
+template <>
+Geom::Point
+ArrayParam<Geom::Point>::readsvg(const gchar * str)
+{
+ gchar ** strarray = g_strsplit(str, ",", 2);
+ double newx, newy;
+ unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
+ success += sp_svg_number_read_d(strarray[1], &newy);
+ g_strfreev (strarray);
+ if (success == 2) {
+ return Geom::Point(newx, newy);
+ }
+ return Geom::Point(Geom::infinity(),Geom::infinity());
+}
+
} /* namespace LivePathEffect */
} /* namespace Inkscape */
diff --git a/src/live_effects/parameter/array.h b/src/live_effects/parameter/array.h
index e5f230111..89c344594 100644
--- a/src/live_effects/parameter/array.h
+++ b/src/live_effects/parameter/array.h
@@ -85,10 +85,7 @@ public:
g_free(str);
}
-private:
- ArrayParam(const ArrayParam&);
- ArrayParam& operator=(const ArrayParam&);
-
+protected:
std::vector<StorageType> _vector;
size_t _default_size;
@@ -103,6 +100,10 @@ private:
}
StorageType readsvg(const gchar * str);
+
+private:
+ ArrayParam(const ArrayParam&);
+ ArrayParam& operator=(const ArrayParam&);
};
diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp
new file mode 100644
index 000000000..c20980193
--- /dev/null
+++ b/src/live_effects/parameter/powerstrokepointarray.cpp
@@ -0,0 +1,173 @@
+#define INKSCAPE_LIVEPATHEFFECT_POWERSTROKE_POINT_ARRAY_CPP
+
+/*
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/parameter/powerstrokepointarray.h"
+
+#include "live_effects/effect.h"
+#include "svg/svg.h"
+#include "svg/stringstream.h"
+#include "knotholder.h"
+#include "sp-lpe-item.h"
+
+#include <2geom/piecewise.h>
+#include <2geom/sbasis-geometric.h>
+
+// needed for on-canvas editting:
+#include "desktop.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+PowerStrokePointArrayParam::PowerStrokePointArrayParam( const Glib::ustring& label, const Glib::ustring& tip,
+ const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
+ Effect* effect, const gchar *htip)
+ : ArrayParam<Geom::Point>(label, tip, key, wr, effect, 0)
+{
+ knot_shape = SP_KNOT_SHAPE_DIAMOND;
+ knot_mode = SP_KNOT_MODE_XOR;
+ knot_color = 0xff00ff00;
+ handle_tip = g_strdup(htip);
+}
+
+PowerStrokePointArrayParam::~PowerStrokePointArrayParam()
+{
+ if (handle_tip)
+ g_free(handle_tip);
+}
+
+Gtk::Widget *
+PowerStrokePointArrayParam::param_newWidget(Gtk::Tooltips * /*tooltips*/)
+{
+ return NULL;
+/*
+ Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = Gtk::manage(
+ new Inkscape::UI::Widget::RegisteredTransformedPoint( param_label,
+ param_tooltip,
+ param_key,
+ *param_wr,
+ param_effect->getRepr(),
+ param_effect->getSPDoc() ) );
+ // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP)
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Geom::Matrix transf = desktop->doc2dt();
+ pointwdg->setTransform(transf);
+ pointwdg->setValue( *this );
+ pointwdg->clearProgrammatically();
+ pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter"));
+
+ Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() );
+ static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true);
+ static_cast<Gtk::HBox*>(hbox)->show_all_children();
+
+ return dynamic_cast<Gtk::Widget *> (hbox);
+*/
+}
+
+
+void
+PowerStrokePointArrayParam::param_transform_multiply(Geom::Matrix const& postmul, bool /*set*/)
+{
+// param_set_and_write_new_value( (*this) * postmul );
+}
+
+
+void
+PowerStrokePointArrayParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color)
+{
+ knot_shape = shape;
+ knot_mode = mode;
+ knot_color = color;
+}
+
+class PowerStrokePointArrayParamKnotHolderEntity : public LPEKnotHolderEntity {
+public:
+ PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index);
+ virtual ~PowerStrokePointArrayParamKnotHolderEntity() {}
+
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
+ virtual Geom::Point knot_get();
+ virtual void knot_click(guint state);
+
+private:
+ PowerStrokePointArrayParam *_pparam;
+ unsigned int _index;
+};
+
+PowerStrokePointArrayParamKnotHolderEntity::PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index)
+ : _pparam(p),
+ _index(index)
+{
+}
+
+void
+PowerStrokePointArrayParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint /*state*/)
+{
+/// @todo how about item transforms???
+ using namespace Geom;
+ Piecewise<D2<SBasis> > const & pwd2 = _pparam->get_pwd2();
+ Piecewise<D2<SBasis> > const & n = _pparam->get_pwd2_normal();
+
+ Geom::Point const s = snap_knot_position(p);
+ double t = nearest_point(s, pwd2);
+ double offset = dot(s - pwd2.valueAt(t), n.valueAt(t));
+ _pparam->_vector.at(_index) = Geom::Point(t, offset);
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+}
+
+Geom::Point
+PowerStrokePointArrayParamKnotHolderEntity::knot_get()
+{
+ using namespace Geom;
+ Piecewise<D2<SBasis> > const & pwd2 = _pparam->get_pwd2();
+ Piecewise<D2<SBasis> > const & n = _pparam->get_pwd2_normal();
+
+ Point offset_point = _pparam->_vector.at(_index);
+
+ Point canvas_point = pwd2.valueAt(offset_point[X]) + offset_point[Y] * n.valueAt(offset_point[X]);
+ return canvas_point;
+}
+
+void
+PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state)
+{
+ g_print ("This is the %d handle associated to parameter '%s'\n", _index, _pparam->param_key.c_str());
+
+ if (state & GDK_CONTROL_MASK) {
+ std::vector<Geom::Point> & vec = _pparam->_vector;
+ vec.insert(vec.begin() + _index, 1, vec.at(_index));
+ _pparam->param_set_and_write_new_value(vec);
+ g_print ("Added handle %d associated to parameter '%s'\n", _index, _pparam->param_key.c_str());
+ /// @todo this BUGS ! the knot stuff should be reloaded when adding a new node!
+ }
+}
+
+void
+PowerStrokePointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+{
+ for (unsigned int i = 0; i < _vector.size(); ++i) {
+ PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(this, i);
+ e->create(desktop, item, knotholder, handle_tip, knot_shape, knot_mode, knot_color);
+ knotholder->add(e);
+ }
+}
+
+} /* namespace LivePathEffect */
+
+} /* namespace Inkscape */
+
+/*
+ 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 :
diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h
new file mode 100644
index 000000000..06d406dfe
--- /dev/null
+++ b/src/live_effects/parameter/powerstrokepointarray.h
@@ -0,0 +1,71 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_POWERSTROKE_POINT_ARRAY_H
+#define INKSCAPE_LIVEPATHEFFECT_POWERSTROKE_POINT_ARRAY_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ *
+* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib/gtypes.h>
+#include <2geom/point.h>
+
+#include <gtkmm/tooltips.h>
+
+#include "live_effects/parameter/array.h"
+
+#include "knot-holder-entity.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class PowerStrokePointArrayParamKnotHolderEntity;
+
+class PowerStrokePointArrayParam : public ArrayParam<Geom::Point> {
+public:
+ PowerStrokePointArrayParam( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect,
+ const gchar *handle_tip = NULL); // tip for automatically associated on-canvas handle
+ virtual ~PowerStrokePointArrayParam();
+
+ virtual Gtk::Widget * param_newWidget(Gtk::Tooltips * tooltips);
+
+ virtual void param_transform_multiply(Geom::Matrix const& /*postmul*/, bool /*set*/);
+
+ void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
+
+ virtual bool providesKnotHolderEntities() { return true; }
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+
+ void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { last_pwd2 = pwd2_in; }
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2() { return last_pwd2; }
+ void set_pwd2_normal(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { last_pwd2_normal = pwd2_in; }
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2_normal() { return last_pwd2_normal; }
+
+ friend class PowerStrokePointArrayParamKnotHolderEntity;
+
+private:
+ PowerStrokePointArrayParam(const PowerStrokePointArrayParam&);
+ PowerStrokePointArrayParam& operator=(const PowerStrokePointArrayParam&);
+
+ SPKnotShapeType knot_shape;
+ SPKnotModeType knot_mode;
+ guint32 knot_color;
+ gchar *handle_tip;
+
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2;
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal;
+};
+
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif