diff options
| author | Ted Gould <ted@gould.cx> | 2008-11-21 05:24:08 +0000 |
|---|---|---|
| committer | Ted Gould <ted@canonical.com> | 2008-11-21 05:24:08 +0000 |
| commit | 44a3a78fb6a3863c0c7f3c1193837337e68a67e4 (patch) | |
| tree | 1722ee5ec6f88c881cd4124923354b3c1311501b /src/live_effects | |
| parent | Merge from trunk (diff) | |
| download | inkscape-44a3a78fb6a3863c0c7f3c1193837337e68a67e4.tar.gz inkscape-44a3a78fb6a3863c0c7f3c1193837337e68a67e4.zip | |
Merge from fe-moved
(bzr r6891)
Diffstat (limited to 'src/live_effects')
33 files changed, 1475 insertions, 629 deletions
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 98875a5a2..89b7b9e3a 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -11,6 +11,7 @@ lpe-gears.cpp lpegroupbbox.cpp lpe-interpolate.cpp lpe-knot.cpp +lpe-hatches.cpp lpe-lattice.cpp lpe-mirror_symmetry.cpp lpeobject.cpp diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 3b136d204..1bb001778 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -8,6 +8,7 @@ live_effects/clean: live_effects_liblive_effects_a_SOURCES = \ live_effects/effect.cpp \ live_effects/effect.h \ + live_effects/effect-enum.h \ live_effects/lpeobject.cpp \ live_effects/lpeobject.h \ live_effects/lpegroupbbox.cpp \ @@ -26,6 +27,8 @@ live_effects_liblive_effects_a_SOURCES = \ live_effects/lpe-knot.h \ live_effects/lpe-vonkoch.cpp \ live_effects/lpe-vonkoch.h \ + live_effects/lpe-hatches.cpp \ + live_effects/lpe-hatches.h \ live_effects/lpe-curvestitch.cpp \ live_effects/lpe-curvestitch.h \ live_effects/lpe-constructgrid.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h new file mode 100644 index 000000000..1e82954f8 --- /dev/null +++ b/src/live_effects/effect-enum.h @@ -0,0 +1,72 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_ENUM_H +#define INKSCAPE_LIVEPATHEFFECT_ENUM_H + +/* + * Inkscape::LivePathEffect::EffectType + * +* Copyright (C) Johan Engelen 2008 <j.b.c.engelen@utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "util/enums.h" + +#define LPE_ENABLE_TEST_EFFECTS + +namespace Inkscape { +namespace LivePathEffect { + +enum EffectType { + BEND_PATH = 0, + PATTERN_ALONG_PATH, + FREEHAND_SHAPE, + SKETCH, + HATCHES, + VONKOCH, + KNOT, +#ifdef LPE_ENABLE_TEST_EFFECTS + DOEFFECTSTACK_TEST, +#endif + GEARS, + CURVE_STITCH, + CIRCLE_WITH_RADIUS, + PERSPECTIVE_PATH, + SPIRO, + LATTICE, + ENVELOPE, + CONSTRUCT_GRID, + PERP_BISECTOR, + TANGENT_TO_CURVE, + MIRROR_SYMMETRY, + CIRCLE_3PTS, + ANGLE_BISECTOR, + PARALLEL, + COPY_ROTATE, + OFFSET, + RULER, + BOOLOPS, + INTERPOLATE, + TEXT_LABEL, + PATH_LENGTH, + LINE_SEGMENT, + INVALID_LPE // This must be last +}; + +extern const Util::EnumData<EffectType> LPETypeData[]; /// defined in effect.cpp +extern const Util::EnumDataConverter<EffectType> LPETypeConverter; /// defined in effect.cpp + +} //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 : diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index a04100cd3..bb5f0c554 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -42,6 +42,7 @@ #include "live_effects/lpe-sketch.h" #include "live_effects/lpe-vonkoch.h" #include "live_effects/lpe-knot.h" +#include "live_effects/lpe-hatches.h" #include "live_effects/lpe-test-doEffect-stack.h" #include "live_effects/lpe-gears.h" #include "live_effects/lpe-curvestitch.h" @@ -99,6 +100,7 @@ const Util::EnumData<EffectType> LPETypeData[] = { {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, {RULER, N_("Ruler"), "ruler"}, {SKETCH, N_("Sketch"), "sketch"}, + {HATCHES, N_("Hatches"), "hatches"}, {SPIRO, N_("Spiro spline"), "spiro"}, {CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"}, {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, @@ -137,6 +139,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case SKETCH: neweffect = static_cast<Effect*> ( new LPESketch(lpeobj) ); break; + case HATCHES: + neweffect = static_cast<Effect*> ( new LPEHatches(lpeobj) ); + break; case VONKOCH: neweffect = static_cast<Effect*> ( new LPEVonKoch(lpeobj) ); break; @@ -663,10 +668,9 @@ Effect::providesKnotholder() if (kh_entity_vector.size() > 0) return true; - // otherwise: are there any PointParams? + // otherwise: are there any parameters that have knotholderentities? for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) { -// if ( Inkscape::LivePathEffect::PointParam *pointparam = dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p) ) { - if (dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p)) { + if ((*p)->providesKnotHolderEntities()) { return true; } } diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 8dd1354e2..ae42e358c 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -16,15 +16,13 @@ #include <2geom/path.h> #include <2geom/forward.h> #include "ui/widget/registry.h" -#include "util/enums.h" #include "sp-lpe-item.h" #include "knotholder.h" #include "parameter/bool.h" +#include "effect-enum.h" #define LPE_CONVERSION_TOLERANCE 0.01 // FIXME: find good solution for this. -#define LPE_ENABLE_TEST_EFFECTS - struct SPDocument; struct SPDesktop; struct SPItem; @@ -49,44 +47,6 @@ namespace NodePath { namespace LivePathEffect { -enum EffectType { - BEND_PATH = 0, - PATTERN_ALONG_PATH, - FREEHAND_SHAPE, - SKETCH, - VONKOCH, - KNOT, -#ifdef LPE_ENABLE_TEST_EFFECTS - DOEFFECTSTACK_TEST, -#endif - GEARS, - CURVE_STITCH, - CIRCLE_WITH_RADIUS, - PERSPECTIVE_PATH, - SPIRO, - LATTICE, - ENVELOPE, - CONSTRUCT_GRID, - PERP_BISECTOR, - TANGENT_TO_CURVE, - MIRROR_SYMMETRY, - CIRCLE_3PTS, - ANGLE_BISECTOR, - PARALLEL, - COPY_ROTATE, - OFFSET, - RULER, - BOOLOPS, - INTERPOLATE, - TEXT_LABEL, - PATH_LENGTH, - LINE_SEGMENT, - INVALID_LPE // This must be last -}; - -extern const Util::EnumData<EffectType> LPETypeData[]; -extern const Util::EnumDataConverter<EffectType> LPETypeConverter; - enum LPEPathFlashType { SUPPRESS_FLASH, // PERMANENT_FLASH, diff --git a/src/live_effects/lpe-circle_with_radius.cpp b/src/live_effects/lpe-circle_with_radius.cpp index 8b169af3c..574a9c004 100644 --- a/src/live_effects/lpe-circle_with_radius.cpp +++ b/src/live_effects/lpe-circle_with_radius.cpp @@ -1,20 +1,11 @@ -#define INKSCAPE_LPE_CIRCLE_WITH_RADIUS_CPP -/** \file - * LPE <circle_with_radius> implementation, used as an example for a base starting class - * when implementing new LivePathEffects. - * - * In vi, three global search-and-replaces will let you rename everything - * in this and the .h file: - * - * :%s/CIRCLE_WITH_RADIUS/YOURNAME/g - * :%s/CircleWithRadius/Yourname/g - * :%s/circle_with_radius/yourname/g +/** @file + * @brief LPE effect that draws a circle based on two points and a radius + * - implementation */ -/* - * Authors: - * Johan Engelen -* -* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> +/* Authors: + * Johan Engelen <j.b.c.engelen@utwente.nl> + * + * Copyright (C) 2007 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -106,4 +97,4 @@ LPECircleWithRadius::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & p fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/live_effects/lpe-circle_with_radius.h b/src/live_effects/lpe-circle_with_radius.h index 19330eb33..2b9494875 100644 --- a/src/live_effects/lpe-circle_with_radius.h +++ b/src/live_effects/lpe-circle_with_radius.h @@ -1,19 +1,17 @@ -#ifndef INKSCAPE_LPE_CIRCLE_WITH_RADIUS_H -#define INKSCAPE_LPE_CIRCLE_WITH_RADIUS_H - -/** \file - * LPE <circle_with_radius> implementation, see lpe-circle_with_radius.cpp. +/** @file + * @brief LPE effect that draws a circle based on two points and a radius */ - -/* - * Authors: - * Johan Engelen -* -* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> +/* Authors: + * Johan Engelen <j.b.c.engelen@utwente.nl> + * + * Copyright (C) 2007 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef INKSCAPE_LPE_CIRCLE_WITH_RADIUS_H +#define INKSCAPE_LPE_CIRCLE_WITH_RADIUS_H + #include "live_effects/effect.h" #include "live_effects/parameter/parameter.h" #include "live_effects/parameter/path.h" @@ -43,3 +41,14 @@ private: } //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/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp index 4404620be..2716e45d7 100644 --- a/src/live_effects/lpe-curvestitch.cpp +++ b/src/live_effects/lpe-curvestitch.cpp @@ -79,10 +79,13 @@ LPECurveStitch::doEffect_path (std::vector<Geom::Path> const & path_in) endpoint_spacing_variation.resetRandomizer(); D2<Piecewise<SBasis> > stroke = make_cuts_independent(strokepath.get_pwd2()); - Interval bndsStroke = bounds_exact(stroke[0]); - gdouble scaling = bndsStroke.max() - bndsStroke.min(); - Interval bndsStrokeY = bounds_exact(stroke[1]); - Point stroke_origin(bndsStroke.min(), (bndsStrokeY.max()+bndsStrokeY.min())/2); + OptInterval bndsStroke = bounds_exact(stroke[0]); + OptInterval bndsStrokeY = bounds_exact(stroke[1]); + if (!bndsStroke && !bndsStrokeY) { + return path_in; + } + gdouble scaling = bndsStroke->max() - bndsStroke->min(); + Point stroke_origin(bndsStroke->min(), (bndsStrokeY->max()+bndsStrokeY->min())/2); std::vector<Geom::Path> path_out; @@ -163,18 +166,22 @@ LPECurveStitch::resetDefaults(SPItem * item) pwd2.concat( temppath[i].toPwSb() ); } D2<Piecewise<SBasis> > d2pw = make_cuts_independent(pwd2); - Interval bndsX = bounds_exact(d2pw[0]); - Interval bndsY = bounds_exact(d2pw[1]); - Point start(bndsX.min(), (bndsY.max()+bndsY.min())/2); - Point end(bndsX.max(), (bndsY.max()+bndsY.min())/2); - - if ( !Geom::are_near(start,end) ) { - Geom::Path path; - path.start( start ); - path.appendNew<Geom::LineSegment>( end ); - strokepath.set_new_value( path.toPwSb(), true ); + OptInterval bndsX = bounds_exact(d2pw[0]); + OptInterval bndsY = bounds_exact(d2pw[1]); + if (bndsX && bndsY) { + Point start(bndsX->min(), (bndsY->max()+bndsY->min())/2); + Point end(bndsX->max(), (bndsY->max()+bndsY->min())/2); + if ( !Geom::are_near(start,end) ) { + Geom::Path path; + path.start( start ); + path.appendNew<Geom::LineSegment>( end ); + strokepath.set_new_value( path.toPwSb(), true ); + } else { + // bounding box is too small to make decent path. set to default default. :-) + strokepath.param_set_and_write_default(); + } } else { - // bounding box is too small to make decent path. set to default default. :-) + // bounding box is non-existent. set to default default. :-) strokepath.param_set_and_write_default(); } } diff --git a/src/live_effects/lpe-hatches.cpp b/src/live_effects/lpe-hatches.cpp new file mode 100644 index 000000000..2205d91f3 --- /dev/null +++ b/src/live_effects/lpe-hatches.cpp @@ -0,0 +1,593 @@ +#define INKSCAPE_LPE_HATCHES_CPP
+/** \file
+ * LPE Curve Stitching implementation, used as an example for a base starting class
+ * when implementing new LivePathEffects.
+ *
+ */
+/*
+ * Authors:
+ * JF Barraud.
+*
+* 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/lpe-hatches.h"
+
+#include "sp-item.h"
+#include "sp-path.h"
+#include "svg/svg.h"
+#include "xml/repr.h"
+
+#include <2geom/path.h>
+#include <2geom/piecewise.h>
+#include <2geom/sbasis.h>
+#include <2geom/sbasis-math.h>
+#include <2geom/sbasis-geometric.h>
+#include <2geom/bezier-to-sbasis.h>
+#include <2geom/sbasis-to-bezier.h>
+#include <2geom/d2.h>
+#include <2geom/matrix.h>
+
+#include "ui/widget/scalar.h"
+#include "libnr/nr-values.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+using namespace Geom;
+
+//------------------------------------------------
+// Some goodies to navigate through curve's levels.
+//------------------------------------------------
+struct LevelCrossing{
+ Point pt;
+ double t;
+ bool sign;
+ bool used;
+ std::pair<unsigned,unsigned> next_on_curve;
+ std::pair<unsigned,unsigned> prev_on_curve;
+};
+struct LevelCrossingOrder {
+ bool operator()(LevelCrossing a, LevelCrossing b) {
+ return a.pt[Y] < b.pt[Y];
+ }
+};
+struct LevelCrossingInfo{
+ double t;
+ unsigned level;
+ unsigned idx;
+};
+struct LevelCrossingInfoOrder {
+ bool operator()(LevelCrossingInfo a, LevelCrossingInfo b) {
+ return a.t < b.t;
+ }
+};
+
+typedef std::vector<LevelCrossing> LevelCrossings;
+
+std::vector<double>
+discontinuities(Piecewise<D2<SBasis> > const &f){
+ std::vector<double> result;
+ if (f.size()==0) return result;
+ result.push_back(f.cuts[0]);
+ Point prev_pt = f.segs[0].at1();
+ //double old_t = f.cuts[0];
+ for(unsigned i=1; i<f.size(); i++){
+ if ( f.segs[i].at0()!=prev_pt){
+ result.push_back(f.cuts[i]);
+ //old_t = f.cuts[i];
+ //assert(f.segs[i-1].at1()==f.valueAt(old_t));
+ }
+ prev_pt = f.segs[i].at1();
+ }
+ result.push_back(f.cuts.back());
+ //assert(f.segs.back().at1()==f.valueAt(old_t));
+ return result;
+}
+
+class LevelsCrossings: public std::vector<LevelCrossings>{
+public:
+ LevelsCrossings():std::vector<LevelCrossings>(){};
+ LevelsCrossings(std::vector<std::vector<double> > const ×,
+ Piecewise<D2<SBasis> > const &f,
+ Piecewise<SBasis> const &dx){
+
+ for (unsigned i=0; i<times.size(); i++){
+ LevelCrossings lcs;
+ for (unsigned j=0; j<times[i].size(); j++){
+ LevelCrossing lc;
+ lc.pt = f.valueAt(times[i][j]);
+ lc.t = times[i][j];
+ lc.sign = ( dx.valueAt(times[i][j])>0 );
+ lc.used = false;
+ lcs.push_back(lc);
+ }
+ std::sort(lcs.begin(), lcs.end(), LevelCrossingOrder());
+ push_back(lcs);
+ }
+ //Now create time ordering.
+ std::vector<LevelCrossingInfo>temp;
+ for (unsigned i=0; i<size(); i++){
+ for (unsigned j=0; j<(*this)[i].size(); j++){
+ LevelCrossingInfo elem;
+ elem.t = (*this)[i][j].t;
+ elem.level = i;
+ elem.idx = j;
+ temp.push_back(elem);
+ }
+ }
+ std::sort(temp.begin(),temp.end(),LevelCrossingInfoOrder());
+ std::vector<double> jumps = discontinuities(f);
+ unsigned jump_idx = 0;
+ unsigned first_in_comp = 0;
+ for (unsigned i=0; i<temp.size(); i++){
+ unsigned lvl = temp[i].level, idx = temp[i].idx;
+ if ( i == temp.size()-1 || temp[i+1].t > jumps[jump_idx+1]){
+ std::pair<unsigned,unsigned>next_data(temp[first_in_comp].level,temp[first_in_comp].idx);
+ (*this)[lvl][idx].next_on_curve = next_data;
+ first_in_comp = i+1;
+ jump_idx += 1;
+ }else{
+ std::pair<unsigned,unsigned> next_data(temp[i+1].level,temp[i+1].idx);
+ (*this)[lvl][idx].next_on_curve = next_data;
+ }
+ }
+
+ for (unsigned i=0; i<size(); i++){
+ for (unsigned j=0; j<(*this)[i].size(); j++){
+ std::pair<unsigned,unsigned> next = (*this)[i][j].next_on_curve;
+ (*this)[next.first][next.second].prev_on_curve = std::pair<unsigned,unsigned>(i,j);
+ }
+ }
+#if 0
+ std::cout<<"\n";
+ for (unsigned i=0; i<temp.size()-1; i++){
+ std::cout<<temp[i].level<<","<<temp[i].idx<<" -> ";
+ }
+ std::cout<<"\n";
+ for (unsigned i=0; i<size(); i++){
+ for (unsigned j=0; j<(*this)[i].size(); j++){
+ std::cout<<"level:"<<i<<", idx:"<<j<<" - ";
+ std::cout<<"next:"<<(*this)[i][j].next_on_curve.first<<",";
+ std::cout<<(*this)[i][j].next_on_curve.second<<" - ";
+ std::cout<<"prev:"<<(*this)[i][j].prev_on_curve.first<<",";
+ std::cout<<(*this)[i][j].prev_on_curve.second<<"\n";
+ }
+ }
+#endif
+ }
+
+ void findFirstUnused(unsigned &level, unsigned &idx){
+ level = size();
+ idx = 0;
+ for (unsigned i=0; i<size(); i++){
+ for (unsigned j=0; j<(*this)[i].size(); j++){
+ if (!(*this)[i][j].used){
+ level = i;
+ idx = j;
+ return;
+ }
+ }
+ }
+ }
+ //set indexes to point to the next point in the "snake walk"
+ //follow_level's meaning:
+ // 0=yes upward
+ // 1=no, last move was upward,
+ // 2=yes downward
+ // 3=no, last move was downward.
+ void step(unsigned &level, unsigned &idx, int &direction){
+ if ( direction % 2 == 0 ){
+ if (direction == 0) {
+ if ( idx >= (*this)[level].size()-1 || (*this)[level][idx+1].used ) {
+ level = size();
+ return;
+ }
+ idx += 1;
+ }else{
+ if ( idx <= 0 || (*this)[level][idx-1].used ) {
+ level = size();
+ return;
+ }
+ idx -= 1;
+ }
+ direction += 1;
+ return;
+ }
+ double t = (*this)[level][idx].t;
+ double sign = ((*this)[level][idx].sign ? 1 : -1);
+ double next_t = t;
+ //level += 1;
+ direction = (direction + 1)%4;
+ if (level == size()){
+ return;
+ }
+
+ std::pair<unsigned,unsigned> next;
+ if ( sign > 0 ){
+ next = (*this)[level][idx].next_on_curve;
+ }else{
+ next = (*this)[level][idx].prev_on_curve;
+ }
+
+ if ( level+1 != next.first || (*this)[next.first][next.second].used ) {
+ level = size();
+ return;
+ }
+ level = next.first;
+ idx = next.second;
+
+/*********************
+ //look for next time on the same level
+ for (unsigned j=0; j<(*this)[level].size(); j++){
+ double tj = (*this)[level][j].t;
+ if ( sign*(tj-t) > 0 ){
+ if( next_t == t || sign*(tj-next_t)<0 ){
+ next_t = tj;
+ idx = j;
+ }
+ }
+ }
+ if ( next_t == t ){//not found? look at max/min time in this component, as time is "periodic".
+ for (unsigned j=0; j<(*this)[level].size(); j++){
+ double tj = (*this)[level][j].t;
+ if ( -sign*(tj-next_t) > 0 ){
+ next_t = tj;
+ idx = j;
+ }
+ }
+ }
+ if ( next_t == t ){//still not found? houch! this should not happen.
+ level = size();
+ return;
+ }
+ if ( (*this)[level][idx].used ) {
+ level = size();
+ return;
+ }
+*************************/
+ return;
+ }
+};
+
+//-------------------------------------------------------
+// Bend a path...
+//-------------------------------------------------------
+
+Piecewise<D2<SBasis> > bend(Piecewise<D2<SBasis> > const &f, Piecewise<SBasis> bending){
+ D2<Piecewise<SBasis> > ff = make_cuts_independent(f);
+ ff[X] += compose(bending, ff[Y]);
+ return sectionize(ff);
+}
+
+//--------------------------------------------------------
+// The Hatches lpe.
+//--------------------------------------------------------
+LPEHatches::LPEHatches(LivePathEffectObject *lpeobject) :
+ Effect(lpeobject),
+ dist_rdm(_("Dist randomness"), _("Variation of dist between hatches, in %."), "dist_rdm", &wr, this, 75),
+ growth(_("Growth"), _("Growth of distance between hatches."), "growth", &wr, this, 0.),
+ scale_tf(_("Start smothness (front side)"), _("MISSING DESCRIPTION"), "scale_tf", &wr, this, 1.),
+ scale_tb(_("Start smothness (back side)"), _("MISSING DESCRIPTION"), "scale_tb", &wr, this, 1.),
+ scale_bf(_("End smothness (front side)"), _("MISSING DESCRIPTION"), "scale_bf", &wr, this, 1.),
+ scale_bb(_("End smothness (back side)"), _("MISSING DESCRIPTION"), "scale_bb", &wr, this, 1.),
+ top_edge_variation(_("Start edge variance"), _("The amount of random jitter to move the hatches start"), "top_edge_variation", &wr, this, 0),
+ bot_edge_variation(_("End edge variance"), _("The amount of random jitter to move the hatches end"), "bot_edge_variation", &wr, this, 0),
+ top_tgt_variation(_("Start tangential variance"), _("The amount of random jitter to move the hatches start along the boundary"), "top_tgt_variation", &wr, this, 0),
+ bot_tgt_variation(_("End tangential variance"), _("The amount of random jitter to move the hatches end along the boundary"), "bot_tgt_variation", &wr, this, 0),
+ top_smth_variation(_("Start smoothness variance"), _("Randomness of the smoothness of the U turn at hatches start"), "top_smth_variation", &wr, this, 0),
+ bot_smth_variation(_("End spacing variance"), _("Randomness of the smoothness of the U turn at hatches end"), "bot_smth_variation", &wr, this, 0),
+ fat_output(_("Generate thick/thin path"), _("Simulate a stroke of varrying width"), "fat_output", &wr, this, true),
+ do_bend(_("Bend hatches"), _("Add a global bend to the hatches (slower)"), "do_bend", &wr, this, true),
+ stroke_width_top(_("Stroke width (start side)"), _("Width at hatches 'start'"), "stroke_width_top", &wr, this, 1.),
+ stroke_width_bot(_("Stroke width (end side)"), _("Width at hatches 'end'"), "stroke_width_bot", &wr, this, 1.),
+ front_thickness(_("Front thickness (%)"), _("MISSING DESCRIPTION"), "front_thickness", &wr, this, 1.),
+ back_thickness(_("Back thickness (%)"), _("MISSING DESCRIPTION"), "back_thickness", &wr, this, .25),
+ bender(_("Global bending"), _("Relative position to ref point defines global bending direction and amount"), "bender", &wr, this, NULL, Geom::Point(-5,0)),
+ direction(_("Hatches width and dir"), _("Defines hatches frequency and direction"), "direction", &wr, this, Geom::Point(50,0))
+{
+ registerParameter( dynamic_cast<Parameter *>(&direction) );
+ registerParameter( dynamic_cast<Parameter *>(&do_bend) );
+ registerParameter( dynamic_cast<Parameter *>(&bender) );
+ registerParameter( dynamic_cast<Parameter *>(&dist_rdm) );
+ registerParameter( dynamic_cast<Parameter *>(&growth) );
+ registerParameter( dynamic_cast<Parameter *>(&top_edge_variation) );
+ registerParameter( dynamic_cast<Parameter *>(&bot_edge_variation) );
+ registerParameter( dynamic_cast<Parameter *>(&top_tgt_variation) );
+ registerParameter( dynamic_cast<Parameter *>(&bot_tgt_variation) );
+ registerParameter( dynamic_cast<Parameter *>(&scale_tf) );
+ registerParameter( dynamic_cast<Parameter *>(&scale_tb) );
+ registerParameter( dynamic_cast<Parameter *>(&scale_bf) );
+ registerParameter( dynamic_cast<Parameter *>(&scale_bb) );
+ registerParameter( dynamic_cast<Parameter *>(&top_smth_variation) );
+ registerParameter( dynamic_cast<Parameter *>(&bot_smth_variation) );
+ registerParameter( dynamic_cast<Parameter *>(&fat_output) );
+ registerParameter( dynamic_cast<Parameter *>(&stroke_width_top) );
+ registerParameter( dynamic_cast<Parameter *>(&stroke_width_bot) );
+ registerParameter( dynamic_cast<Parameter *>(&front_thickness) );
+ registerParameter( dynamic_cast<Parameter *>(&back_thickness) );
+
+ //hatch_dist.param_set_range(0.1, NR_HUGE);
+ growth.param_set_range(-0.95, NR_HUGE);
+ dist_rdm.param_set_range(0, 99.);
+ stroke_width_top.param_set_range(0, NR_HUGE);
+ stroke_width_bot.param_set_range(0, NR_HUGE);
+ front_thickness.param_set_range(0, NR_HUGE);
+ back_thickness.param_set_range(0, NR_HUGE);
+
+ concatenate_before_pwd2 = true;
+ show_orig_path = true;
+}
+
+LPEHatches::~LPEHatches()
+{
+
+}
+
+Geom::Piecewise<Geom::D2<Geom::SBasis> >
+LPEHatches::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in){
+
+ Piecewise<D2<SBasis> > result;
+
+ Piecewise<D2<SBasis> > transformed_pwd2_in = pwd2_in;
+ Piecewise<SBasis> tilter;//used to bend the hatches
+ Matrix bend_mat;//used to bend the hatches
+
+ if (do_bend.get_value()){
+ Point bend_dir = -rot90(unit_vector(direction.getOrigin() - bender));
+ double bend_amount = L2(direction.getOrigin() - bender);
+ bend_mat = Matrix(-bend_dir[Y], bend_dir[X], bend_dir[X], bend_dir[Y],0,0);
+ transformed_pwd2_in = pwd2_in * bend_mat;
+ tilter = Piecewise<SBasis>(shift(Linear(bend_amount),1));
+ OptRect bbox = bounds_exact( transformed_pwd2_in );
+ if (not(bbox)) return pwd2_in;
+ tilter.setDomain((*bbox)[Y]);
+ transformed_pwd2_in = bend(transformed_pwd2_in, tilter);
+ transformed_pwd2_in = transformed_pwd2_in * bend_mat.inverse();
+ }
+ hatch_dist = Geom::L2(direction.getVector())/5;
+ Point hatches_dir = rot90(unit_vector(direction.getVector()));
+ Matrix mat(-hatches_dir[Y], hatches_dir[X], hatches_dir[X], hatches_dir[Y],0,0);
+ transformed_pwd2_in = transformed_pwd2_in * mat;
+
+ std::vector<std::vector<Point> > snakePoints;
+ snakePoints = linearSnake(transformed_pwd2_in);
+ if ( snakePoints.size() > 0 ){
+ Piecewise<D2<SBasis> >smthSnake = smoothSnake(snakePoints);
+ smthSnake = smthSnake*mat.inverse();
+ if (do_bend.get_value()){
+ smthSnake = smthSnake*bend_mat;
+ smthSnake = bend(smthSnake, -tilter);
+ smthSnake = smthSnake*bend_mat.inverse();
+ }
+ return (smthSnake);
+ }
+ return pwd2_in;
+}
+
+//------------------------------------------------
+// Generate the levels with random, growth...
+//------------------------------------------------
+std::vector<double>
+LPEHatches::generateLevels(Interval const &domain){
+ std::vector<double> result;
+ double x = domain.min() + double(hatch_dist)/2.;
+ double step = double(hatch_dist);
+ double scale = 1+(hatch_dist*growth/domain.extent());
+ while (x < domain.max()){
+ result.push_back(x);
+ double rdm = 1;
+ if (dist_rdm.get_value() != 0)
+ rdm = 1.+ double((2*dist_rdm - dist_rdm.get_value()))/100.;
+ x+= step*rdm;
+ step*=scale;//(1.+double(growth));
+ }
+ return result;
+}
+
+
+//-------------------------------------------------------
+// Walk through the intersections to create linear hatches
+//-------------------------------------------------------
+std::vector<std::vector<Point> >
+LPEHatches::linearSnake(Piecewise<D2<SBasis> > const &f){
+
+ std::vector<std::vector<Point> > result;
+
+ Piecewise<SBasis> x = make_cuts_independent(f)[X];
+ //Rque: derivative is computed twice in the 2 lines below!!
+ Piecewise<SBasis> dx = derivative(x);
+ OptInterval range = bounds_exact(x);
+
+ if (not range) return result;
+ std::vector<double> levels = generateLevels(*range);
+ std::vector<std::vector<double> > times;
+ times = multi_roots(x,levels);
+
+//TODO: fix multi_roots!!!*****************************************
+//remove doubles :-(
+ std::vector<std::vector<double> > cleaned_times(levels.size(),std::vector<double>());
+ for (unsigned i=0; i<times.size(); i++){
+ if ( times[i].size()>0 ){
+ double last_t = times[i][0]-1;//ugly hack!!
+ for (unsigned j=0; j<times[i].size(); j++){
+ if (times[i][j]-last_t >0.000001){
+ last_t = times[i][j];
+ cleaned_times[i].push_back(last_t);
+ }
+ }
+ }
+ }
+ times = cleaned_times;
+// for (unsigned i=0; i<times.size(); i++){
+// std::cout << "roots on level "<<i<<": ";
+// for (unsigned j=0; j<times[i].size(); j++){
+// std::cout << times[i][j] <<" ";
+// }
+// std::cout <<"\n";
+// }
+//*******************************************************************
+ LevelsCrossings lscs(times,f,dx);
+ unsigned i,j;
+ lscs.findFirstUnused(i,j);
+ std::vector<Point> result_component;
+ while ( i < lscs.size() ){
+ int dir = 0;
+ while ( i < lscs.size() ){
+ result_component.push_back(lscs[i][j].pt);
+ lscs[i][j].used = true;
+ lscs.step(i,j, dir);
+ }
+ result.push_back(result_component);
+ result_component = std::vector<Point>();
+ lscs.findFirstUnused(i,j);
+ }
+ return result;
+}
+
+//-------------------------------------------------------
+// Smooth the linear hatches according to params...
+//-------------------------------------------------------
+Piecewise<D2<SBasis> >
+LPEHatches::smoothSnake(std::vector<std::vector<Point> > const &linearSnake){
+
+ Piecewise<D2<SBasis> > result;
+ for (unsigned comp=0; comp<linearSnake.size(); comp++){
+ if (linearSnake[comp].size()>=2){
+ bool is_top = true;//Inversion here; due to downward y?
+ Point last_pt = linearSnake[comp][0];
+ Point last_top = linearSnake[comp][0];
+ Point last_bot = linearSnake[comp][0];
+ Point last_hdle = linearSnake[comp][0];
+ Point last_top_hdle = linearSnake[comp][0];
+ Point last_bot_hdle = linearSnake[comp][0];
+ Geom::Path res_comp(last_pt);
+ Geom::Path res_comp_top(last_pt);
+ Geom::Path res_comp_bot(last_pt);
+ unsigned i=1;
+ while( i+1<linearSnake[comp].size() ){
+ Point pt0 = linearSnake[comp][i];
+ Point pt1 = linearSnake[comp][i+1];
+ Point new_pt = (pt0+pt1)/2;
+ double scale_in = (is_top ? scale_tf : scale_bf );
+ double scale_out = (is_top ? scale_tb : scale_bb );
+ if (is_top){
+ if (top_edge_variation.get_value() != 0)
+ new_pt[Y] += double(top_edge_variation)-top_edge_variation.get_value()/2.;
+ if (top_tgt_variation.get_value() != 0)
+ new_pt[X] += double(top_tgt_variation)-top_tgt_variation.get_value()/2.;
+ if (top_smth_variation.get_value() != 0) {
+ scale_in*=(100.-double(top_smth_variation))/100.;
+ scale_out*=(100.-double(top_smth_variation))/100.;
+ }
+ }else{
+ if (bot_edge_variation.get_value() != 0)
+ new_pt[Y] += double(bot_edge_variation)-bot_edge_variation.get_value()/2.;
+ if (bot_tgt_variation.get_value() != 0)
+ new_pt[X] += double(bot_tgt_variation)-bot_tgt_variation.get_value()/2.;
+ if (bot_smth_variation.get_value() != 0) {
+ scale_in*=(100.-double(bot_smth_variation))/100.;
+ scale_out*=(100.-double(bot_smth_variation))/100.;
+ }
+ }
+ Point new_hdle_in = new_pt + (pt0-pt1) * (scale_in /2.);
+ Point new_hdle_out = new_pt - (pt0-pt1) * (scale_out/2.);
+
+ if ( fat_output.get_value() ){
+ double scaled_width = double((is_top ? stroke_width_top : stroke_width_bot))/(pt1[X]-pt0[X]);
+ Point hdle_offset = (pt1-pt0)*scaled_width;
+ Point inside = new_pt;
+ Point inside_hdle_in;
+ Point inside_hdle_out;
+ inside[Y]+= double((is_top ? -stroke_width_top : stroke_width_bot));
+ inside_hdle_in = inside + (new_hdle_in -new_pt) + hdle_offset * double((is_top ? front_thickness : back_thickness));
+ inside_hdle_out = inside + (new_hdle_out-new_pt) - hdle_offset * double((is_top ? back_thickness : front_thickness));
+ //TODO: find a good way to handle limit cases (small smthness, large stroke).
+ //if (inside_hdle_in[X] > inside[X]) inside_hdle_in = inside;
+ //if (inside_hdle_out[X] < inside[X]) inside_hdle_out = inside;
+
+ if (is_top){
+ res_comp_top.appendNew<CubicBezier>(last_top_hdle,new_hdle_in,new_pt);
+ res_comp_bot.appendNew<CubicBezier>(last_bot_hdle,inside_hdle_in,inside);
+ last_top_hdle = new_hdle_out;
+ last_bot_hdle = inside_hdle_out;
+ }else{
+ res_comp_top.appendNew<CubicBezier>(last_top_hdle,inside_hdle_in,inside);
+ res_comp_bot.appendNew<CubicBezier>(last_bot_hdle,new_hdle_in,new_pt);
+ last_top_hdle = inside_hdle_out;
+ last_bot_hdle = new_hdle_out;
+ }
+ }else{
+ res_comp.appendNew<CubicBezier>(last_hdle,new_hdle_in,new_pt);
+ }
+
+ last_hdle = new_hdle_out;
+ i+=2;
+ is_top = !is_top;
+ }
+ if ( i<linearSnake[comp].size() )
+ if ( fat_output.get_value() ){
+ res_comp_top.appendNew<CubicBezier>(last_top_hdle,linearSnake[comp][i],linearSnake[comp][i]);
+ res_comp_bot.appendNew<CubicBezier>(last_bot_hdle,linearSnake[comp][i],linearSnake[comp][i]);
+ }else{
+ res_comp.appendNew<CubicBezier>(last_hdle,linearSnake[comp][i],linearSnake[comp][i]);
+ }
+ if ( fat_output.get_value() ){
+ res_comp = res_comp_bot;
+ res_comp.append(res_comp_top.reverse(),Geom::Path::STITCH_DISCONTINUOUS);
+ }
+ result.concat(res_comp.toPwSb());
+ }
+ }
+ return result;
+}
+
+void
+LPEHatches::doBeforeEffect (SPLPEItem */*lpeitem*/)
+{
+ using namespace Geom;
+ top_edge_variation.resetRandomizer();
+ bot_edge_variation.resetRandomizer();
+ top_tgt_variation.resetRandomizer();
+ bot_tgt_variation.resetRandomizer();
+ top_smth_variation.resetRandomizer();
+ bot_smth_variation.resetRandomizer();
+ dist_rdm.resetRandomizer();
+
+ //original_bbox(lpeitem);
+}
+
+
+void
+LPEHatches::resetDefaults(SPItem * item)
+{
+ Geom::OptRect bbox = item->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX);
+ Geom::Point origin(0.,0.);
+ Geom::Point vector(50.,0.);
+ if (bbox) {
+ origin = bbox->midpoint();
+ vector = Geom::Point((*bbox)[X].extent()/4, 0.);
+ top_edge_variation.param_set_value( (*bbox)[Y].extent()/10, 0 );
+ bot_edge_variation.param_set_value( (*bbox)[Y].extent()/10, 0 );
+ }
+ direction.set_and_write_new_values(origin, vector);
+ bender.param_set_and_write_new_value( origin + Geom::Point(5,0) );
+ hatch_dist = Geom::L2(vector)/5;
+}
+
+
+} //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/lpe-hatches.h b/src/live_effects/lpe-hatches.h new file mode 100644 index 000000000..029847186 --- /dev/null +++ b/src/live_effects/lpe-hatches.h @@ -0,0 +1,77 @@ +#ifndef INKSCAPE_LPE_HATCHES_H
+#define INKSCAPE_LPE_HATCHES_H
+
+/** \file
+ * Implementation of the curve stitch effect, see lpe-hatches.cpp
+ */
+
+/*
+ * Authors:
+ * JFBarraud
+ *
+ * Copyright (C) JF Barraud 2008.
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/effect.h"
+#include "live_effects/parameter/point.h"
+#include "live_effects/parameter/parameter.h"
+#include "live_effects/parameter/bool.h"
+#include "live_effects/parameter/random.h"
+#include "live_effects/parameter/vector.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+class LPEHatches : public Effect {
+public:
+ LPEHatches(LivePathEffectObject *lpeobject);
+ virtual ~LPEHatches();
+
+ virtual Geom::Piecewise<Geom::D2<Geom::SBasis> >
+ doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
+
+ virtual void resetDefaults(SPItem * item);
+
+ virtual void doBeforeEffect(SPLPEItem * item);
+
+ std::vector<double>
+ generateLevels(Geom::Interval const &domain);
+
+ std::vector<std::vector<Geom::Point> >
+ linearSnake(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &f);
+
+ Geom::Piecewise<Geom::D2<Geom::SBasis> >
+ smoothSnake(std::vector<std::vector<Geom::Point> > const &linearSnake);
+
+private:
+ double hatch_dist;
+ RandomParam dist_rdm;
+ ScalarParam growth;
+ //topfront,topback,bottomfront,bottomback handle scales.
+ ScalarParam scale_tf, scale_tb, scale_bf, scale_bb;
+
+ RandomParam top_edge_variation;
+ RandomParam bot_edge_variation;
+ RandomParam top_tgt_variation;
+ RandomParam bot_tgt_variation;
+ RandomParam top_smth_variation;
+ RandomParam bot_smth_variation;
+
+ BoolParam fat_output, do_bend;
+ ScalarParam stroke_width_top;
+ ScalarParam stroke_width_bot;
+ ScalarParam front_thickness, back_thickness;
+
+ PointParam bender;
+ VectorParam direction;
+
+ LPEHatches(const LPEHatches&);
+ LPEHatches& operator=(const LPEHatches&);
+};
+
+} //namespace LivePathEffect
+} //namespace Inkscape
+
+#endif
diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp index a4c722acc..b2f1547a9 100644 --- a/src/live_effects/lpe-interpolate.cpp +++ b/src/live_effects/lpe-interpolate.cpp @@ -61,8 +61,12 @@ LPEInterpolate::doEffect_path (Geom::PathVector const & path_in) Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_B = path_in[1].toPwSb(); // Transform both paths to (0,0) midpoint, so they can easily be positioned along interpolate_path - pwd2_A -= Geom::bounds_exact(pwd2_A).midpoint(); - pwd2_B -= Geom::bounds_exact(pwd2_B).midpoint(); + if (Geom::OptRect bounds = Geom::bounds_exact(pwd2_A)) { + pwd2_A -= bounds->midpoint(); + } + if (Geom::OptRect bounds = Geom::bounds_exact(pwd2_B)) { + pwd2_B -= bounds->midpoint(); + } // Make sure both paths have the same number of segments and cuts at the same locations pwd2_B.setDomain(pwd2_A.domain()); @@ -99,14 +103,18 @@ LPEInterpolate::resetDefaults(SPItem * item) if ( (pathv.size() < 2) ) return; - Geom::Rect bounds_A = pathv[0].boundsExact(); - Geom::Rect bounds_B = pathv[1].boundsExact(); - - Geom::PathVector traj_pathv; - traj_pathv.push_back( Geom::Path() ); - traj_pathv[0].start( bounds_A.midpoint() ); - traj_pathv[0].appendNew<Geom::LineSegment>( bounds_B.midpoint() ); - trajectory_path.set_new_value( traj_pathv, true ); + Geom::OptRect bounds_A = pathv[0].boundsExact(); + Geom::OptRect bounds_B = pathv[1].boundsExact(); + + if (bounds_A && bounds_B) { + Geom::PathVector traj_pathv; + traj_pathv.push_back( Geom::Path() ); + traj_pathv[0].start( bounds_A->midpoint() ); + traj_pathv[0].appendNew<Geom::LineSegment>( bounds_B->midpoint() ); + trajectory_path.set_new_value( traj_pathv, true ); + } else { + trajectory_path.param_set_and_write_default(); + } } } //namespace LivePathEffect diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 0ff1beccf..df18f8767 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -1,12 +1,10 @@ -#define INKSCAPE_LPE_KNOT_CPP -/** \file - * LPE <knot> implementation +/** @file + * @brief LPE knot effect implementation */ -/* - * Authors: - * JF Barraud -* -* Copyright (C) JF Barraud 2007 <jf.barraud@gmail.com> +/* Authors: + * Jean-Francois Barraud <jf.barraud@gmail.com> + * + * Copyright (C) 2007 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -107,8 +105,9 @@ findShadowedTime(Geom::Path const &patha, return Interval(tmin,tmax); } +// TODO: Fix all this in 2geom!!!! //--------------------------------------------------------------------------- -// a 2Geom work around. +// some 2Geom work around. //--------------------------------------------------------------------------- //Cubic Bezier curves might self intersect; the 2geom code used to miss them. @@ -133,29 +132,36 @@ split_at_horiz_vert_tgt (std::vector<Geom::Path> const & path_in){ return ret; } - -//--------------------------------------------------------------------------- -//LPEKnot specific Crossing Data manipulation. -//--------------------------------------------------------------------------- - -//TODO: Fix this in 2Geom: I think CrossingSets should not contain duplicates. +//TODO: Fix this in 2Geom; I think CrossingSets should not contain duplicates. Geom::CrossingSet crossingSet_remove_double(Geom::CrossingSet const &input){ Geom::CrossingSet result(input.size()); //Yeah, I know, there is a "unique" algorithm for that... + //Note: I'm not sure the duplicates are always consecutive!! (can be first and last, I think) + //Note: I also found crossings c with c.a==c.b and c.ta==c.tb . Is it normal? + //Note: I also found crossings c with c.ta or c.tb not in path[a] or path[b] domain. This is definitely not normal. Geom::Crossing last; for( unsigned i=0; i<input.size(); i++){ for( unsigned j=0; j<input[i].size(); j++){ - if( j==0 || !(input[i][j]==last) ){ - result[i].push_back(input[i][j]); - last = input[i][j]; - }else{ - g_warning("Duplicate found in a Geom::CrossingSet!"); + bool dup = false; + for ( unsigned k=0; k<result[i].size(); k++){ + if ( input[i][j]==result[i][k] ){ + dup = true; + g_warning("Duplicate found in a Geom::CrossingSet!"); + break; + } + } + if (!dup) { + result[i].push_back( input[i][j] ); } } } return result; } +//--------------------------------------------------------------------------- +//LPEKnot specific Crossing Data manipulation. +//--------------------------------------------------------------------------- + //TODO: evaluate how usefull/lpeknot specific that is. Worth being moved to 2geom? (I doubt it) namespace LPEKnotNS { @@ -173,15 +179,21 @@ namespace LPEKnotNS { CrossingPoints::CrossingPoints(Geom::CrossingSet const &input, std::vector<Geom::Path> const &path) : std::vector<CrossingPoint>() { using namespace Geom; -// g_print("JF>\nCrossing set content:\n"); + //g_print("DBG>\nCrossing set content:\n"); for( unsigned i=0; i<input.size(); i++){ Crossings i_crossings = input[i]; for( unsigned n=0; n<i_crossings.size(); n++ ){ Crossing c = i_crossings[n]; -// g_print("JF> (%u,%u) at times (%f,%f) ----->",c.a,c.b,c.ta,c.tb); + //g_print("DBG> [%u,%u]:(%u,%u) at times (%f,%f) ----->",i,n,c.a,c.b,c.ta,c.tb); unsigned j = c.getOther(i); - if (i<j || (i==j && c.ta<c.tb) ){ + if (i<j || (i==j && c.ta<=c.tb) ){//FIXME: equality should not happen, but does happen. CrossingPoint cp; + double ti = c.getTime(i); + //FIXME: times in crossing are sometimes out of range!! + //if (0<ti || ti > 1)g_print("oops! -->"); + if (ti > 1) ti=1; + if (ti < 0) ti=0; + cp.pt = path[i].pointAt(c.getTime(i)); cp.i = i; cp.j = j; @@ -189,7 +201,7 @@ CrossingPoints::CrossingPoints(Geom::CrossingSet const &input, std::vector<Geom: Crossing c_bar = c; if (i==j){ c_bar.a = c.b; - c_bar.b = c.a; + c_bar.b = c.a; c_bar.ta = c.tb; c_bar.tb = c.ta; c_bar.dir = !c.dir; @@ -197,24 +209,37 @@ CrossingPoints::CrossingPoints(Geom::CrossingSet const &input, std::vector<Geom: cp.nj = std::find(input[j].begin(),input[j].end(),c_bar)-input[j].begin(); cp.sign = 1; push_back(cp); -// g_print("i=%u, ni=%u, j=%u, nj=%u\n",cp.i,cp.ni,cp.j,cp.nj); - } - else{ -// g_print("\n"); + //g_print("i=%u, ni=%u, j=%u, nj=%u\n",cp.i,cp.ni,cp.j,cp.nj); + }/* + else{ + //debug purpose only: + //This crossing is already registered in output. Just make sure it has a "mirror". + g_print("deja trouve?"); + get(i,n); bool found = false; for( unsigned ii=0; ii<input.size(); ii++){ Crossings ii_crossings = input[ii]; for( unsigned nn=0; nn<ii_crossings.size(); nn++ ){ Crossing cc = ii_crossings[nn]; if (cc.b==c.a && cc.a==c.b && cc.ta==c.tb && cc.tb==c.ta) found = true; + if ( (ii!=i || nn!=n) && + ( (cc.b==c.a && cc.a==c.b && cc.ta==c.tb && cc.tb==c.ta) || + (cc.a==c.a && cc.b==c.b && cc.ta==c.ta && cc.tb==c.tb) + ) ) found = true; } } - if (!found) { - throw std::exception(); - } + assert( found ); + g_print(" oui!\n"); } + */ } } + + //g_print("CrossingPoints reslut:\n"); + //for (unsigned k=0; k<size(); k++){ + // g_print("cpts[%u]: i=%u, ni=%u, j=%u, nj=%u\n",k,(*this)[k].i,(*this)[k].ni,(*this)[k].j,(*this)[k].nj); + //} + } CrossingPoints::CrossingPoints(std::vector<double> const &input) : std::vector<CrossingPoint>() @@ -386,19 +411,8 @@ LPEKnot::doEffect_path (std::vector<Geom::Path> const &input_path) CrossingSet crossingTable = crossings_among(path_in); - for(unsigned i=0;i<crossingTable.size();i++){ - for(unsigned j=0;j<crossingTable[i].size();j++){ -// g_print("JF>avant: %u,%u,%f,%f\n",crossingTable[i][j].a, crossingTable[i][j].b, crossingTable[i][j].ta, crossingTable[i][j].tb); - } - } crossingTable = crossingSet_remove_double(crossingTable); - for(unsigned i=0;i<crossingTable.size();i++){ - for(unsigned j=0;j<crossingTable[i].size();j++){ -// g_print("JF>apres: %u,%u,%f,%f\n",crossingTable[i][j].a, crossingTable[i][j].b, crossingTable[i][j].ta, crossingTable[i][j].tb); - } - } - crossing_points = LPEKnotNS::CrossingPoints(crossingTable, path_in); crossing_points.inherit_signs(old_crdata); crossing_points_vector.param_set_and_write_new_value(crossing_points.to_vector()); @@ -522,8 +536,8 @@ KnotHolderEntityCrossingSwitcher::knot_click(guint state) /* ######################## */ -} //namespace LivePathEffect (setq default-directory "c:/Documents And Settings/jf/Mes Documents/InkscapeSVN") -} /* namespace Inkscape */ +} // namespace LivePathEffect +} // namespace Inkscape /* Local Variables: @@ -534,4 +548,4 @@ KnotHolderEntityCrossingSwitcher::knot_click(guint state) fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/live_effects/lpe-knot.h b/src/live_effects/lpe-knot.h index 4c98ccd55..cbd33466d 100644 --- a/src/live_effects/lpe-knot.h +++ b/src/live_effects/lpe-knot.h @@ -1,22 +1,21 @@ -#ifndef INKSCAPE_LPE_KNOT_H -#define INKSCAPE_LPE_KNOT_H - /** \file - * LPE <knot> implementation, see lpe-knot.cpp. + * LPE knot effect implementation, see lpe-knot.cpp. */ - -/* - * Authors: - * JFB, but derived from Johan Engelen! -* -* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> +/* Authors: + * Jean-Francois Barraud <jf.barraud@gmail.com> + * Johan Engelen <j.b.c.engelen@utwente.nl> + * + * Copyright (C) Johan Engelen 2007 * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef INKSCAPE_LPE_KNOT_H +#define INKSCAPE_LPE_KNOT_H + #include "live_effects/effect.h" #include "live_effects/parameter/parameter.h" -#include "live_effects/parameter/vector.h" +#include "live_effects/parameter/array.h" #include "live_effects/parameter/path.h" #include "2geom/crossing.h" @@ -70,7 +69,7 @@ private: // add the parameters for your effect here: ScalarParam interruption_width; ScalarParam switcher_size; - VectorParam<double> crossing_points_vector; + ArrayParam<double> crossing_points_vector; LPEKnotNS::CrossingPoints crossing_points; diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp index 0e5011e51..954a01029 100644 --- a/src/live_effects/lpe-patternalongpath.cpp +++ b/src/live_effects/lpe-patternalongpath.cpp @@ -66,7 +66,8 @@ LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) : normal_offset(_("Normal offset"), "", "normal_offset", &wr, this, 0), tang_offset(_("Tangential offset"), "", "tang_offset", &wr, this, 0), prop_units(_("Offsets in unit of pattern size"), _("Spacing, tangential and normal offset are expressed as a ratio of width/height"), "prop_units", &wr, this, false), - vertical_pattern(_("Pattern is vertical"), _("Rotate pattern 90 deg before applying"), "vertical_pattern", &wr, this, false) + vertical_pattern(_("Pattern is vertical"), _("Rotate pattern 90 deg before applying"), "vertical_pattern", &wr, this, false), + fuse_tolerance(_("Fuse nearby ends"), "Fuse ends closer than this number. 0 means don't fuse.", "fuse_tolerance", &wr, this, 0) { registerParameter( dynamic_cast<Parameter *>(&pattern) ); registerParameter( dynamic_cast<Parameter *>(©type) ); @@ -77,6 +78,7 @@ LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&tang_offset) ); registerParameter( dynamic_cast<Parameter *>(&prop_units) ); registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) ); + registerParameter( dynamic_cast<Parameter *>(&fuse_tolerance) ); prop_scale.param_set_digits(3); prop_scale.param_set_increments(0.01, 0.10); @@ -94,105 +96,122 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con /* Much credit should go to jfb and mgsloan of lib2geom development for the code below! */ Piecewise<D2<SBasis> > output; + std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > pre_output; PAPCopyType type = copytype.get_value(); D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(pattern.get_pwd2()); Piecewise<SBasis> x0 = vertical_pattern.get_value() ? Piecewise<SBasis>(patternd2[1]) : Piecewise<SBasis>(patternd2[0]); Piecewise<SBasis> y0 = vertical_pattern.get_value() ? Piecewise<SBasis>(patternd2[0]) : Piecewise<SBasis>(patternd2[1]); - Interval pattBndsX = bounds_exact(x0); - x0 -= pattBndsX.min(); - Interval pattBndsY = bounds_exact(y0); - y0 -= pattBndsY.middle(); - - double xspace = spacing; - double noffset = normal_offset; - double toffset = tang_offset; - if (prop_units.get_value()){ - xspace *= pattBndsX.extent(); - noffset *= pattBndsY.extent(); - toffset *= pattBndsX.extent(); - } + OptInterval pattBndsX = bounds_exact(x0); + OptInterval pattBndsY = bounds_exact(y0); + if (pattBndsX && pattBndsY) { + x0 -= pattBndsX->min(); + y0 -= pattBndsY->middle(); + + double xspace = spacing; + double noffset = normal_offset; + double toffset = tang_offset; + if (prop_units.get_value() && pattBndsY){ + xspace *= pattBndsX->extent(); + noffset *= pattBndsY->extent(); + toffset *= pattBndsX->extent(); + } - //Prevent more than 90% overlap... - if (xspace < -pattBndsX.extent()*.9) { - xspace = -pattBndsX.extent()*.9; - } - //TODO: dynamical update of parameter ranges? - //if (prop_units.get_value()){ - // spacing.param_set_range(-.9, NR_HUGE); - // }else{ - // spacing.param_set_range(-pattBndsX.extent()*.9, NR_HUGE); - // } - - y0+=noffset; - - std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > paths_in; - paths_in = split_at_discontinuities(pwd2_in); - - for (unsigned idx = 0; idx < paths_in.size(); idx++){ - Geom::Piecewise<Geom::D2<Geom::SBasis> > path_i = paths_in[idx]; - Piecewise<SBasis> x = x0; - Piecewise<SBasis> y = y0; - Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(path_i,2,.1); - uskeleton = remove_short_cuts(uskeleton,.01); - Piecewise<D2<SBasis> > n = rot90(derivative(uskeleton)); - n = force_continuity(remove_short_cuts(n,.1)); - - int nbCopies = 0; - double scaling = 1; - switch(type) { - case PAPCT_REPEATED: - nbCopies = static_cast<int>(floor((uskeleton.domain().extent() - toffset + xspace)/(pattBndsX.extent()+xspace))); - pattBndsX = Interval(pattBndsX.min(),pattBndsX.max()+xspace); - break; - - case PAPCT_SINGLE: - nbCopies = (toffset + pattBndsX.extent() < uskeleton.domain().extent()) ? 1 : 0; - break; - - case PAPCT_SINGLE_STRETCHED: - nbCopies = 1; - scaling = (uskeleton.domain().extent() - toffset)/pattBndsX.extent(); - break; - - case PAPCT_REPEATED_STRETCHED: - // if uskeleton is closed: - if(path_i.segs.front().at0() == path_i.segs.back().at1()){ - nbCopies = static_cast<int>(std::floor((uskeleton.domain().extent() - toffset)/(pattBndsX.extent()+xspace))); - pattBndsX = Interval(pattBndsX.min(),pattBndsX.max()+xspace); - scaling = (uskeleton.domain().extent() - toffset)/(((double)nbCopies)*pattBndsX.extent()); - // if not closed: no space at the end + //Prevent more than 90% overlap... + if (xspace < -pattBndsX->extent()*.9) { + xspace = -pattBndsX->extent()*.9; + } + //TODO: dynamical update of parameter ranges? + //if (prop_units.get_value()){ + // spacing.param_set_range(-.9, NR_HUGE); + // }else{ + // spacing.param_set_range(-pattBndsX.extent()*.9, NR_HUGE); + // } + + y0+=noffset; + + std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > paths_in; + paths_in = split_at_discontinuities(pwd2_in); + + for (unsigned idx = 0; idx < paths_in.size(); idx++){ + Geom::Piecewise<Geom::D2<Geom::SBasis> > path_i = paths_in[idx]; + Piecewise<SBasis> x = x0; + Piecewise<SBasis> y = y0; + Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(path_i,2,.1); + uskeleton = remove_short_cuts(uskeleton,.01); + Piecewise<D2<SBasis> > n = rot90(derivative(uskeleton)); + n = force_continuity(remove_short_cuts(n,.1)); + + int nbCopies = 0; + double scaling = 1; + switch(type) { + case PAPCT_REPEATED: + nbCopies = static_cast<int>(floor((uskeleton.domain().extent() - toffset + xspace)/(pattBndsX->extent()+xspace))); + pattBndsX = Interval(pattBndsX->min(),pattBndsX->max()+xspace); + break; + + case PAPCT_SINGLE: + nbCopies = (toffset + pattBndsX->extent() < uskeleton.domain().extent()) ? 1 : 0; + break; + + case PAPCT_SINGLE_STRETCHED: + nbCopies = 1; + scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent(); + break; + + case PAPCT_REPEATED_STRETCHED: + // if uskeleton is closed: + if(path_i.segs.front().at0() == path_i.segs.back().at1()){ + nbCopies = static_cast<int>(std::floor((uskeleton.domain().extent() - toffset)/(pattBndsX->extent()+xspace))); + pattBndsX = Interval(pattBndsX->min(),pattBndsX->max()+xspace); + scaling = (uskeleton.domain().extent() - toffset)/(((double)nbCopies)*pattBndsX->extent()); + // if not closed: no space at the end + }else{ + nbCopies = static_cast<int>(std::floor((uskeleton.domain().extent() - toffset + xspace)/(pattBndsX->extent()+xspace))); + pattBndsX = Interval(pattBndsX->min(),pattBndsX->max()+xspace); + scaling = (uskeleton.domain().extent() - toffset)/(((double)nbCopies)*pattBndsX->extent() - xspace); + } + break; + + default: + return pwd2_in; + }; + + double pattWidth = pattBndsX->extent() * scaling; + + if (scaling != 1.0) { + x*=scaling; + } + if ( scale_y_rel.get_value() ) { + y*=(scaling*prop_scale); + } else { + if (prop_scale != 1.0) y *= prop_scale; + } + x += toffset; + + double offs = 0; + for (int i=0; i<nbCopies; i++){ + if (fuse_tolerance > 0){ + Geom::Piecewise<Geom::D2<Geom::SBasis> > output_piece = compose(uskeleton,x+offs)+y*compose(n,x+offs); + std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > splited_output_piece = split_at_discontinuities(output_piece); + pre_output.insert(pre_output.end(), splited_output_piece.begin(), splited_output_piece.end() ); }else{ - nbCopies = static_cast<int>(std::floor((uskeleton.domain().extent() - toffset + xspace)/(pattBndsX.extent()+xspace))); - pattBndsX = Interval(pattBndsX.min(),pattBndsX.max()+xspace); - scaling = (uskeleton.domain().extent() - toffset)/(((double)nbCopies)*pattBndsX.extent() - xspace); + output.concat(compose(uskeleton,x+offs)+y*compose(n,x+offs)); } - break; - - default: - return pwd2_in; - }; - - double pattWidth = pattBndsX.extent() * scaling; - - if (scaling != 1.0) { - x*=scaling; - } - if ( scale_y_rel.get_value() ) { - y*=(scaling*prop_scale); - } else { - if (prop_scale != 1.0) y *= prop_scale; + offs+=pattWidth; + } } - x += toffset; - - double offs = 0; - for (int i=0; i<nbCopies; i++){ - output.concat(compose(uskeleton,x+offs)+y*compose(n,x+offs)); - offs+=pattWidth; + if (fuse_tolerance > 0){ + pre_output = fuse_nearby_ends(pre_output, fuse_tolerance); + for (unsigned i=0; i<pre_output.size(); i++){ + output.concat(pre_output[i]); + } } + return output; + } else { + return pwd2_in; } - return output; } LPEFreehandShape::LPEFreehandShape(LivePathEffectObject *lpeobject) : LPEPatternAlongPath(lpeobject) diff --git a/src/live_effects/lpe-patternalongpath.h b/src/live_effects/lpe-patternalongpath.h index 5adc049fb..f35f7a5cb 100644 --- a/src/live_effects/lpe-patternalongpath.h +++ b/src/live_effects/lpe-patternalongpath.h @@ -42,6 +42,7 @@ private: ScalarParam tang_offset; BoolParam prop_units; BoolParam vertical_pattern; + ScalarParam fuse_tolerance; void on_pattern_pasted(); diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index 2eef0cd5b..d5262f33c 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -1,22 +1,11 @@ -#define INKSCAPE_LPE_PERSPECTIVE_PATH_CPP -/** \file - * LPE <perspective_path> implementation, used as an example for a base starting class - * when implementing new LivePathEffects. - * - * In vi, three global search-and-replaces will let you rename everything - * in this and the .h file: - * - * :%s/PERSPECTIVE_PATH/YOURNAME/g - * :%s/PerspectivePath/Yourname/g - * :%s/perspective_path/yourname/g +/** @file + * @brief LPE perspective path effect implementation. */ -/* - * Authors: - * Johan Engelen - * Maximilian Albert +/* Authors: + * Maximilian Albert <maximilian.albert@gmail.com> + * Johan Engelen <j.b.c.engelen@utwente.nl> * - * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> - * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com> + * Copyright (C) 2007-2008 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -198,4 +187,4 @@ KnotHolderEntityOffset::knot_get() fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/live_effects/lpe-perspective_path.h b/src/live_effects/lpe-perspective_path.h index 62589e875..23731f9f7 100644 --- a/src/live_effects/lpe-perspective_path.h +++ b/src/live_effects/lpe-perspective_path.h @@ -1,19 +1,18 @@ -#ifndef INKSCAPE_LPE_PERSPECTIVE_PATH_H -#define INKSCAPE_LPE_PERSPECTIVE_PATH_H - -/** \file - * LPE <perspective_path> implementation, see lpe-perspective_path.cpp. +/** @file + * @brief LPE perspective path effect implementation */ - -/* - * Authors: - * Johan Engelen -* -* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> +/* Authors: + * Maximilian Albert <maximilian.albert@gmail.com> + * Johan Engelen <j.b.c.engelen@utwente.nl> + * + * Copyright (C) 2007 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef INKSCAPE_LPE_PERSPECTIVE_PATH_H +#define INKSCAPE_LPE_PERSPECTIVE_PATH_H + #include "live_effects/effect.h" #include "live_effects/parameter/parameter.h" #include "live_effects/parameter/bool.h" @@ -65,3 +64,14 @@ private: } //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/lpe-skeleton.cpp b/src/live_effects/lpe-skeleton.cpp index c2ab7be51..fdee68b88 100644 --- a/src/live_effects/lpe-skeleton.cpp +++ b/src/live_effects/lpe-skeleton.cpp @@ -1,7 +1,7 @@ #define INKSCAPE_LPE_SKELETON_CPP /** \file - * LPE <skeleton> implementation, used as an example for a base starting class - * when implementing new LivePathEffects. + * @brief Minimal dummy LPE effect implementation, used as an example for a base + * starting class when implementing new LivePathEffects. * * In vi, three global search-and-replaces will let you rename everything * in this and the .h file: @@ -10,11 +10,10 @@ * :%s/Skeleton/Yourname/g * :%s/skeleton/yourname/g */ -/* - * Authors: - * Johan Engelen +/* Authors: + * Johan Engelen <j.b.c.engelen@utwente.nl> * - * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * Copyright (C) 2007 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -84,7 +83,7 @@ LPESkeleton::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd * Define the classes for your knotholder handles here */ -/** +/* namespace Skeleton { class KnotHolderEntityMyHandle : public LPEKnotHolderEntity @@ -97,7 +96,7 @@ public: }; } // namespace Skeleton -**/ +*/ /* ######################## */ @@ -113,4 +112,4 @@ public: fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/live_effects/lpe-skeleton.h b/src/live_effects/lpe-skeleton.h index d961ad954..fd9dc0aba 100644 --- a/src/live_effects/lpe-skeleton.h +++ b/src/live_effects/lpe-skeleton.h @@ -1,19 +1,17 @@ -#ifndef INKSCAPE_LPE_SKELETON_H -#define INKSCAPE_LPE_SKELETON_H - -/** \file - * LPE <skeleton> implementation, see lpe-skeleton.cpp. +/** @file + * @brief Minimal LPE effect, see lpe-skeleton.cpp. */ - -/* - * Authors: - * Johan Engelen +/* Authors: + * Johan Engelen <j.b.c.engelen@utwente.nl> * - * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * Copyright (C) 2007 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef INKSCAPE_LPE_SKELETON_H +#define INKSCAPE_LPE_SKELETON_H + #include "live_effects/effect.h" #include "live_effects/parameter/parameter.h" @@ -65,4 +63,4 @@ private: fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp index 38957a658..1fe4ba525 100644 --- a/src/live_effects/lpe-sketch.cpp +++ b/src/live_effects/lpe-sketch.cpp @@ -1,12 +1,11 @@ -#define INKSCAPE_LPE_SKETCH_CPP -/** \file - * LPE <sketch> implementation +/** @file + * @brief LPE sketch effect implementation */ -/* - * Authors: - * Johan Engelen -* -* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> +/* Authors: + * Jean-Francois Barraud <jf.barraud@gmail.com> + * Johan Engelen <j.b.c.engelen@utwente.nl> + * + * Copyright (C) 2007 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -189,7 +188,7 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_ //----- Approximated Strokes. std::vector<Piecewise<D2<SBasis> > > pieces_in = split_at_discontinuities (pwd2_in); - + //work separately on each component. for (unsigned pieceidx = 0; pieceidx < pieces_in.size(); pieceidx++){ @@ -247,10 +246,11 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_ t1 = times[0]; //pick a rdm perturbation, and collect the perturbed piece into output. - Piecewise<D2<SBasis> > pwperturb = computePerturbation(s0,s1); + Piecewise<D2<SBasis> > pwperturb = computePerturbation(s0-0.01,s1+0.01); pwperturb = compose(pwperturb,portion(piecelength,t0,t1)); + output.concat(portion(piece,t0,t1)+pwperturb); - + //step points: s0 = s1 - overlap. //TODO: make sure this has to end? s0 = s1 - strokeoverlap*(1-strokeoverlap_rdm)*(s1-s0); @@ -258,7 +258,6 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_ } } - //----- Construction lines. //TODO: choose places according to curvature?. @@ -268,7 +267,9 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_ Piecewise<D2<SBasis> > m = pwd2_in; Piecewise<D2<SBasis> > v = derivative(pwd2_in); Piecewise<D2<SBasis> > a = derivative(v); + for (unsigned i=0; i<nbtangents; i++){ + // pick a point where to draw a tangent (s = dist from start along path). double s = total_length * ( i + tgtlength_rdm ) / (nbtangents+1.); std::vector<double> times; @@ -290,6 +291,7 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_ } output.concat(Piecewise<D2<SBasis> >(tgt)); } + return output; } @@ -319,4 +321,4 @@ LPESketch::doBeforeEffect (SPLPEItem *lpeitem) fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/live_effects/lpe-sketch.h b/src/live_effects/lpe-sketch.h index bca4e2447..4237c2b67 100644 --- a/src/live_effects/lpe-sketch.h +++ b/src/live_effects/lpe-sketch.h @@ -1,19 +1,18 @@ -#ifndef INKSCAPE_LPE_SKETCH_H -#define INKSCAPE_LPE_SKETCH_H - /** \file - * LPE <sketch> implementation, see lpe-sketch.cpp. + * @brief LPE sketch effect implementation, see lpe-sketch.cpp. */ - -/* - * Authors: - * JFB, but derived from Johan Engelen! -* -* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> +/* Authors: + * Jean-Francois Barraud <jf.barraud@gmail.com> + * Johan Engelen <j.b.c.engelen@utwente.nl> + * + * Copyright (C) 2007 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef INKSCAPE_LPE_SKETCH_H +#define INKSCAPE_LPE_SKETCH_H + #include "live_effects/effect.h" #include "live_effects/parameter/parameter.h" #include "live_effects/parameter/random.h" @@ -59,3 +58,14 @@ private: } //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/lpegroupbbox.cpp b/src/live_effects/lpegroupbbox.cpp index 3b1ece2ad..3820b5ba7 100644 --- a/src/live_effects/lpegroupbbox.cpp +++ b/src/live_effects/lpegroupbbox.cpp @@ -37,7 +37,7 @@ GroupBBoxEffect::original_bbox(SPLPEItem *lpeitem, bool absolute) transform = Geom::identity(); } - boost::optional<Geom::Rect> bbox = item->getBounds(transform, SPItem::GEOMETRIC_BBOX); + Geom::OptRect bbox = item->getBounds(transform, SPItem::GEOMETRIC_BBOX); if (bbox) { boundingbox_X = (*bbox)[Geom::X]; boundingbox_Y = (*bbox)[Geom::Y]; diff --git a/src/live_effects/parameter/CMakeLists.txt b/src/live_effects/parameter/CMakeLists.txt index d7775f44d..f93d8910a 100644 --- a/src/live_effects/parameter/CMakeLists.txt +++ b/src/live_effects/parameter/CMakeLists.txt @@ -1,4 +1,5 @@ SET(live_effects_parameter_SRC +array.cpp bool.cpp parameter.cpp path.cpp diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert index 869f4a7f4..3832e24cb 100644 --- a/src/live_effects/parameter/Makefile_insert +++ b/src/live_effects/parameter/Makefile_insert @@ -8,14 +8,14 @@ live_effects/parameter/clean: live_effects_parameter_liblpeparam_a_SOURCES = \ live_effects/parameter/parameter.cpp \ live_effects/parameter/parameter.h \ + live_effects/parameter/array.cpp \ + live_effects/parameter/array.h \ live_effects/parameter/bool.cpp \ live_effects/parameter/bool.h \ live_effects/parameter/random.cpp \ live_effects/parameter/random.h \ live_effects/parameter/point.cpp \ live_effects/parameter/point.h \ - live_effects/parameter/pointparam-knotholder.cpp \ - live_effects/parameter/pointparam-knotholder.h \ live_effects/parameter/enum.h \ live_effects/parameter/path-reference.cpp \ live_effects/parameter/path-reference.h \ diff --git a/src/live_effects/parameter/array.cpp b/src/live_effects/parameter/array.cpp new file mode 100644 index 000000000..c576bedd5 --- /dev/null +++ b/src/live_effects/parameter/array.cpp @@ -0,0 +1,51 @@ +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ARRAY_CPP + +/* + * Copyright (C) Johan Engelen 2008 <j.b.c.engelen@utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/parameter/array.h" + +#include "svg/svg.h" +#include "svg/stringstream.h" + +#include <2geom/coord.h> + +namespace Inkscape { + +namespace LivePathEffect { + +template <> +double +ArrayParam<double>::readsvg(const gchar * str) +{ + double newx = Geom::infinity(); + sp_svg_number_read_d(str, &newx); + return newx; +} + +template <> +float +ArrayParam<float>::readsvg(const gchar * str) +{ + float newx = Geom::infinity(); + sp_svg_number_read_f(str, &newx); + return newx; +} + +} /* 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/array.h b/src/live_effects/parameter/array.h new file mode 100644 index 000000000..4da329c4d --- /dev/null +++ b/src/live_effects/parameter/array.h @@ -0,0 +1,123 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ARRAY_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ARRAY_H + +/* + * Inkscape::LivePathEffectParameters + * +* Copyright (C) Johan Engelen 2008 <j.b.c.engelen@utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <vector> + +#include <glib/gtypes.h> + +#include <gtkmm/tooltips.h> + +#include "live_effects/parameter/parameter.h" + +#include "svg/svg.h" +#include "svg/stringstream.h" + +namespace Inkscape { + +namespace LivePathEffect { + +template <typename StorageType> +class ArrayParam : public Parameter { +public: + ArrayParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + size_t n = 0 ) + : Parameter(label, tip, key, wr, effect), _vector(n) + { + + } + + virtual ~ArrayParam() { + + }; + + std::vector<StorageType> const & data() const { + return _vector; + } + + virtual Gtk::Widget * param_newWidget(Gtk::Tooltips * /*tooltips*/) { + return NULL; + } + + virtual bool param_readSVGValue(const gchar * strvalue) { + _vector.clear(); + gchar ** strarray = g_strsplit(strvalue, "|", 0); + gchar ** iter = strarray; + while (*iter != NULL) { + _vector.push_back( readsvg(*iter) ); + iter++; + } + g_strfreev (strarray); + return true; + } + + virtual gchar * param_getSVGValue() const { + Inkscape::SVGOStringStream os; + writesvg(os, _vector); + gchar * str = g_strdup(os.str().c_str()); + return str; + } + + void param_setValue(std::vector<StorageType> const &new_vector) { + _vector = new_vector; + } + + void param_set_default() { + param_setValue( std::vector<StorageType>() ); + } + + void param_set_and_write_new_value(std::vector<StorageType> const &new_vector) { + Inkscape::SVGOStringStream os; + writesvg(os, new_vector); + gchar * str = g_strdup(os.str().c_str()); + param_write_to_repr(str); + g_free(str); + } + +private: + ArrayParam(const ArrayParam&); + ArrayParam& operator=(const ArrayParam&); + + std::vector<StorageType> _vector; + + void writesvg(SVGOStringStream &str, std::vector<StorageType> const &vector) const { + for (unsigned int i = 0; i < vector.size(); ++i) { + if (i != 0) { + // separate items with pipe symbol + str << " | "; + } + str << vector[i]; + } + } + + StorageType readsvg(const gchar * str); +}; + + +} //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 : diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index aac3dfa69..71bd5673d 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -60,7 +60,8 @@ public: virtual Glib::ustring * param_getTooltip() { return ¶m_tooltip; }; // overload these for your particular parameter to make it provide knotholder handles or canvas helperpaths - virtual void addKnotHolderEntities(KnotHolder */*knotholder*/, SPDesktop */*desktop*/, SPItem */*item*/) {} + virtual bool providesKnotHolderEntities() { return false; } + virtual void addKnotHolderEntities(KnotHolder */*knotholder*/, SPDesktop */*desktop*/, SPItem */*item*/) {}; virtual void addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/) {}; virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {}; diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp index 5d541eff8..057cc424b 100644 --- a/src/live_effects/parameter/point.cpp +++ b/src/live_effects/parameter/point.cpp @@ -7,7 +7,6 @@ */ #include "live_effects/parameter/point.h" -#include "live_effects/parameter/pointparam-knotholder.h" #include "live_effects/effect.h" #include "svg/svg.h" #include "svg/stringstream.h" diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h index ca440c1fc..ec61fcd88 100644 --- a/src/live_effects/parameter/point.h +++ b/src/live_effects/parameter/point.h @@ -49,14 +49,13 @@ public: void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + virtual bool providesKnotHolderEntities() { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); private: PointParam(const PointParam&); PointParam& operator=(const PointParam&); - void on_button_click(); - Geom::Point defvalue; SPKnotShapeType knot_shape; diff --git a/src/live_effects/parameter/pointparam-knotholder.cpp b/src/live_effects/parameter/pointparam-knotholder.cpp deleted file mode 100644 index b814f597d..000000000 --- a/src/live_effects/parameter/pointparam-knotholder.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#define INKSCAPE_LPE_POINTPARAM_KNOTHOLDER_C - -/* - * Container for PointParamKnotHolder visual handles - * - * Authors: - * Johan Engelen <goejendaagh@zonnet.nl> - * - * Copyright (C) 2008 authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "live_effects/parameter/pointparam-knotholder.h" -#include "live_effects/lpeobject.h" -#include "document.h" -#include "sp-shape.h" -#include "knot.h" -#include "knotholder.h" - -#include <glibmm/i18n.h> -#include <2geom/point.h> -#include <2geom/matrix.h> -#include "svg/stringstream.h" -#include "xml/repr.h" - -class SPDesktop; - -namespace Inkscape { - -static void pointparam_knot_clicked_handler (SPKnot *knot, guint state, PointParamKnotHolder *kh); -static void pointparam_knot_moved_handler(SPKnot *knot, Geom::Point const *p, guint state, PointParamKnotHolder *kh); -static void pointparam_knot_ungrabbed_handler (SPKnot *knot, unsigned int state, PointParamKnotHolder *kh); - -PointParamKnotHolder::PointParamKnotHolder(SPDesktop *desktop, SPObject *lpeobject, const gchar * key, SPItem *item) -{ - if (!desktop || !item || !SP_IS_ITEM(item)) { - g_print ("Error! Throw an exception, please!\n"); - } - - this->desktop = desktop; - this->item = item; - this->lpeobject = LIVEPATHEFFECT(lpeobject); - g_object_ref(G_OBJECT(item)); - g_object_ref(G_OBJECT(lpeobject)); - - this->released = NULL; - - this->repr = lpeobject->repr; - this->repr_key = key; - - this->local_change = FALSE; -} - -PointParamKnotHolder::~PointParamKnotHolder() -{ - g_object_unref(G_OBJECT(this->item)); - g_object_unref(G_OBJECT(this->lpeobject)); -} - -class KnotHolderEntityPointParam : public LPEKnotHolderEntity { -public: - virtual Geom::Point knot_get(); - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); -}; - -Geom::Point -KnotHolderEntityPointParam::knot_get() { - return Geom::Point(0,0); -} - -void -KnotHolderEntityPointParam::knot_set(Geom::Point const &/*p*/, Geom::Point const &/*origin*/, guint /*state*/) { -} - -void -PointParamKnotHolder::add_knot ( - Geom::Point & p, -// TODO: check if knot_click being ignored is bad: - PointParamKnotHolderClickedFunc /*knot_click*/, - SPKnotShapeType shape, - SPKnotModeType mode, - guint32 color, - const gchar *tip ) -{ - /* create new SPKnotHolderEntry */ - KnotHolderEntity *e = new KnotHolderEntityPointParam(); - e->create(this->desktop, this->item, this, tip, shape, mode, color); - - entity.push_back(e); - - // Move to current point. - Geom::Point dp = p * sp_item_i2d_affine(item); - sp_knot_set_position(e->knot, dp, SP_KNOT_STATE_NORMAL); - - e->handler_id = g_signal_connect(e->knot, "moved", G_CALLBACK(pointparam_knot_moved_handler), this); - e->_click_handler_id = g_signal_connect(e->knot, "clicked", G_CALLBACK(pointparam_knot_clicked_handler), this); - e->_ungrab_handler_id = g_signal_connect(e->knot, "ungrabbed", G_CALLBACK(pointparam_knot_ungrabbed_handler), this); - - sp_knot_show(e->knot); -} - -static void pointparam_knot_clicked_handler(SPKnot */*knot*/, guint /*state*/, PointParamKnotHolder */*kh*/) -{ - -} - -/** - * \param p In desktop coordinates. - * This function does not write to XML, but tries to write directly to the PointParam to quickly live update the effect - */ -static void pointparam_knot_moved_handler(SPKnot */*knot*/, Geom::Point const *p, guint /*state*/, PointParamKnotHolder *kh) -{ - Geom::Matrix const i2d(sp_item_i2d_affine(kh->getItem())); - Geom::Point pos = (*p) * i2d.inverse(); - - Inkscape::SVGOStringStream os; - os << pos; - - // note: get_lpe() will always return a valid pointer? - kh->lpeobject->get_lpe()->setParameter(kh->repr_key, os.str().c_str()); -} - -static void pointparam_knot_ungrabbed_handler(SPKnot *knot, unsigned int /*state*/, PointParamKnotHolder *kh) -{ - Geom::Matrix const i2d(sp_item_i2d_affine(kh->getItem())); - Geom::Point pos = sp_knot_position(knot) * i2d.inverse(); - - Inkscape::SVGOStringStream os; - os << pos; - - kh->repr->setAttribute(kh->repr_key , os.str().c_str()); - - sp_document_done(SP_OBJECT_DOCUMENT (kh->lpeobject), SP_VERB_CONTEXT_LPE, _("Change LPE point parameter")); -} - -} // 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/parameter/pointparam-knotholder.h b/src/live_effects/parameter/pointparam-knotholder.h deleted file mode 100644 index f6dfdead5..000000000 --- a/src/live_effects/parameter/pointparam-knotholder.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef INKSCAPE_LPE_POINTPARAM_KNOTHOLDER_H -#define INKSCAPE_LPE_POINTPARAM_KNOTHOLDER_H - -/* - * PointParamKnotHolder - Hold SPKnot list and manage signals for LPE PointParam - * - * Author: - * Johan Engelen <goejendaagh@zonnet.nl> - * - * Copyright (C) 2008 Johan Engelen - * - * Released under GNU GPL - * - */ - -#include "knotholder.h" -#include <glib/gtypes.h> -#include "knot-enums.h" -#include "forward.h" -#include "libnr/nr-forward.h" -#include <2geom/point.h> -#include "live_effects/lpeobject.h" - -namespace Inkscape { -namespace XML { -class Node; -} - - - -typedef void (* PointParamKnotHolderSetFunc) (SPItem *item, Geom::Point const &p, Geom::Point const &origin, guint state); -typedef Geom::Point (* PointParamKnotHolderGetFunc) (SPItem *item); -typedef void (* PointParamKnotHolderClickedFunc) (SPItem *item, guint state); - -class PointParamKnotHolder : public KnotHolder { -public: - PointParamKnotHolder(SPDesktop *desktop, SPObject *lpeobject, const gchar * key, SPItem *item); - ~PointParamKnotHolder(); - - LivePathEffectObject * lpeobject; - Inkscape::XML::Node * repr; - const gchar * repr_key; - - void add_knot ( Geom::Point & p, - PointParamKnotHolderClickedFunc knot_click, - SPKnotShapeType shape, - SPKnotModeType mode, - guint32 color, - const gchar *tip ); -}; - -} // namespace Inkscape - - -#endif /* INKSCAPE_LPE_POINTPARAM_KNOTHOLDER_H */ - -/* - 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/vector.cpp b/src/live_effects/parameter/vector.cpp index 90d9ebff9..9a68334fd 100644 --- a/src/live_effects/parameter/vector.cpp +++ b/src/live_effects/parameter/vector.cpp @@ -7,32 +7,190 @@ */ #include "live_effects/parameter/vector.h" - +#include "sp-lpe-item.h" +#include "knotholder.h" #include "svg/svg.h" #include "svg/stringstream.h" +#include <gtkmm.h> -#include <2geom/coord.h> +// needed for on-canvas editting: +class SPDesktop; namespace Inkscape { namespace LivePathEffect { -template <> -double -VectorParam<double>::readsvg(const gchar * str) +VectorParam::VectorParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, Geom::Point default_vector) + : Parameter(label, tip, key, wr, effect), + defvalue(default_vector), + origin(0.,0.), + vector(default_vector) +{ + vec_knot_shape = SP_KNOT_SHAPE_DIAMOND; + vec_knot_mode = SP_KNOT_MODE_XOR; + vec_knot_color = 0xffffb500; + ori_knot_shape = SP_KNOT_SHAPE_CIRCLE; + ori_knot_mode = SP_KNOT_MODE_XOR; + ori_knot_color = 0xffffb500; +} + +VectorParam::~VectorParam() +{ + +} + +void +VectorParam::param_set_default() +{ + setOrigin(Geom::Point(0.,0.)); + setVector(defvalue); +} + +bool +VectorParam::param_readSVGValue(const gchar * strvalue) +{ + gchar ** strarray = g_strsplit(strvalue, ",", 4); + double val[4]; + unsigned int i = 0; + while (strarray[i] && i < 4) { + if (sp_svg_number_read_d(strarray[i], &val[i]) != 0) { + i++; + } else { + break; + } + } + g_strfreev (strarray); + if (i == 4) { + setOrigin( Geom::Point(val[0], val[1]) ); + setVector( Geom::Point(val[2], val[3]) ); + return true; + } + return false; +} + +gchar * +VectorParam::param_getSVGValue() const +{ + Inkscape::SVGOStringStream os; + os << origin << " , " << vector; + gchar * str = g_strdup(os.str().c_str()); + return str; +} + +Gtk::Widget * +VectorParam::param_newWidget(Gtk::Tooltips * /*tooltips*/) +{ +/* + 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); + */ return NULL; +} + +void +VectorParam::set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector) +{ + setValues(new_origin, new_vector); + gchar * str = param_getSVGValue(); + param_write_to_repr(str); + g_free(str); +} + +void +VectorParam::param_transform_multiply(Geom::Matrix const& postmul, bool /*set*/) +{ + set_and_write_new_values( origin * postmul, vector * postmul ); +} + + +void +VectorParam::set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) { - double newx = Geom::infinity(); - sp_svg_number_read_d(str, &newx); - return newx; + vec_knot_shape = shape; + vec_knot_mode = mode; + vec_knot_color = color; } -template <> -float -VectorParam<float>::readsvg(const gchar * str) +void +VectorParam::set_origin_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) { - float newx = Geom::infinity(); - sp_svg_number_read_f(str, &newx); - return newx; + ori_knot_shape = shape; + ori_knot_mode = mode; + ori_knot_color = color; +} + +class VectorParamKnotHolderEntity_Origin : public LPEKnotHolderEntity { +public: + VectorParamKnotHolderEntity_Origin(VectorParam *p) : param(p) { } + virtual ~VectorParamKnotHolderEntity_Origin() {} + + virtual void knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint /*state*/) { + Geom::Point const s = snap_knot_position(p); + param->setOrigin(s); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + }; + virtual Geom::Point knot_get(){ + return param->origin; + }; + virtual void knot_click(guint /*state*/){ + g_print ("This is the origin handle associated to parameter '%s'\n", param->param_key.c_str()); + }; + +private: + VectorParam *param; +}; + +class VectorParamKnotHolderEntity_Vector : public LPEKnotHolderEntity { +public: + VectorParamKnotHolderEntity_Vector(VectorParam *p) : param(p) { } + virtual ~VectorParamKnotHolderEntity_Vector() {} + + virtual void knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) { + Geom::Point const s = p - param->origin; + /// @todo implement angle snapping when holding CTRL + param->setVector(s); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + }; + virtual Geom::Point knot_get(){ + return param->origin + param->vector; + }; + virtual void knot_click(guint /*state*/){ + g_print ("This is the vector handle associated to parameter '%s'\n", param->param_key.c_str()); + }; + +private: + VectorParam *param; +}; + +void +VectorParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +{ + VectorParamKnotHolderEntity_Origin *origin_e = new VectorParamKnotHolderEntity_Origin(this); + origin_e->create(desktop, item, knotholder, handleTip(), ori_knot_shape, ori_knot_mode, ori_knot_color); + knotholder->add(origin_e); + + VectorParamKnotHolderEntity_Vector *vector_e = new VectorParamKnotHolderEntity_Vector(this); + vector_e->create(desktop, item, knotholder, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color); + knotholder->add(vector_e); } } /* namespace LivePathEffect */ diff --git a/src/live_effects/parameter/vector.h b/src/live_effects/parameter/vector.h index 0b65fea14..a4c29d317 100644 --- a/src/live_effects/parameter/vector.h +++ b/src/live_effects/parameter/vector.h @@ -4,27 +4,25 @@ /* * Inkscape::LivePathEffectParameters * -* Copyright (C) Johan Engelen 2008 <j.b.c.engelen@utwente.nl> + * Copyright (C) Johan Engelen 2008 <j.b.c.engelen@utwente.nl> * * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <vector> - #include <glib/gtypes.h> +#include <2geom/point.h> #include <gtkmm/tooltips.h> #include "live_effects/parameter/parameter.h" -#include "svg/svg.h" -#include "svg/stringstream.h" +#include "knot-holder-entity.h" namespace Inkscape { namespace LivePathEffect { -template <typename StorageType> + class VectorParam : public Parameter { public: VectorParam( const Glib::ustring& label, @@ -32,76 +30,51 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - size_t n = 0 ) - : Parameter(label, tip, key, wr, effect), _vector(n) - { - - } - - virtual ~VectorParam() { - - }; - - std::vector<StorageType> const & data() const { - return _vector; - } - - virtual Gtk::Widget * param_newWidget(Gtk::Tooltips * /*tooltips*/) { - return NULL; - } - - virtual bool param_readSVGValue(const gchar * strvalue) { - _vector.clear(); - gchar ** strarray = g_strsplit(strvalue, "|", 0); - gchar ** iter = strarray; - while (*iter != NULL) { - _vector.push_back( readsvg(*iter) ); - iter++; - } - g_strfreev (strarray); - return true; - } - - virtual gchar * param_getSVGValue() const { - Inkscape::SVGOStringStream os; - writesvg(os, _vector); - gchar * str = g_strdup(os.str().c_str()); - return str; - } - - void param_setValue(std::vector<StorageType> const &new_vector) { - _vector = new_vector; - } - - void param_set_default() { - param_setValue( std::vector<StorageType>() ); - } - - void param_set_and_write_new_value(std::vector<StorageType> const &new_vector) { - Inkscape::SVGOStringStream os; - writesvg(os, new_vector); - gchar * str = g_strdup(os.str().c_str()); - param_write_to_repr(str); - g_free(str); - } + Geom::Point default_vector = Geom::Point(1,0) ); + virtual ~VectorParam(); + + virtual Gtk::Widget * param_newWidget(Gtk::Tooltips * tooltips); + inline const gchar *handleTip() const { return param_tooltip.c_str(); } + + virtual bool param_readSVGValue(const gchar * strvalue); + virtual gchar * param_getSVGValue() const; + + Geom::Point getVector() const { return vector; }; + Geom::Point getOrigin() const { return origin; }; + void setValues(Geom::Point const &new_origin, Geom::Point const &new_vector) { setVector(new_vector); setOrigin(new_origin); }; + void setVector(Geom::Point const &new_vector) { vector = new_vector; }; + void setOrigin(Geom::Point const &new_origin) { origin = new_origin; }; + virtual void param_set_default(); + + void set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector); + + virtual void param_transform_multiply(Geom::Matrix const &postmul, bool set); + + void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + void set_origin_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + + virtual bool providesKnotHolderEntities() { return true; } + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); private: VectorParam(const VectorParam&); VectorParam& operator=(const VectorParam&); - std::vector<StorageType> _vector; + Geom::Point defvalue; - void writesvg(SVGOStringStream &str, std::vector<StorageType> const &vector) const { - for (unsigned int i = 0; i < vector.size(); ++i) { - if (i != 0) { - // separate items with pipe symbol - str << " | "; - } - str << vector[i]; - } - } + Geom::Point origin; + Geom::Point vector; - StorageType readsvg(const gchar * str); + /// The looks of the vector and origin knots oncanvas + SPKnotShapeType vec_knot_shape; + SPKnotModeType vec_knot_mode; + guint32 vec_knot_color; + SPKnotShapeType ori_knot_shape; + SPKnotModeType ori_knot_mode; + guint32 ori_knot_color; + + friend class VectorParamKnotHolderEntity_Origin; + friend class VectorParamKnotHolderEntity_Vector; }; @@ -110,14 +83,3 @@ private: } //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 : |
