summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: e027cc2)
raw | patch | inline | side by side (parent: e027cc2)
author | jfbarraud <jfbarraud@users.sourceforge.net> | |
Wed, 26 Nov 2008 20:56:08 +0000 (20:56 +0000) | ||
committer | jfbarraud <jfbarraud@users.sourceforge.net> | |
Wed, 26 Nov 2008 20:56:08 +0000 (20:56 +0000) |
src/live_effects/CMakeLists.txt | patch | blob | history | |
src/live_effects/effect-enum.h | patch | blob | history | |
src/live_effects/effect.cpp | patch | blob | history | |
src/live_effects/lpe-hatches.cpp | [deleted file] | patch | blob | history |
src/live_effects/lpe-hatches.h | [deleted file] | patch | blob | history |
src/live_effects/lpe-rough-hatches.cpp | [new file with mode: 0644] | patch | blob |
src/live_effects/lpe-rough-hatches.h | [new file with mode: 0644] | patch | blob |
index 89b7b9e3a7f72afdf15907e75d8665ee27d94451..72d955586b8bc9ab023f78ea7d2a7790e69af1c1 100644 (file)
lpegroupbbox.cpp
lpe-interpolate.cpp
lpe-knot.cpp
-lpe-hatches.cpp
+lpe-rough-hatches.cpp
lpe-lattice.cpp
lpe-mirror_symmetry.cpp
lpeobject.cpp
index 1e82954f8a4ca9295ae235d6963686aab640af02..4c0d9389f3436ec1f092a799218c29b8497a25c8 100644 (file)
PATTERN_ALONG_PATH,
FREEHAND_SHAPE,
SKETCH,
- HATCHES,
+ ROUGH_HATCHES,
VONKOCH,
KNOT,
#ifdef LPE_ENABLE_TEST_EFFECTS
index bb5f0c55465b196b830d3395f0e7b04106ecfcdb..2a316a0bb243df282db5398e082590080833b89c 100644 (file)
#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-rough-hatches.h"
#include "live_effects/lpe-test-doEffect-stack.h"
#include "live_effects/lpe-gears.h"
#include "live_effects/lpe-curvestitch.h"
namespace LivePathEffect {
const Util::EnumData<EffectType> LPETypeData[] = {
- // {constant defined in effect.h, N_("name of your effect"), "name of your effect in SVG"}
+ // {constant defined in effect-enum.h, N_("name of your effect"), "name of your effect in SVG"}
{ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"},
{BEND_PATH, N_("Bend"), "bend_path"},
{BOOLOPS, N_("Boolops"), "boolops"},
{COPY_ROTATE, N_("Rotate copies"), "copy_rotate"},
{RULER, N_("Ruler"), "ruler"},
{SKETCH, N_("Sketch"), "sketch"},
- {HATCHES, N_("Hatches"), "hatches"},
+ {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"},
{SPIRO, N_("Spiro spline"), "spiro"},
{CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"},
{TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},
case SKETCH:
neweffect = static_cast<Effect*> ( new LPESketch(lpeobj) );
break;
- case HATCHES:
- neweffect = static_cast<Effect*> ( new LPEHatches(lpeobj) );
+ case ROUGH_HATCHES:
+ neweffect = static_cast<Effect*> ( new LPERoughHatches(lpeobj) );
break;
case VONKOCH:
neweffect = static_cast<Effect*> ( new LPEVonKoch(lpeobj) );
diff --git a/src/live_effects/lpe-hatches.cpp b/src/live_effects/lpe-hatches.cpp
+++ /dev/null
@@ -1,593 +0,0 @@
-#define INKSCAPE_LPE_HATCHES_CPP\r
-/** \file\r
- * LPE Curve Stitching implementation, used as an example for a base starting class\r
- * when implementing new LivePathEffects.\r
- *\r
- */\r
-/*\r
- * Authors:\r
- * JF Barraud.\r
-*\r
-* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>\r
- *\r
- * Released under GNU GPL, read the file 'COPYING' for more information\r
- */\r
-\r
-#include "live_effects/lpe-hatches.h"\r
-\r
-#include "sp-item.h"\r
-#include "sp-path.h"\r
-#include "svg/svg.h"\r
-#include "xml/repr.h"\r
-\r
-#include <2geom/path.h>\r
-#include <2geom/piecewise.h>\r
-#include <2geom/sbasis.h>\r
-#include <2geom/sbasis-math.h>\r
-#include <2geom/sbasis-geometric.h>\r
-#include <2geom/bezier-to-sbasis.h>\r
-#include <2geom/sbasis-to-bezier.h>\r
-#include <2geom/d2.h>\r
-#include <2geom/matrix.h>\r
-\r
-#include "ui/widget/scalar.h"\r
-#include "libnr/nr-values.h"\r
-\r
-namespace Inkscape {\r
-namespace LivePathEffect {\r
-\r
-using namespace Geom;\r
-\r
-//------------------------------------------------\r
-// Some goodies to navigate through curve's levels.\r
-//------------------------------------------------\r
-struct LevelCrossing{\r
- Point pt;\r
- double t;\r
- bool sign;\r
- bool used;\r
- std::pair<unsigned,unsigned> next_on_curve;\r
- std::pair<unsigned,unsigned> prev_on_curve;\r
-};\r
-struct LevelCrossingOrder {\r
- bool operator()(LevelCrossing a, LevelCrossing b) {\r
- return a.pt[Y] < b.pt[Y];\r
- }\r
-};\r
-struct LevelCrossingInfo{\r
- double t;\r
- unsigned level;\r
- unsigned idx;\r
-};\r
-struct LevelCrossingInfoOrder {\r
- bool operator()(LevelCrossingInfo a, LevelCrossingInfo b) {\r
- return a.t < b.t;\r
- }\r
-};\r
-\r
-typedef std::vector<LevelCrossing> LevelCrossings;\r
-\r
-std::vector<double>\r
-discontinuities(Piecewise<D2<SBasis> > const &f){\r
- std::vector<double> result;\r
- if (f.size()==0) return result;\r
- result.push_back(f.cuts[0]);\r
- Point prev_pt = f.segs[0].at1();\r
- //double old_t = f.cuts[0];\r
- for(unsigned i=1; i<f.size(); i++){\r
- if ( f.segs[i].at0()!=prev_pt){\r
- result.push_back(f.cuts[i]);\r
- //old_t = f.cuts[i];\r
- //assert(f.segs[i-1].at1()==f.valueAt(old_t));\r
- }\r
- prev_pt = f.segs[i].at1();\r
- }\r
- result.push_back(f.cuts.back());\r
- //assert(f.segs.back().at1()==f.valueAt(old_t));\r
- return result;\r
-}\r
-\r
-class LevelsCrossings: public std::vector<LevelCrossings>{\r
-public:\r
- LevelsCrossings():std::vector<LevelCrossings>(){};\r
- LevelsCrossings(std::vector<std::vector<double> > const ×,\r
- Piecewise<D2<SBasis> > const &f,\r
- Piecewise<SBasis> const &dx){\r
- \r
- for (unsigned i=0; i<times.size(); i++){\r
- LevelCrossings lcs;\r
- for (unsigned j=0; j<times[i].size(); j++){\r
- LevelCrossing lc;\r
- lc.pt = f.valueAt(times[i][j]);\r
- lc.t = times[i][j];\r
- lc.sign = ( dx.valueAt(times[i][j])>0 );\r
- lc.used = false;\r
- lcs.push_back(lc);\r
- }\r
- std::sort(lcs.begin(), lcs.end(), LevelCrossingOrder());\r
- push_back(lcs);\r
- }\r
- //Now create time ordering.\r
- std::vector<LevelCrossingInfo>temp;\r
- for (unsigned i=0; i<size(); i++){\r
- for (unsigned j=0; j<(*this)[i].size(); j++){\r
- LevelCrossingInfo elem;\r
- elem.t = (*this)[i][j].t;\r
- elem.level = i;\r
- elem.idx = j;\r
- temp.push_back(elem);\r
- }\r
- }\r
- std::sort(temp.begin(),temp.end(),LevelCrossingInfoOrder());\r
- std::vector<double> jumps = discontinuities(f);\r
- unsigned jump_idx = 0;\r
- unsigned first_in_comp = 0;\r
- for (unsigned i=0; i<temp.size(); i++){\r
- unsigned lvl = temp[i].level, idx = temp[i].idx;\r
- if ( i == temp.size()-1 || temp[i+1].t > jumps[jump_idx+1]){\r
- std::pair<unsigned,unsigned>next_data(temp[first_in_comp].level,temp[first_in_comp].idx);\r
- (*this)[lvl][idx].next_on_curve = next_data;\r
- first_in_comp = i+1;\r
- jump_idx += 1;\r
- }else{\r
- std::pair<unsigned,unsigned> next_data(temp[i+1].level,temp[i+1].idx);\r
- (*this)[lvl][idx].next_on_curve = next_data;\r
- }\r
- }\r
-\r
- for (unsigned i=0; i<size(); i++){\r
- for (unsigned j=0; j<(*this)[i].size(); j++){\r
- std::pair<unsigned,unsigned> next = (*this)[i][j].next_on_curve;\r
- (*this)[next.first][next.second].prev_on_curve = std::pair<unsigned,unsigned>(i,j);\r
- }\r
- }\r
-#if 0\r
- std::cout<<"\n";\r
- for (unsigned i=0; i<temp.size()-1; i++){\r
- std::cout<<temp[i].level<<","<<temp[i].idx<<" -> ";\r
- }\r
- std::cout<<"\n";\r
- for (unsigned i=0; i<size(); i++){\r
- for (unsigned j=0; j<(*this)[i].size(); j++){\r
- std::cout<<"level:"<<i<<", idx:"<<j<<" - ";\r
- std::cout<<"next:"<<(*this)[i][j].next_on_curve.first<<",";\r
- std::cout<<(*this)[i][j].next_on_curve.second<<" - ";\r
- std::cout<<"prev:"<<(*this)[i][j].prev_on_curve.first<<",";\r
- std::cout<<(*this)[i][j].prev_on_curve.second<<"\n";\r
- }\r
- }\r
-#endif\r
- }\r
-\r
- void findFirstUnused(unsigned &level, unsigned &idx){\r
- level = size();\r
- idx = 0;\r
- for (unsigned i=0; i<size(); i++){\r
- for (unsigned j=0; j<(*this)[i].size(); j++){\r
- if (!(*this)[i][j].used){\r
- level = i;\r
- idx = j;\r
- return;\r
- }\r
- }\r
- }\r
- }\r
- //set indexes to point to the next point in the "snake walk"\r
- //follow_level's meaning: \r
- // 0=yes upward\r
- // 1=no, last move was upward,\r
- // 2=yes downward\r
- // 3=no, last move was downward.\r
- void step(unsigned &level, unsigned &idx, int &direction){\r
- if ( direction % 2 == 0 ){\r
- if (direction == 0) {\r
- if ( idx >= (*this)[level].size()-1 || (*this)[level][idx+1].used ) {\r
- level = size();\r
- return;\r
- }\r
- idx += 1;\r
- }else{\r
- if ( idx <= 0 || (*this)[level][idx-1].used ) {\r
- level = size();\r
- return;\r
- }\r
- idx -= 1;\r
- }\r
- direction += 1;\r
- return;\r
- }\r
- double t = (*this)[level][idx].t;\r
- double sign = ((*this)[level][idx].sign ? 1 : -1);\r
- double next_t = t;\r
- //level += 1;\r
- direction = (direction + 1)%4;\r
- if (level == size()){\r
- return;\r
- }\r
-\r
- std::pair<unsigned,unsigned> next;\r
- if ( sign > 0 ){\r
- next = (*this)[level][idx].next_on_curve;\r
- }else{\r
- next = (*this)[level][idx].prev_on_curve;\r
- }\r
-\r
- if ( level+1 != next.first || (*this)[next.first][next.second].used ) {\r
- level = size();\r
- return;\r
- }\r
- level = next.first;\r
- idx = next.second;\r
-\r
-/*********************\r
- //look for next time on the same level\r
- for (unsigned j=0; j<(*this)[level].size(); j++){\r
- double tj = (*this)[level][j].t;\r
- if ( sign*(tj-t) > 0 ){\r
- if( next_t == t || sign*(tj-next_t)<0 ){\r
- next_t = tj;\r
- idx = j;\r
- }\r
- }\r
- }\r
- if ( next_t == t ){//not found? look at max/min time in this component, as time is "periodic".\r
- for (unsigned j=0; j<(*this)[level].size(); j++){\r
- double tj = (*this)[level][j].t;\r
- if ( -sign*(tj-next_t) > 0 ){\r
- next_t = tj;\r
- idx = j;\r
- }\r
- }\r
- }\r
- if ( next_t == t ){//still not found? houch! this should not happen.\r
- level = size();\r
- return;\r
- }\r
- if ( (*this)[level][idx].used ) {\r
- level = size();\r
- return;\r
- }\r
-*************************/\r
- return;\r
- }\r
-};\r
-\r
-//-------------------------------------------------------\r
-// Bend a path...\r
-//-------------------------------------------------------\r
-\r
-Piecewise<D2<SBasis> > bend(Piecewise<D2<SBasis> > const &f, Piecewise<SBasis> bending){\r
- D2<Piecewise<SBasis> > ff = make_cuts_independent(f);\r
- ff[X] += compose(bending, ff[Y]);\r
- return sectionize(ff);\r
-}\r
-\r
-//--------------------------------------------------------\r
-// The Hatches lpe.\r
-//--------------------------------------------------------\r
-LPEHatches::LPEHatches(LivePathEffectObject *lpeobject) :\r
- Effect(lpeobject),\r
- dist_rdm(_("Dist randomness"), _("Variation of dist between hatches, in %."), "dist_rdm", &wr, this, 75),\r
- growth(_("Growth"), _("Growth of distance between hatches."), "growth", &wr, this, 0.),\r
- scale_tf(_("Start smothness (front side)"), _("MISSING DESCRIPTION"), "scale_tf", &wr, this, 1.),\r
- scale_tb(_("Start smothness (back side)"), _("MISSING DESCRIPTION"), "scale_tb", &wr, this, 1.),\r
- scale_bf(_("End smothness (front side)"), _("MISSING DESCRIPTION"), "scale_bf", &wr, this, 1.),\r
- scale_bb(_("End smothness (back side)"), _("MISSING DESCRIPTION"), "scale_bb", &wr, this, 1.),\r
- top_edge_variation(_("Start edge variance"), _("The amount of random jitter to move the hatches start"), "top_edge_variation", &wr, this, 0),\r
- bot_edge_variation(_("End edge variance"), _("The amount of random jitter to move the hatches end"), "bot_edge_variation", &wr, this, 0),\r
- 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),\r
- 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),\r
- top_smth_variation(_("Start smoothness variance"), _("Randomness of the smoothness of the U turn at hatches start"), "top_smth_variation", &wr, this, 0),\r
- bot_smth_variation(_("End spacing variance"), _("Randomness of the smoothness of the U turn at hatches end"), "bot_smth_variation", &wr, this, 0),\r
- fat_output(_("Generate thick/thin path"), _("Simulate a stroke of varrying width"), "fat_output", &wr, this, true),\r
- do_bend(_("Bend hatches"), _("Add a global bend to the hatches (slower)"), "do_bend", &wr, this, true),\r
- stroke_width_top(_("Stroke width (start side)"), _("Width at hatches 'start'"), "stroke_width_top", &wr, this, 1.),\r
- stroke_width_bot(_("Stroke width (end side)"), _("Width at hatches 'end'"), "stroke_width_bot", &wr, this, 1.),\r
- front_thickness(_("Front thickness (%)"), _("MISSING DESCRIPTION"), "front_thickness", &wr, this, 1.),\r
- back_thickness(_("Back thickness (%)"), _("MISSING DESCRIPTION"), "back_thickness", &wr, this, .25),\r
- bender(_("Global bending"), _("Relative position to ref point defines global bending direction and amount"), "bender", &wr, this, NULL, Geom::Point(-5,0)),\r
- direction(_("Hatches width and dir"), _("Defines hatches frequency and direction"), "direction", &wr, this, Geom::Point(50,0))\r
-{\r
- registerParameter( dynamic_cast<Parameter *>(&direction) );\r
- registerParameter( dynamic_cast<Parameter *>(&do_bend) );\r
- registerParameter( dynamic_cast<Parameter *>(&bender) );\r
- registerParameter( dynamic_cast<Parameter *>(&dist_rdm) );\r
- registerParameter( dynamic_cast<Parameter *>(&growth) );\r
- registerParameter( dynamic_cast<Parameter *>(&top_edge_variation) );\r
- registerParameter( dynamic_cast<Parameter *>(&bot_edge_variation) );\r
- registerParameter( dynamic_cast<Parameter *>(&top_tgt_variation) );\r
- registerParameter( dynamic_cast<Parameter *>(&bot_tgt_variation) );\r
- registerParameter( dynamic_cast<Parameter *>(&scale_tf) );\r
- registerParameter( dynamic_cast<Parameter *>(&scale_tb) );\r
- registerParameter( dynamic_cast<Parameter *>(&scale_bf) );\r
- registerParameter( dynamic_cast<Parameter *>(&scale_bb) );\r
- registerParameter( dynamic_cast<Parameter *>(&top_smth_variation) );\r
- registerParameter( dynamic_cast<Parameter *>(&bot_smth_variation) );\r
- registerParameter( dynamic_cast<Parameter *>(&fat_output) );\r
- registerParameter( dynamic_cast<Parameter *>(&stroke_width_top) );\r
- registerParameter( dynamic_cast<Parameter *>(&stroke_width_bot) );\r
- registerParameter( dynamic_cast<Parameter *>(&front_thickness) );\r
- registerParameter( dynamic_cast<Parameter *>(&back_thickness) );\r
-\r
- //hatch_dist.param_set_range(0.1, NR_HUGE);\r
- growth.param_set_range(-0.95, NR_HUGE);\r
- dist_rdm.param_set_range(0, 99.);\r
- stroke_width_top.param_set_range(0, NR_HUGE);\r
- stroke_width_bot.param_set_range(0, NR_HUGE);\r
- front_thickness.param_set_range(0, NR_HUGE);\r
- back_thickness.param_set_range(0, NR_HUGE);\r
-\r
- concatenate_before_pwd2 = true;\r
- show_orig_path = true;\r
-}\r
-\r
-LPEHatches::~LPEHatches()\r
-{\r
-\r
-}\r
-\r
-Geom::Piecewise<Geom::D2<Geom::SBasis> > \r
-LPEHatches::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in){\r
-\r
- Piecewise<D2<SBasis> > result;\r
- \r
- Piecewise<D2<SBasis> > transformed_pwd2_in = pwd2_in;\r
- Piecewise<SBasis> tilter;//used to bend the hatches\r
- Matrix bend_mat;//used to bend the hatches\r
-\r
- if (do_bend.get_value()){\r
- Point bend_dir = -rot90(unit_vector(direction.getOrigin() - bender));\r
- double bend_amount = L2(direction.getOrigin() - bender);\r
- bend_mat = Matrix(-bend_dir[Y], bend_dir[X], bend_dir[X], bend_dir[Y],0,0);\r
- transformed_pwd2_in = pwd2_in * bend_mat;\r
- tilter = Piecewise<SBasis>(shift(Linear(bend_amount),1));\r
- OptRect bbox = bounds_exact( transformed_pwd2_in );\r
- if (not(bbox)) return pwd2_in;\r
- tilter.setDomain((*bbox)[Y]);\r
- transformed_pwd2_in = bend(transformed_pwd2_in, tilter);\r
- transformed_pwd2_in = transformed_pwd2_in * bend_mat.inverse();\r
- }\r
- hatch_dist = Geom::L2(direction.getVector())/5;\r
- Point hatches_dir = rot90(unit_vector(direction.getVector()));\r
- Matrix mat(-hatches_dir[Y], hatches_dir[X], hatches_dir[X], hatches_dir[Y],0,0);\r
- transformed_pwd2_in = transformed_pwd2_in * mat;\r
- \r
- std::vector<std::vector<Point> > snakePoints;\r
- snakePoints = linearSnake(transformed_pwd2_in);\r
- if ( snakePoints.size() > 0 ){\r
- Piecewise<D2<SBasis> >smthSnake = smoothSnake(snakePoints); \r
- smthSnake = smthSnake*mat.inverse();\r
- if (do_bend.get_value()){\r
- smthSnake = smthSnake*bend_mat;\r
- smthSnake = bend(smthSnake, -tilter);\r
- smthSnake = smthSnake*bend_mat.inverse();\r
- }\r
- return (smthSnake);\r
- }\r
- return pwd2_in;\r
-}\r
-\r
-//------------------------------------------------\r
-// Generate the levels with random, growth...\r
-//------------------------------------------------\r
-std::vector<double>\r
-LPEHatches::generateLevels(Interval const &domain){\r
- std::vector<double> result;\r
- double x = domain.min() + double(hatch_dist)/2.;\r
- double step = double(hatch_dist);\r
- double scale = 1+(hatch_dist*growth/domain.extent());\r
- while (x < domain.max()){\r
- result.push_back(x);\r
- double rdm = 1;\r
- if (dist_rdm.get_value() != 0) \r
- rdm = 1.+ double((2*dist_rdm - dist_rdm.get_value()))/100.;\r
- x+= step*rdm;\r
- step*=scale;//(1.+double(growth));\r
- }\r
- return result;\r
-}\r
-\r
-\r
-//-------------------------------------------------------\r
-// Walk through the intersections to create linear hatches\r
-//-------------------------------------------------------\r
-std::vector<std::vector<Point> > \r
-LPEHatches::linearSnake(Piecewise<D2<SBasis> > const &f){\r
-\r
- std::vector<std::vector<Point> > result;\r
-\r
- Piecewise<SBasis> x = make_cuts_independent(f)[X];\r
- //Rque: derivative is computed twice in the 2 lines below!!\r
- Piecewise<SBasis> dx = derivative(x);\r
- OptInterval range = bounds_exact(x);\r
-\r
- if (not range) return result;\r
- std::vector<double> levels = generateLevels(*range);\r
- std::vector<std::vector<double> > times;\r
- times = multi_roots(x,levels);\r
-\r
-//TODO: fix multi_roots!!!*****************************************\r
-//remove doubles :-(\r
- std::vector<std::vector<double> > cleaned_times(levels.size(),std::vector<double>());\r
- for (unsigned i=0; i<times.size(); i++){\r
- if ( times[i].size()>0 ){\r
- double last_t = times[i][0]-1;//ugly hack!!\r
- for (unsigned j=0; j<times[i].size(); j++){\r
- if (times[i][j]-last_t >0.000001){\r
- last_t = times[i][j];\r
- cleaned_times[i].push_back(last_t);\r
- }\r
- }\r
- }\r
- }\r
- times = cleaned_times;\r
-// for (unsigned i=0; i<times.size(); i++){\r
-// std::cout << "roots on level "<<i<<": ";\r
-// for (unsigned j=0; j<times[i].size(); j++){\r
-// std::cout << times[i][j] <<" ";\r
-// }\r
-// std::cout <<"\n";\r
-// }\r
-//*******************************************************************\r
- LevelsCrossings lscs(times,f,dx);\r
- unsigned i,j;\r
- lscs.findFirstUnused(i,j);\r
- std::vector<Point> result_component;\r
- while ( i < lscs.size() ){ \r
- int dir = 0;\r
- while ( i < lscs.size() ){\r
- result_component.push_back(lscs[i][j].pt);\r
- lscs[i][j].used = true;\r
- lscs.step(i,j, dir);\r
- }\r
- result.push_back(result_component);\r
- result_component = std::vector<Point>();\r
- lscs.findFirstUnused(i,j);\r
- }\r
- return result;\r
-}\r
-\r
-//-------------------------------------------------------\r
-// Smooth the linear hatches according to params...\r
-//-------------------------------------------------------\r
-Piecewise<D2<SBasis> > \r
-LPEHatches::smoothSnake(std::vector<std::vector<Point> > const &linearSnake){\r
-\r
- Piecewise<D2<SBasis> > result;\r
- for (unsigned comp=0; comp<linearSnake.size(); comp++){\r
- if (linearSnake[comp].size()>=2){\r
- bool is_top = true;//Inversion here; due to downward y? \r
- Point last_pt = linearSnake[comp][0];\r
- Point last_top = linearSnake[comp][0];\r
- Point last_bot = linearSnake[comp][0];\r
- Point last_hdle = linearSnake[comp][0];\r
- Point last_top_hdle = linearSnake[comp][0];\r
- Point last_bot_hdle = linearSnake[comp][0];\r
- Geom::Path res_comp(last_pt);\r
- Geom::Path res_comp_top(last_pt);\r
- Geom::Path res_comp_bot(last_pt);\r
- unsigned i=1;\r
- while( i+1<linearSnake[comp].size() ){\r
- Point pt0 = linearSnake[comp][i];\r
- Point pt1 = linearSnake[comp][i+1];\r
- Point new_pt = (pt0+pt1)/2;\r
- double scale_in = (is_top ? scale_tf : scale_bf );\r
- double scale_out = (is_top ? scale_tb : scale_bb );\r
- if (is_top){\r
- if (top_edge_variation.get_value() != 0) \r
- new_pt[Y] += double(top_edge_variation)-top_edge_variation.get_value()/2.;\r
- if (top_tgt_variation.get_value() != 0) \r
- new_pt[X] += double(top_tgt_variation)-top_tgt_variation.get_value()/2.;\r
- if (top_smth_variation.get_value() != 0) {\r
- scale_in*=(100.-double(top_smth_variation))/100.;\r
- scale_out*=(100.-double(top_smth_variation))/100.;\r
- }\r
- }else{\r
- if (bot_edge_variation.get_value() != 0) \r
- new_pt[Y] += double(bot_edge_variation)-bot_edge_variation.get_value()/2.;\r
- if (bot_tgt_variation.get_value() != 0) \r
- new_pt[X] += double(bot_tgt_variation)-bot_tgt_variation.get_value()/2.;\r
- if (bot_smth_variation.get_value() != 0) {\r
- scale_in*=(100.-double(bot_smth_variation))/100.;\r
- scale_out*=(100.-double(bot_smth_variation))/100.;\r
- }\r
- }\r
- Point new_hdle_in = new_pt + (pt0-pt1) * (scale_in /2.);\r
- Point new_hdle_out = new_pt - (pt0-pt1) * (scale_out/2.);\r
- \r
- if ( fat_output.get_value() ){\r
- double scaled_width = double((is_top ? stroke_width_top : stroke_width_bot))/(pt1[X]-pt0[X]);\r
- Point hdle_offset = (pt1-pt0)*scaled_width;\r
- Point inside = new_pt;\r
- Point inside_hdle_in;\r
- Point inside_hdle_out;\r
- inside[Y]+= double((is_top ? -stroke_width_top : stroke_width_bot));\r
- inside_hdle_in = inside + (new_hdle_in -new_pt) + hdle_offset * double((is_top ? front_thickness : back_thickness));\r
- inside_hdle_out = inside + (new_hdle_out-new_pt) - hdle_offset * double((is_top ? back_thickness : front_thickness));\r
- //TODO: find a good way to handle limit cases (small smthness, large stroke).\r
- //if (inside_hdle_in[X] > inside[X]) inside_hdle_in = inside;\r
- //if (inside_hdle_out[X] < inside[X]) inside_hdle_out = inside;\r
- \r
- if (is_top){\r
- res_comp_top.appendNew<CubicBezier>(last_top_hdle,new_hdle_in,new_pt);\r
- res_comp_bot.appendNew<CubicBezier>(last_bot_hdle,inside_hdle_in,inside);\r
- last_top_hdle = new_hdle_out;\r
- last_bot_hdle = inside_hdle_out;\r
- }else{\r
- res_comp_top.appendNew<CubicBezier>(last_top_hdle,inside_hdle_in,inside);\r
- res_comp_bot.appendNew<CubicBezier>(last_bot_hdle,new_hdle_in,new_pt);\r
- last_top_hdle = inside_hdle_out;\r
- last_bot_hdle = new_hdle_out;\r
- }\r
- }else{\r
- res_comp.appendNew<CubicBezier>(last_hdle,new_hdle_in,new_pt);\r
- }\r
- \r
- last_hdle = new_hdle_out;\r
- i+=2;\r
- is_top = !is_top;\r
- }\r
- if ( i<linearSnake[comp].size() )\r
- if ( fat_output.get_value() ){\r
- res_comp_top.appendNew<CubicBezier>(last_top_hdle,linearSnake[comp][i],linearSnake[comp][i]);\r
- res_comp_bot.appendNew<CubicBezier>(last_bot_hdle,linearSnake[comp][i],linearSnake[comp][i]);\r
- }else{\r
- res_comp.appendNew<CubicBezier>(last_hdle,linearSnake[comp][i],linearSnake[comp][i]);\r
- }\r
- if ( fat_output.get_value() ){\r
- res_comp = res_comp_bot;\r
- res_comp.append(res_comp_top.reverse(),Geom::Path::STITCH_DISCONTINUOUS);\r
- } \r
- result.concat(res_comp.toPwSb());\r
- }\r
- }\r
- return result;\r
-}\r
-\r
-void\r
-LPEHatches::doBeforeEffect (SPLPEItem */*lpeitem*/)\r
-{\r
- using namespace Geom;\r
- top_edge_variation.resetRandomizer();\r
- bot_edge_variation.resetRandomizer();\r
- top_tgt_variation.resetRandomizer();\r
- bot_tgt_variation.resetRandomizer();\r
- top_smth_variation.resetRandomizer();\r
- bot_smth_variation.resetRandomizer();\r
- dist_rdm.resetRandomizer();\r
-\r
- //original_bbox(lpeitem);\r
-}\r
-\r
-\r
-void\r
-LPEHatches::resetDefaults(SPItem * item)\r
-{\r
- Geom::OptRect bbox = item->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX);\r
- Geom::Point origin(0.,0.);\r
- Geom::Point vector(50.,0.);\r
- if (bbox) {\r
- origin = bbox->midpoint();\r
- vector = Geom::Point((*bbox)[X].extent()/4, 0.);\r
- top_edge_variation.param_set_value( (*bbox)[Y].extent()/10, 0 );\r
- bot_edge_variation.param_set_value( (*bbox)[Y].extent()/10, 0 );\r
- }\r
- direction.set_and_write_new_values(origin, vector);\r
- bender.param_set_and_write_new_value( origin + Geom::Point(5,0) );\r
- hatch_dist = Geom::L2(vector)/5;\r
-}\r
-\r
-\r
-} //namespace LivePathEffect\r
-} /* namespace Inkscape */\r
-\r
-/*\r
- Local Variables:\r
- mode:c++\r
- c-file-style:"stroustrup"\r
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
- indent-tabs-mode:nil\r
- fill-column:99\r
- End:\r
-*/\r
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
diff --git a/src/live_effects/lpe-hatches.h b/src/live_effects/lpe-hatches.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef INKSCAPE_LPE_HATCHES_H\r
-#define INKSCAPE_LPE_HATCHES_H\r
-\r
-/** \file\r
- * Implementation of the curve stitch effect, see lpe-hatches.cpp\r
- */\r
-\r
-/*\r
- * Authors:\r
- * JFBarraud\r
- *\r
- * Copyright (C) JF Barraud 2008.\r
- *\r
- * Released under GNU GPL, read the file 'COPYING' for more information\r
- */\r
-\r
-#include "live_effects/effect.h"\r
-#include "live_effects/parameter/point.h"\r
-#include "live_effects/parameter/parameter.h"\r
-#include "live_effects/parameter/bool.h"\r
-#include "live_effects/parameter/random.h"\r
-#include "live_effects/parameter/vector.h"\r
-\r
-namespace Inkscape {\r
-namespace LivePathEffect {\r
-\r
-class LPEHatches : public Effect {\r
-public:\r
- LPEHatches(LivePathEffectObject *lpeobject);\r
- virtual ~LPEHatches();\r
-\r
- virtual Geom::Piecewise<Geom::D2<Geom::SBasis> >\r
- doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);\r
-\r
- virtual void resetDefaults(SPItem * item);\r
-\r
- virtual void doBeforeEffect(SPLPEItem * item);\r
-\r
- std::vector<double>\r
- generateLevels(Geom::Interval const &domain);\r
-\r
- std::vector<std::vector<Geom::Point> >\r
- linearSnake(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &f);\r
-\r
- Geom::Piecewise<Geom::D2<Geom::SBasis> > \r
- smoothSnake(std::vector<std::vector<Geom::Point> > const &linearSnake);\r
- \r
-private:\r
- double hatch_dist;\r
- RandomParam dist_rdm;\r
- ScalarParam growth;\r
- //topfront,topback,bottomfront,bottomback handle scales.\r
- ScalarParam scale_tf, scale_tb, scale_bf, scale_bb;\r
-\r
- RandomParam top_edge_variation;\r
- RandomParam bot_edge_variation;\r
- RandomParam top_tgt_variation;\r
- RandomParam bot_tgt_variation;\r
- RandomParam top_smth_variation;\r
- RandomParam bot_smth_variation;\r
-\r
- BoolParam fat_output, do_bend;\r
- ScalarParam stroke_width_top;\r
- ScalarParam stroke_width_bot;\r
- ScalarParam front_thickness, back_thickness;\r
-\r
- PointParam bender;\r
- VectorParam direction;\r
-\r
- LPEHatches(const LPEHatches&);\r
- LPEHatches& operator=(const LPEHatches&);\r
-};\r
-\r
-} //namespace LivePathEffect\r
-} //namespace Inkscape\r
-\r
-#endif\r
diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp
--- /dev/null
@@ -0,0 +1,593 @@
+#define INKSCAPE_LPE_ROUGH_HATCHES_CPP\r
+/** \file\r
+ * LPE Curve Stitching implementation, used as an example for a base starting class\r
+ * when implementing new LivePathEffects.\r
+ *\r
+ */\r
+/*\r
+ * Authors:\r
+ * JF Barraud.\r
+*\r
+* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+\r
+#include "live_effects/lpe-rough-hatches.h"\r
+\r
+#include "sp-item.h"\r
+#include "sp-path.h"\r
+#include "svg/svg.h"\r
+#include "xml/repr.h"\r
+\r
+#include <2geom/path.h>\r
+#include <2geom/piecewise.h>\r
+#include <2geom/sbasis.h>\r
+#include <2geom/sbasis-math.h>\r
+#include <2geom/sbasis-geometric.h>\r
+#include <2geom/bezier-to-sbasis.h>\r
+#include <2geom/sbasis-to-bezier.h>\r
+#include <2geom/d2.h>\r
+#include <2geom/matrix.h>\r
+\r
+#include "ui/widget/scalar.h"\r
+#include "libnr/nr-values.h"\r
+\r
+namespace Inkscape {\r
+namespace LivePathEffect {\r
+\r
+using namespace Geom;\r
+\r
+//------------------------------------------------\r
+// Some goodies to navigate through curve's levels.\r
+//------------------------------------------------\r
+struct LevelCrossing{\r
+ Point pt;\r
+ double t;\r
+ bool sign;\r
+ bool used;\r
+ std::pair<unsigned,unsigned> next_on_curve;\r
+ std::pair<unsigned,unsigned> prev_on_curve;\r
+};\r
+struct LevelCrossingOrder {\r
+ bool operator()(LevelCrossing a, LevelCrossing b) {\r
+ return a.pt[Y] < b.pt[Y];\r
+ }\r
+};\r
+struct LevelCrossingInfo{\r
+ double t;\r
+ unsigned level;\r
+ unsigned idx;\r
+};\r
+struct LevelCrossingInfoOrder {\r
+ bool operator()(LevelCrossingInfo a, LevelCrossingInfo b) {\r
+ return a.t < b.t;\r
+ }\r
+};\r
+\r
+typedef std::vector<LevelCrossing> LevelCrossings;\r
+\r
+std::vector<double>\r
+discontinuities(Piecewise<D2<SBasis> > const &f){\r
+ std::vector<double> result;\r
+ if (f.size()==0) return result;\r
+ result.push_back(f.cuts[0]);\r
+ Point prev_pt = f.segs[0].at1();\r
+ //double old_t = f.cuts[0];\r
+ for(unsigned i=1; i<f.size(); i++){\r
+ if ( f.segs[i].at0()!=prev_pt){\r
+ result.push_back(f.cuts[i]);\r
+ //old_t = f.cuts[i];\r
+ //assert(f.segs[i-1].at1()==f.valueAt(old_t));\r
+ }\r
+ prev_pt = f.segs[i].at1();\r
+ }\r
+ result.push_back(f.cuts.back());\r
+ //assert(f.segs.back().at1()==f.valueAt(old_t));\r
+ return result;\r
+}\r
+\r
+class LevelsCrossings: public std::vector<LevelCrossings>{\r
+public:\r
+ LevelsCrossings():std::vector<LevelCrossings>(){};\r
+ LevelsCrossings(std::vector<std::vector<double> > const ×,\r
+ Piecewise<D2<SBasis> > const &f,\r
+ Piecewise<SBasis> const &dx){\r
+ \r
+ for (unsigned i=0; i<times.size(); i++){\r
+ LevelCrossings lcs;\r
+ for (unsigned j=0; j<times[i].size(); j++){\r
+ LevelCrossing lc;\r
+ lc.pt = f.valueAt(times[i][j]);\r
+ lc.t = times[i][j];\r
+ lc.sign = ( dx.valueAt(times[i][j])>0 );\r
+ lc.used = false;\r
+ lcs.push_back(lc);\r
+ }\r
+ std::sort(lcs.begin(), lcs.end(), LevelCrossingOrder());\r
+ push_back(lcs);\r
+ }\r
+ //Now create time ordering.\r
+ std::vector<LevelCrossingInfo>temp;\r
+ for (unsigned i=0; i<size(); i++){\r
+ for (unsigned j=0; j<(*this)[i].size(); j++){\r
+ LevelCrossingInfo elem;\r
+ elem.t = (*this)[i][j].t;\r
+ elem.level = i;\r
+ elem.idx = j;\r
+ temp.push_back(elem);\r
+ }\r
+ }\r
+ std::sort(temp.begin(),temp.end(),LevelCrossingInfoOrder());\r
+ std::vector<double> jumps = discontinuities(f);\r
+ unsigned jump_idx = 0;\r
+ unsigned first_in_comp = 0;\r
+ for (unsigned i=0; i<temp.size(); i++){\r
+ unsigned lvl = temp[i].level, idx = temp[i].idx;\r
+ if ( i == temp.size()-1 || temp[i+1].t > jumps[jump_idx+1]){\r
+ std::pair<unsigned,unsigned>next_data(temp[first_in_comp].level,temp[first_in_comp].idx);\r
+ (*this)[lvl][idx].next_on_curve = next_data;\r
+ first_in_comp = i+1;\r
+ jump_idx += 1;\r
+ }else{\r
+ std::pair<unsigned,unsigned> next_data(temp[i+1].level,temp[i+1].idx);\r
+ (*this)[lvl][idx].next_on_curve = next_data;\r
+ }\r
+ }\r
+\r
+ for (unsigned i=0; i<size(); i++){\r
+ for (unsigned j=0; j<(*this)[i].size(); j++){\r
+ std::pair<unsigned,unsigned> next = (*this)[i][j].next_on_curve;\r
+ (*this)[next.first][next.second].prev_on_curve = std::pair<unsigned,unsigned>(i,j);\r
+ }\r
+ }\r
+#if 0\r
+ std::cout<<"\n";\r
+ for (unsigned i=0; i<temp.size()-1; i++){\r
+ std::cout<<temp[i].level<<","<<temp[i].idx<<" -> ";\r
+ }\r
+ std::cout<<"\n";\r
+ for (unsigned i=0; i<size(); i++){\r
+ for (unsigned j=0; j<(*this)[i].size(); j++){\r
+ std::cout<<"level:"<<i<<", idx:"<<j<<" - ";\r
+ std::cout<<"next:"<<(*this)[i][j].next_on_curve.first<<",";\r
+ std::cout<<(*this)[i][j].next_on_curve.second<<" - ";\r
+ std::cout<<"prev:"<<(*this)[i][j].prev_on_curve.first<<",";\r
+ std::cout<<(*this)[i][j].prev_on_curve.second<<"\n";\r
+ }\r
+ }\r
+#endif\r
+ }\r
+\r
+ void findFirstUnused(unsigned &level, unsigned &idx){\r
+ level = size();\r
+ idx = 0;\r
+ for (unsigned i=0; i<size(); i++){\r
+ for (unsigned j=0; j<(*this)[i].size(); j++){\r
+ if (!(*this)[i][j].used){\r
+ level = i;\r
+ idx = j;\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ //set indexes to point to the next point in the "snake walk"\r
+ //follow_level's meaning: \r
+ // 0=yes upward\r
+ // 1=no, last move was upward,\r
+ // 2=yes downward\r
+ // 3=no, last move was downward.\r
+ void step(unsigned &level, unsigned &idx, int &direction){\r
+ if ( direction % 2 == 0 ){\r
+ if (direction == 0) {\r
+ if ( idx >= (*this)[level].size()-1 || (*this)[level][idx+1].used ) {\r
+ level = size();\r
+ return;\r
+ }\r
+ idx += 1;\r
+ }else{\r
+ if ( idx <= 0 || (*this)[level][idx-1].used ) {\r
+ level = size();\r
+ return;\r
+ }\r
+ idx -= 1;\r
+ }\r
+ direction += 1;\r
+ return;\r
+ }\r
+ double t = (*this)[level][idx].t;\r
+ double sign = ((*this)[level][idx].sign ? 1 : -1);\r
+ double next_t = t;\r
+ //level += 1;\r
+ direction = (direction + 1)%4;\r
+ if (level == size()){\r
+ return;\r
+ }\r
+\r
+ std::pair<unsigned,unsigned> next;\r
+ if ( sign > 0 ){\r
+ next = (*this)[level][idx].next_on_curve;\r
+ }else{\r
+ next = (*this)[level][idx].prev_on_curve;\r
+ }\r
+\r
+ if ( level+1 != next.first || (*this)[next.first][next.second].used ) {\r
+ level = size();\r
+ return;\r
+ }\r
+ level = next.first;\r
+ idx = next.second;\r
+\r
+/*********************\r
+ //look for next time on the same level\r
+ for (unsigned j=0; j<(*this)[level].size(); j++){\r
+ double tj = (*this)[level][j].t;\r
+ if ( sign*(tj-t) > 0 ){\r
+ if( next_t == t || sign*(tj-next_t)<0 ){\r
+ next_t = tj;\r
+ idx = j;\r
+ }\r
+ }\r
+ }\r
+ if ( next_t == t ){//not found? look at max/min time in this component, as time is "periodic".\r
+ for (unsigned j=0; j<(*this)[level].size(); j++){\r
+ double tj = (*this)[level][j].t;\r
+ if ( -sign*(tj-next_t) > 0 ){\r
+ next_t = tj;\r
+ idx = j;\r
+ }\r
+ }\r
+ }\r
+ if ( next_t == t ){//still not found? houch! this should not happen.\r
+ level = size();\r
+ return;\r
+ }\r
+ if ( (*this)[level][idx].used ) {\r
+ level = size();\r
+ return;\r
+ }\r
+*************************/\r
+ return;\r
+ }\r
+};\r
+\r
+//-------------------------------------------------------\r
+// Bend a path...\r
+//-------------------------------------------------------\r
+\r
+Piecewise<D2<SBasis> > bend(Piecewise<D2<SBasis> > const &f, Piecewise<SBasis> bending){\r
+ D2<Piecewise<SBasis> > ff = make_cuts_independent(f);\r
+ ff[X] += compose(bending, ff[Y]);\r
+ return sectionize(ff);\r
+}\r
+\r
+//--------------------------------------------------------\r
+// The RoughHatches lpe.\r
+//--------------------------------------------------------\r
+LPERoughHatches::LPERoughHatches(LivePathEffectObject *lpeobject) :\r
+ Effect(lpeobject),\r
+ dist_rdm(_("Dist randomness"), _("Variation of dist between hatches, in %."), "dist_rdm", &wr, this, 75),\r
+ growth(_("Growth"), _("Growth of distance between hatches."), "growth", &wr, this, 0.),\r
+ scale_tf(_("Start smothness (front side)"), _("MISSING DESCRIPTION"), "scale_tf", &wr, this, 1.),\r
+ scale_tb(_("Start smothness (back side)"), _("MISSING DESCRIPTION"), "scale_tb", &wr, this, 1.),\r
+ scale_bf(_("End smothness (front side)"), _("MISSING DESCRIPTION"), "scale_bf", &wr, this, 1.),\r
+ scale_bb(_("End smothness (back side)"), _("MISSING DESCRIPTION"), "scale_bb", &wr, this, 1.),\r
+ top_edge_variation(_("Start edge variance"), _("The amount of random jitter to move the hatches start"), "top_edge_variation", &wr, this, 0),\r
+ bot_edge_variation(_("End edge variance"), _("The amount of random jitter to move the hatches end"), "bot_edge_variation", &wr, this, 0),\r
+ 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),\r
+ 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),\r
+ top_smth_variation(_("Start smoothness variance"), _("Randomness of the smoothness of the U turn at hatches start"), "top_smth_variation", &wr, this, 0),\r
+ bot_smth_variation(_("End spacing variance"), _("Randomness of the smoothness of the U turn at hatches end"), "bot_smth_variation", &wr, this, 0),\r
+ fat_output(_("Generate thick/thin path"), _("Simulate a stroke of varrying width"), "fat_output", &wr, this, true),\r
+ do_bend(_("Bend hatches"), _("Add a global bend to the hatches (slower)"), "do_bend", &wr, this, true),\r
+ stroke_width_top(_("Stroke width (start side)"), _("Width at hatches 'start'"), "stroke_width_top", &wr, this, 1.),\r
+ stroke_width_bot(_("Stroke width (end side)"), _("Width at hatches 'end'"), "stroke_width_bot", &wr, this, 1.),\r
+ front_thickness(_("Front thickness (%)"), _("MISSING DESCRIPTION"), "front_thickness", &wr, this, 1.),\r
+ back_thickness(_("Back thickness (%)"), _("MISSING DESCRIPTION"), "back_thickness", &wr, this, .25),\r
+ bender(_("Global bending"), _("Relative position to ref point defines global bending direction and amount"), "bender", &wr, this, NULL, Geom::Point(-5,0)),\r
+ direction(_("Hatches width and dir"), _("Defines hatches frequency and direction"), "direction", &wr, this, Geom::Point(50,0))\r
+{\r
+ registerParameter( dynamic_cast<Parameter *>(&direction) );\r
+ registerParameter( dynamic_cast<Parameter *>(&do_bend) );\r
+ registerParameter( dynamic_cast<Parameter *>(&bender) );\r
+ registerParameter( dynamic_cast<Parameter *>(&dist_rdm) );\r
+ registerParameter( dynamic_cast<Parameter *>(&growth) );\r
+ registerParameter( dynamic_cast<Parameter *>(&top_edge_variation) );\r
+ registerParameter( dynamic_cast<Parameter *>(&bot_edge_variation) );\r
+ registerParameter( dynamic_cast<Parameter *>(&top_tgt_variation) );\r
+ registerParameter( dynamic_cast<Parameter *>(&bot_tgt_variation) );\r
+ registerParameter( dynamic_cast<Parameter *>(&scale_tf) );\r
+ registerParameter( dynamic_cast<Parameter *>(&scale_tb) );\r
+ registerParameter( dynamic_cast<Parameter *>(&scale_bf) );\r
+ registerParameter( dynamic_cast<Parameter *>(&scale_bb) );\r
+ registerParameter( dynamic_cast<Parameter *>(&top_smth_variation) );\r
+ registerParameter( dynamic_cast<Parameter *>(&bot_smth_variation) );\r
+ registerParameter( dynamic_cast<Parameter *>(&fat_output) );\r
+ registerParameter( dynamic_cast<Parameter *>(&stroke_width_top) );\r
+ registerParameter( dynamic_cast<Parameter *>(&stroke_width_bot) );\r
+ registerParameter( dynamic_cast<Parameter *>(&front_thickness) );\r
+ registerParameter( dynamic_cast<Parameter *>(&back_thickness) );\r
+\r
+ //hatch_dist.param_set_range(0.1, NR_HUGE);\r
+ growth.param_set_range(-0.95, NR_HUGE);\r
+ dist_rdm.param_set_range(0, 99.);\r
+ stroke_width_top.param_set_range(0, NR_HUGE);\r
+ stroke_width_bot.param_set_range(0, NR_HUGE);\r
+ front_thickness.param_set_range(0, NR_HUGE);\r
+ back_thickness.param_set_range(0, NR_HUGE);\r
+\r
+ concatenate_before_pwd2 = true;\r
+ show_orig_path = true;\r
+}\r
+\r
+LPERoughHatches::~LPERoughHatches()\r
+{\r
+\r
+}\r
+\r
+Geom::Piecewise<Geom::D2<Geom::SBasis> > \r
+LPERoughHatches::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in){\r
+\r
+ Piecewise<D2<SBasis> > result;\r
+ \r
+ Piecewise<D2<SBasis> > transformed_pwd2_in = pwd2_in;\r
+ Piecewise<SBasis> tilter;//used to bend the hatches\r
+ Matrix bend_mat;//used to bend the hatches\r
+\r
+ if (do_bend.get_value()){\r
+ Point bend_dir = -rot90(unit_vector(direction.getOrigin() - bender));\r
+ double bend_amount = L2(direction.getOrigin() - bender);\r
+ bend_mat = Matrix(-bend_dir[Y], bend_dir[X], bend_dir[X], bend_dir[Y],0,0);\r
+ transformed_pwd2_in = pwd2_in * bend_mat;\r
+ tilter = Piecewise<SBasis>(shift(Linear(bend_amount),1));\r
+ OptRect bbox = bounds_exact( transformed_pwd2_in );\r
+ if (not(bbox)) return pwd2_in;\r
+ tilter.setDomain((*bbox)[Y]);\r
+ transformed_pwd2_in = bend(transformed_pwd2_in, tilter);\r
+ transformed_pwd2_in = transformed_pwd2_in * bend_mat.inverse();\r
+ }\r
+ hatch_dist = Geom::L2(direction.getVector())/5;\r
+ Point hatches_dir = rot90(unit_vector(direction.getVector()));\r
+ Matrix mat(-hatches_dir[Y], hatches_dir[X], hatches_dir[X], hatches_dir[Y],0,0);\r
+ transformed_pwd2_in = transformed_pwd2_in * mat;\r
+ \r
+ std::vector<std::vector<Point> > snakePoints;\r
+ snakePoints = linearSnake(transformed_pwd2_in);\r
+ if ( snakePoints.size() > 0 ){\r
+ Piecewise<D2<SBasis> >smthSnake = smoothSnake(snakePoints); \r
+ smthSnake = smthSnake*mat.inverse();\r
+ if (do_bend.get_value()){\r
+ smthSnake = smthSnake*bend_mat;\r
+ smthSnake = bend(smthSnake, -tilter);\r
+ smthSnake = smthSnake*bend_mat.inverse();\r
+ }\r
+ return (smthSnake);\r
+ }\r
+ return pwd2_in;\r
+}\r
+\r
+//------------------------------------------------\r
+// Generate the levels with random, growth...\r
+//------------------------------------------------\r
+std::vector<double>\r
+LPERoughHatches::generateLevels(Interval const &domain){\r
+ std::vector<double> result;\r
+ double x = domain.min() + double(hatch_dist)/2.;\r
+ double step = double(hatch_dist);\r
+ double scale = 1+(hatch_dist*growth/domain.extent());\r
+ while (x < domain.max()){\r
+ result.push_back(x);\r
+ double rdm = 1;\r
+ if (dist_rdm.get_value() != 0) \r
+ rdm = 1.+ double((2*dist_rdm - dist_rdm.get_value()))/100.;\r
+ x+= step*rdm;\r
+ step*=scale;//(1.+double(growth));\r
+ }\r
+ return result;\r
+}\r
+\r
+\r
+//-------------------------------------------------------\r
+// Walk through the intersections to create linear hatches\r
+//-------------------------------------------------------\r
+std::vector<std::vector<Point> > \r
+LPERoughHatches::linearSnake(Piecewise<D2<SBasis> > const &f){\r
+\r
+ std::vector<std::vector<Point> > result;\r
+\r
+ Piecewise<SBasis> x = make_cuts_independent(f)[X];\r
+ //Rque: derivative is computed twice in the 2 lines below!!\r
+ Piecewise<SBasis> dx = derivative(x);\r
+ OptInterval range = bounds_exact(x);\r
+\r
+ if (not range) return result;\r
+ std::vector<double> levels = generateLevels(*range);\r
+ std::vector<std::vector<double> > times;\r
+ times = multi_roots(x,levels);\r
+\r
+//TODO: fix multi_roots!!!*****************************************\r
+//remove doubles :-(\r
+ std::vector<std::vector<double> > cleaned_times(levels.size(),std::vector<double>());\r
+ for (unsigned i=0; i<times.size(); i++){\r
+ if ( times[i].size()>0 ){\r
+ double last_t = times[i][0]-1;//ugly hack!!\r
+ for (unsigned j=0; j<times[i].size(); j++){\r
+ if (times[i][j]-last_t >0.000001){\r
+ last_t = times[i][j];\r
+ cleaned_times[i].push_back(last_t);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ times = cleaned_times;\r
+// for (unsigned i=0; i<times.size(); i++){\r
+// std::cout << "roots on level "<<i<<": ";\r
+// for (unsigned j=0; j<times[i].size(); j++){\r
+// std::cout << times[i][j] <<" ";\r
+// }\r
+// std::cout <<"\n";\r
+// }\r
+//*******************************************************************\r
+ LevelsCrossings lscs(times,f,dx);\r
+ unsigned i,j;\r
+ lscs.findFirstUnused(i,j);\r
+ std::vector<Point> result_component;\r
+ while ( i < lscs.size() ){ \r
+ int dir = 0;\r
+ while ( i < lscs.size() ){\r
+ result_component.push_back(lscs[i][j].pt);\r
+ lscs[i][j].used = true;\r
+ lscs.step(i,j, dir);\r
+ }\r
+ result.push_back(result_component);\r
+ result_component = std::vector<Point>();\r
+ lscs.findFirstUnused(i,j);\r
+ }\r
+ return result;\r
+}\r
+\r
+//-------------------------------------------------------\r
+// Smooth the linear hatches according to params...\r
+//-------------------------------------------------------\r
+Piecewise<D2<SBasis> > \r
+LPERoughHatches::smoothSnake(std::vector<std::vector<Point> > const &linearSnake){\r
+\r
+ Piecewise<D2<SBasis> > result;\r
+ for (unsigned comp=0; comp<linearSnake.size(); comp++){\r
+ if (linearSnake[comp].size()>=2){\r
+ bool is_top = true;//Inversion here; due to downward y? \r
+ Point last_pt = linearSnake[comp][0];\r
+ Point last_top = linearSnake[comp][0];\r
+ Point last_bot = linearSnake[comp][0];\r
+ Point last_hdle = linearSnake[comp][0];\r
+ Point last_top_hdle = linearSnake[comp][0];\r
+ Point last_bot_hdle = linearSnake[comp][0];\r
+ Geom::Path res_comp(last_pt);\r
+ Geom::Path res_comp_top(last_pt);\r
+ Geom::Path res_comp_bot(last_pt);\r
+ unsigned i=1;\r
+ while( i+1<linearSnake[comp].size() ){\r
+ Point pt0 = linearSnake[comp][i];\r
+ Point pt1 = linearSnake[comp][i+1];\r
+ Point new_pt = (pt0+pt1)/2;\r
+ double scale_in = (is_top ? scale_tf : scale_bf );\r
+ double scale_out = (is_top ? scale_tb : scale_bb );\r
+ if (is_top){\r
+ if (top_edge_variation.get_value() != 0) \r
+ new_pt[Y] += double(top_edge_variation)-top_edge_variation.get_value()/2.;\r
+ if (top_tgt_variation.get_value() != 0) \r
+ new_pt[X] += double(top_tgt_variation)-top_tgt_variation.get_value()/2.;\r
+ if (top_smth_variation.get_value() != 0) {\r
+ scale_in*=(100.-double(top_smth_variation))/100.;\r
+ scale_out*=(100.-double(top_smth_variation))/100.;\r
+ }\r
+ }else{\r
+ if (bot_edge_variation.get_value() != 0) \r
+ new_pt[Y] += double(bot_edge_variation)-bot_edge_variation.get_value()/2.;\r
+ if (bot_tgt_variation.get_value() != 0) \r
+ new_pt[X] += double(bot_tgt_variation)-bot_tgt_variation.get_value()/2.;\r
+ if (bot_smth_variation.get_value() != 0) {\r
+ scale_in*=(100.-double(bot_smth_variation))/100.;\r
+ scale_out*=(100.-double(bot_smth_variation))/100.;\r
+ }\r
+ }\r
+ Point new_hdle_in = new_pt + (pt0-pt1) * (scale_in /2.);\r
+ Point new_hdle_out = new_pt - (pt0-pt1) * (scale_out/2.);\r
+ \r
+ if ( fat_output.get_value() ){\r
+ double scaled_width = double((is_top ? stroke_width_top : stroke_width_bot))/(pt1[X]-pt0[X]);\r
+ Point hdle_offset = (pt1-pt0)*scaled_width;\r
+ Point inside = new_pt;\r
+ Point inside_hdle_in;\r
+ Point inside_hdle_out;\r
+ inside[Y]+= double((is_top ? -stroke_width_top : stroke_width_bot));\r
+ inside_hdle_in = inside + (new_hdle_in -new_pt) + hdle_offset * double((is_top ? front_thickness : back_thickness));\r
+ inside_hdle_out = inside + (new_hdle_out-new_pt) - hdle_offset * double((is_top ? back_thickness : front_thickness));\r
+ //TODO: find a good way to handle limit cases (small smthness, large stroke).\r
+ //if (inside_hdle_in[X] > inside[X]) inside_hdle_in = inside;\r
+ //if (inside_hdle_out[X] < inside[X]) inside_hdle_out = inside;\r
+ \r
+ if (is_top){\r
+ res_comp_top.appendNew<CubicBezier>(last_top_hdle,new_hdle_in,new_pt);\r
+ res_comp_bot.appendNew<CubicBezier>(last_bot_hdle,inside_hdle_in,inside);\r
+ last_top_hdle = new_hdle_out;\r
+ last_bot_hdle = inside_hdle_out;\r
+ }else{\r
+ res_comp_top.appendNew<CubicBezier>(last_top_hdle,inside_hdle_in,inside);\r
+ res_comp_bot.appendNew<CubicBezier>(last_bot_hdle,new_hdle_in,new_pt);\r
+ last_top_hdle = inside_hdle_out;\r
+ last_bot_hdle = new_hdle_out;\r
+ }\r
+ }else{\r
+ res_comp.appendNew<CubicBezier>(last_hdle,new_hdle_in,new_pt);\r
+ }\r
+ \r
+ last_hdle = new_hdle_out;\r
+ i+=2;\r
+ is_top = !is_top;\r
+ }\r
+ if ( i<linearSnake[comp].size() )\r
+ if ( fat_output.get_value() ){\r
+ res_comp_top.appendNew<CubicBezier>(last_top_hdle,linearSnake[comp][i],linearSnake[comp][i]);\r
+ res_comp_bot.appendNew<CubicBezier>(last_bot_hdle,linearSnake[comp][i],linearSnake[comp][i]);\r
+ }else{\r
+ res_comp.appendNew<CubicBezier>(last_hdle,linearSnake[comp][i],linearSnake[comp][i]);\r
+ }\r
+ if ( fat_output.get_value() ){\r
+ res_comp = res_comp_bot;\r
+ res_comp.append(res_comp_top.reverse(),Geom::Path::STITCH_DISCONTINUOUS);\r
+ } \r
+ result.concat(res_comp.toPwSb());\r
+ }\r
+ }\r
+ return result;\r
+}\r
+\r
+void\r
+LPERoughHatches::doBeforeEffect (SPLPEItem */*lpeitem*/)\r
+{\r
+ using namespace Geom;\r
+ top_edge_variation.resetRandomizer();\r
+ bot_edge_variation.resetRandomizer();\r
+ top_tgt_variation.resetRandomizer();\r
+ bot_tgt_variation.resetRandomizer();\r
+ top_smth_variation.resetRandomizer();\r
+ bot_smth_variation.resetRandomizer();\r
+ dist_rdm.resetRandomizer();\r
+\r
+ //original_bbox(lpeitem);\r
+}\r
+\r
+\r
+void\r
+LPERoughHatches::resetDefaults(SPItem * item)\r
+{\r
+ Geom::OptRect bbox = item->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX);\r
+ Geom::Point origin(0.,0.);\r
+ Geom::Point vector(50.,0.);\r
+ if (bbox) {\r
+ origin = bbox->midpoint();\r
+ vector = Geom::Point((*bbox)[X].extent()/4, 0.);\r
+ top_edge_variation.param_set_value( (*bbox)[Y].extent()/10, 0 );\r
+ bot_edge_variation.param_set_value( (*bbox)[Y].extent()/10, 0 );\r
+ }\r
+ direction.set_and_write_new_values(origin, vector);\r
+ bender.param_set_and_write_new_value( origin + Geom::Point(5,0) );\r
+ hatch_dist = Geom::L2(vector)/5;\r
+}\r
+\r
+\r
+} //namespace LivePathEffect\r
+} /* namespace Inkscape */\r
+\r
+/*\r
+ Local Variables:\r
+ mode:c++\r
+ c-file-style:"stroustrup"\r
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
+ indent-tabs-mode:nil\r
+ fill-column:99\r
+ End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
diff --git a/src/live_effects/lpe-rough-hatches.h b/src/live_effects/lpe-rough-hatches.h
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef INKSCAPE_LPE_ROUGH_HATCHES_H\r
+#define INKSCAPE_LPE_ROUGH_HATCHES_H\r
+\r
+/** \file\r
+ * Fills an area with rough hatches.\r
+ */\r
+\r
+/*\r
+ * Authors:\r
+ * JFBarraud\r
+ *\r
+ * Copyright (C) JF Barraud 2008.\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+\r
+#include "live_effects/effect.h"\r
+#include "live_effects/parameter/point.h"\r
+#include "live_effects/parameter/parameter.h"\r
+#include "live_effects/parameter/bool.h"\r
+#include "live_effects/parameter/random.h"\r
+#include "live_effects/parameter/vector.h"\r
+\r
+namespace Inkscape {\r
+namespace LivePathEffect {\r
+\r
+class LPERoughHatches : public Effect {\r
+public:\r
+ LPERoughHatches(LivePathEffectObject *lpeobject);\r
+ virtual ~LPERoughHatches();\r
+\r
+ virtual Geom::Piecewise<Geom::D2<Geom::SBasis> >\r
+ doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);\r
+\r
+ virtual void resetDefaults(SPItem * item);\r
+\r
+ virtual void doBeforeEffect(SPLPEItem * item);\r
+\r
+ std::vector<double>\r
+ generateLevels(Geom::Interval const &domain);\r
+\r
+ std::vector<std::vector<Geom::Point> >\r
+ linearSnake(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &f);\r
+\r
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > \r
+ smoothSnake(std::vector<std::vector<Geom::Point> > const &linearSnake);\r
+ \r
+private:\r
+ double hatch_dist;\r
+ RandomParam dist_rdm;\r
+ ScalarParam growth;\r
+ //topfront,topback,bottomfront,bottomback handle scales.\r
+ ScalarParam scale_tf, scale_tb, scale_bf, scale_bb;\r
+\r
+ RandomParam top_edge_variation;\r
+ RandomParam bot_edge_variation;\r
+ RandomParam top_tgt_variation;\r
+ RandomParam bot_tgt_variation;\r
+ RandomParam top_smth_variation;\r
+ RandomParam bot_smth_variation;\r
+\r
+ BoolParam fat_output, do_bend;\r
+ ScalarParam stroke_width_top;\r
+ ScalarParam stroke_width_bot;\r
+ ScalarParam front_thickness, back_thickness;\r
+\r
+ PointParam bender;\r
+ VectorParam direction;\r
+\r
+ LPERoughHatches(const LPERoughHatches&);\r
+ LPERoughHatches& operator=(const LPERoughHatches&);\r
+};\r
+\r
+} //namespace LivePathEffect\r
+} //namespace Inkscape\r
+\r
+#endif\r