summaryrefslogtreecommitdiffstats
path: root/src/live_effects
diff options
context:
space:
mode:
authorTed Gould <ted@gould.cx>2008-11-21 05:24:08 +0000
committerTed Gould <ted@canonical.com>2008-11-21 05:24:08 +0000
commit44a3a78fb6a3863c0c7f3c1193837337e68a67e4 (patch)
tree1722ee5ec6f88c881cd4124923354b3c1311501b /src/live_effects
parentMerge from trunk (diff)
downloadinkscape-44a3a78fb6a3863c0c7f3c1193837337e68a67e4.tar.gz
inkscape-44a3a78fb6a3863c0c7f3c1193837337e68a67e4.zip
Merge from fe-moved
(bzr r6891)
Diffstat (limited to 'src/live_effects')
-rw-r--r--src/live_effects/CMakeLists.txt1
-rw-r--r--src/live_effects/Makefile_insert3
-rw-r--r--src/live_effects/effect-enum.h72
-rw-r--r--src/live_effects/effect.cpp10
-rw-r--r--src/live_effects/effect.h42
-rw-r--r--src/live_effects/lpe-circle_with_radius.cpp25
-rw-r--r--src/live_effects/lpe-circle_with_radius.h31
-rw-r--r--src/live_effects/lpe-curvestitch.cpp37
-rw-r--r--src/live_effects/lpe-hatches.cpp593
-rw-r--r--src/live_effects/lpe-hatches.h77
-rw-r--r--src/live_effects/lpe-interpolate.cpp28
-rw-r--r--src/live_effects/lpe-knot.cpp104
-rw-r--r--src/live_effects/lpe-knot.h23
-rw-r--r--src/live_effects/lpe-patternalongpath.cpp195
-rw-r--r--src/live_effects/lpe-patternalongpath.h1
-rw-r--r--src/live_effects/lpe-perspective_path.cpp25
-rw-r--r--src/live_effects/lpe-perspective_path.h32
-rw-r--r--src/live_effects/lpe-skeleton.cpp17
-rw-r--r--src/live_effects/lpe-skeleton.h20
-rw-r--r--src/live_effects/lpe-sketch.cpp28
-rw-r--r--src/live_effects/lpe-sketch.h30
-rw-r--r--src/live_effects/lpegroupbbox.cpp2
-rw-r--r--src/live_effects/parameter/CMakeLists.txt1
-rw-r--r--src/live_effects/parameter/Makefile_insert4
-rw-r--r--src/live_effects/parameter/array.cpp51
-rw-r--r--src/live_effects/parameter/array.h123
-rw-r--r--src/live_effects/parameter/parameter.h3
-rw-r--r--src/live_effects/parameter/point.cpp1
-rw-r--r--src/live_effects/parameter/point.h3
-rw-r--r--src/live_effects/parameter/pointparam-knotholder.cpp148
-rw-r--r--src/live_effects/parameter/pointparam-knotholder.h66
-rw-r--r--src/live_effects/parameter/vector.cpp186
-rw-r--r--src/live_effects/parameter/vector.h122
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 &times,
+ 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 *>(&copytype) );
@@ -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 &param_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 :