diff options
Diffstat (limited to 'src/live_effects')
| -rw-r--r-- | src/live_effects/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/live_effects/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/live_effects/effect-enum.h | 1 | ||||
| -rw-r--r-- | src/live_effects/effect.cpp | 6 | ||||
| -rw-r--r-- | src/live_effects/lpe-circle_3pts.cpp | 22 | ||||
| -rw-r--r-- | src/live_effects/lpe-circle_with_radius.cpp | 20 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 262 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke.h | 53 | ||||
| -rw-r--r-- | src/live_effects/parameter/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/live_effects/parameter/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/live_effects/parameter/array.cpp | 16 | ||||
| -rw-r--r-- | src/live_effects/parameter/array.h | 9 | ||||
| -rw-r--r-- | src/live_effects/parameter/powerstrokepointarray.cpp | 173 | ||||
| -rw-r--r-- | src/live_effects/parameter/powerstrokepointarray.h | 71 |
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 |
