From: jfbarraud Date: Wed, 26 Nov 2008 20:56:08 +0000 (+0000) Subject: renamed lpe-hatches to lpe-rough-hatches. X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=06cd6b0ab2dbe286184e35d1078bab18c966b0d2;p=inkscape.git renamed lpe-hatches to lpe-rough-hatches. --- diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 89b7b9e3a..72d955586 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -11,7 +11,7 @@ lpe-gears.cpp lpegroupbbox.cpp lpe-interpolate.cpp lpe-knot.cpp -lpe-hatches.cpp +lpe-rough-hatches.cpp lpe-lattice.cpp lpe-mirror_symmetry.cpp lpeobject.cpp diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 1e82954f8..4c0d9389f 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -21,7 +21,7 @@ enum EffectType { PATTERN_ALONG_PATH, FREEHAND_SHAPE, SKETCH, - HATCHES, + ROUGH_HATCHES, VONKOCH, KNOT, #ifdef LPE_ENABLE_TEST_EFFECTS diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index bb5f0c554..2a316a0bb 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -42,7 +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-rough-hatches.h" #include "live_effects/lpe-test-doEffect-stack.h" #include "live_effects/lpe-gears.h" #include "live_effects/lpe-curvestitch.h" @@ -73,7 +73,7 @@ namespace Inkscape { namespace LivePathEffect { const Util::EnumData 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"}, @@ -100,7 +100,7 @@ const Util::EnumData LPETypeData[] = { {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"}, @@ -139,8 +139,8 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case SKETCH: neweffect = static_cast ( new LPESketch(lpeobj) ); break; - case HATCHES: - neweffect = static_cast ( new LPEHatches(lpeobj) ); + case ROUGH_HATCHES: + neweffect = static_cast ( new LPERoughHatches(lpeobj) ); break; case VONKOCH: neweffect = static_cast ( new LPEVonKoch(lpeobj) ); diff --git a/src/live_effects/lpe-hatches.cpp b/src/live_effects/lpe-hatches.cpp deleted file mode 100644 index 2205d91f3..000000000 --- a/src/live_effects/lpe-hatches.cpp +++ /dev/null @@ -1,593 +0,0 @@ -#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 - * - * 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 next_on_curve; - std::pair 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 LevelCrossings; - -std::vector -discontinuities(Piecewise > const &f){ - std::vector 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{ -public: - LevelsCrossings():std::vector(){}; - LevelsCrossings(std::vector > const ×, - Piecewise > const &f, - Piecewise const &dx){ - - for (unsigned i=0; i0 ); - lc.used = false; - lcs.push_back(lc); - } - std::sort(lcs.begin(), lcs.end(), LevelCrossingOrder()); - push_back(lcs); - } - //Now create time ordering. - std::vectortemp; - for (unsigned i=0; i jumps = discontinuities(f); - unsigned jump_idx = 0; - unsigned first_in_comp = 0; - for (unsigned i=0; i jumps[jump_idx+1]){ - std::pairnext_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 next_data(temp[i+1].level,temp[i+1].idx); - (*this)[lvl][idx].next_on_curve = next_data; - } - } - - for (unsigned i=0; i next = (*this)[i][j].next_on_curve; - (*this)[next.first][next.second].prev_on_curve = std::pair(i,j); - } - } -#if 0 - std::cout<<"\n"; - for (unsigned i=0; i "; - } - std::cout<<"\n"; - for (unsigned i=0; i= (*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 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 > bend(Piecewise > const &f, Piecewise bending){ - D2 > 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(&direction) ); - registerParameter( dynamic_cast(&do_bend) ); - registerParameter( dynamic_cast(&bender) ); - registerParameter( dynamic_cast(&dist_rdm) ); - registerParameter( dynamic_cast(&growth) ); - registerParameter( dynamic_cast(&top_edge_variation) ); - registerParameter( dynamic_cast(&bot_edge_variation) ); - registerParameter( dynamic_cast(&top_tgt_variation) ); - registerParameter( dynamic_cast(&bot_tgt_variation) ); - registerParameter( dynamic_cast(&scale_tf) ); - registerParameter( dynamic_cast(&scale_tb) ); - registerParameter( dynamic_cast(&scale_bf) ); - registerParameter( dynamic_cast(&scale_bb) ); - registerParameter( dynamic_cast(&top_smth_variation) ); - registerParameter( dynamic_cast(&bot_smth_variation) ); - registerParameter( dynamic_cast(&fat_output) ); - registerParameter( dynamic_cast(&stroke_width_top) ); - registerParameter( dynamic_cast(&stroke_width_bot) ); - registerParameter( dynamic_cast(&front_thickness) ); - registerParameter( dynamic_cast(&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 > -LPEHatches::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in){ - - Piecewise > result; - - Piecewise > transformed_pwd2_in = pwd2_in; - Piecewise 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(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 > snakePoints; - snakePoints = linearSnake(transformed_pwd2_in); - if ( snakePoints.size() > 0 ){ - Piecewise >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 -LPEHatches::generateLevels(Interval const &domain){ - std::vector 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 > -LPEHatches::linearSnake(Piecewise > const &f){ - - std::vector > result; - - Piecewise x = make_cuts_independent(f)[X]; - //Rque: derivative is computed twice in the 2 lines below!! - Piecewise dx = derivative(x); - OptInterval range = bounds_exact(x); - - if (not range) return result; - std::vector levels = generateLevels(*range); - std::vector > times; - times = multi_roots(x,levels); - -//TODO: fix multi_roots!!!***************************************** -//remove doubles :-( - std::vector > cleaned_times(levels.size(),std::vector()); - for (unsigned i=0; i0 ){ - double last_t = times[i][0]-1;//ugly hack!! - for (unsigned j=0; j0.000001){ - last_t = times[i][j]; - cleaned_times[i].push_back(last_t); - } - } - } - } - times = cleaned_times; -// for (unsigned i=0; i 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(); - lscs.findFirstUnused(i,j); - } - return result; -} - -//------------------------------------------------------- -// Smooth the linear hatches according to params... -//------------------------------------------------------- -Piecewise > -LPEHatches::smoothSnake(std::vector > const &linearSnake){ - - Piecewise > result; - for (unsigned comp=0; comp=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 inside[X]) inside_hdle_in = inside; - //if (inside_hdle_out[X] < inside[X]) inside_hdle_out = inside; - - if (is_top){ - res_comp_top.appendNew(last_top_hdle,new_hdle_in,new_pt); - res_comp_bot.appendNew(last_bot_hdle,inside_hdle_in,inside); - last_top_hdle = new_hdle_out; - last_bot_hdle = inside_hdle_out; - }else{ - res_comp_top.appendNew(last_top_hdle,inside_hdle_in,inside); - res_comp_bot.appendNew(last_bot_hdle,new_hdle_in,new_pt); - last_top_hdle = inside_hdle_out; - last_bot_hdle = new_hdle_out; - } - }else{ - res_comp.appendNew(last_hdle,new_hdle_in,new_pt); - } - - last_hdle = new_hdle_out; - i+=2; - is_top = !is_top; - } - if ( i(last_top_hdle,linearSnake[comp][i],linearSnake[comp][i]); - res_comp_bot.appendNew(last_bot_hdle,linearSnake[comp][i],linearSnake[comp][i]); - }else{ - res_comp.appendNew(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 deleted file mode 100644 index 029847186..000000000 --- a/src/live_effects/lpe-hatches.h +++ /dev/null @@ -1,77 +0,0 @@ -#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 > - doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); - - virtual void resetDefaults(SPItem * item); - - virtual void doBeforeEffect(SPLPEItem * item); - - std::vector - generateLevels(Geom::Interval const &domain); - - std::vector > - linearSnake(Geom::Piecewise > const &f); - - Geom::Piecewise > - smoothSnake(std::vector > 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-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp new file mode 100644 index 000000000..94d9669aa --- /dev/null +++ b/src/live_effects/lpe-rough-hatches.cpp @@ -0,0 +1,593 @@ +#define INKSCAPE_LPE_ROUGH_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 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-rough-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 next_on_curve; + std::pair 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 LevelCrossings; + +std::vector +discontinuities(Piecewise > const &f){ + std::vector 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{ +public: + LevelsCrossings():std::vector(){}; + LevelsCrossings(std::vector > const ×, + Piecewise > const &f, + Piecewise const &dx){ + + for (unsigned i=0; i0 ); + lc.used = false; + lcs.push_back(lc); + } + std::sort(lcs.begin(), lcs.end(), LevelCrossingOrder()); + push_back(lcs); + } + //Now create time ordering. + std::vectortemp; + for (unsigned i=0; i jumps = discontinuities(f); + unsigned jump_idx = 0; + unsigned first_in_comp = 0; + for (unsigned i=0; i jumps[jump_idx+1]){ + std::pairnext_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 next_data(temp[i+1].level,temp[i+1].idx); + (*this)[lvl][idx].next_on_curve = next_data; + } + } + + for (unsigned i=0; i next = (*this)[i][j].next_on_curve; + (*this)[next.first][next.second].prev_on_curve = std::pair(i,j); + } + } +#if 0 + std::cout<<"\n"; + for (unsigned i=0; i "; + } + std::cout<<"\n"; + for (unsigned i=0; i= (*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 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 > bend(Piecewise > const &f, Piecewise bending){ + D2 > ff = make_cuts_independent(f); + ff[X] += compose(bending, ff[Y]); + return sectionize(ff); +} + +//-------------------------------------------------------- +// The RoughHatches lpe. +//-------------------------------------------------------- +LPERoughHatches::LPERoughHatches(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(&direction) ); + registerParameter( dynamic_cast(&do_bend) ); + registerParameter( dynamic_cast(&bender) ); + registerParameter( dynamic_cast(&dist_rdm) ); + registerParameter( dynamic_cast(&growth) ); + registerParameter( dynamic_cast(&top_edge_variation) ); + registerParameter( dynamic_cast(&bot_edge_variation) ); + registerParameter( dynamic_cast(&top_tgt_variation) ); + registerParameter( dynamic_cast(&bot_tgt_variation) ); + registerParameter( dynamic_cast(&scale_tf) ); + registerParameter( dynamic_cast(&scale_tb) ); + registerParameter( dynamic_cast(&scale_bf) ); + registerParameter( dynamic_cast(&scale_bb) ); + registerParameter( dynamic_cast(&top_smth_variation) ); + registerParameter( dynamic_cast(&bot_smth_variation) ); + registerParameter( dynamic_cast(&fat_output) ); + registerParameter( dynamic_cast(&stroke_width_top) ); + registerParameter( dynamic_cast(&stroke_width_bot) ); + registerParameter( dynamic_cast(&front_thickness) ); + registerParameter( dynamic_cast(&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; +} + +LPERoughHatches::~LPERoughHatches() +{ + +} + +Geom::Piecewise > +LPERoughHatches::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in){ + + Piecewise > result; + + Piecewise > transformed_pwd2_in = pwd2_in; + Piecewise 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(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 > snakePoints; + snakePoints = linearSnake(transformed_pwd2_in); + if ( snakePoints.size() > 0 ){ + Piecewise >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 +LPERoughHatches::generateLevels(Interval const &domain){ + std::vector 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 > +LPERoughHatches::linearSnake(Piecewise > const &f){ + + std::vector > result; + + Piecewise x = make_cuts_independent(f)[X]; + //Rque: derivative is computed twice in the 2 lines below!! + Piecewise dx = derivative(x); + OptInterval range = bounds_exact(x); + + if (not range) return result; + std::vector levels = generateLevels(*range); + std::vector > times; + times = multi_roots(x,levels); + +//TODO: fix multi_roots!!!***************************************** +//remove doubles :-( + std::vector > cleaned_times(levels.size(),std::vector()); + for (unsigned i=0; i0 ){ + double last_t = times[i][0]-1;//ugly hack!! + for (unsigned j=0; j0.000001){ + last_t = times[i][j]; + cleaned_times[i].push_back(last_t); + } + } + } + } + times = cleaned_times; +// for (unsigned i=0; i 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(); + lscs.findFirstUnused(i,j); + } + return result; +} + +//------------------------------------------------------- +// Smooth the linear hatches according to params... +//------------------------------------------------------- +Piecewise > +LPERoughHatches::smoothSnake(std::vector > const &linearSnake){ + + Piecewise > result; + for (unsigned comp=0; comp=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 inside[X]) inside_hdle_in = inside; + //if (inside_hdle_out[X] < inside[X]) inside_hdle_out = inside; + + if (is_top){ + res_comp_top.appendNew(last_top_hdle,new_hdle_in,new_pt); + res_comp_bot.appendNew(last_bot_hdle,inside_hdle_in,inside); + last_top_hdle = new_hdle_out; + last_bot_hdle = inside_hdle_out; + }else{ + res_comp_top.appendNew(last_top_hdle,inside_hdle_in,inside); + res_comp_bot.appendNew(last_bot_hdle,new_hdle_in,new_pt); + last_top_hdle = inside_hdle_out; + last_bot_hdle = new_hdle_out; + } + }else{ + res_comp.appendNew(last_hdle,new_hdle_in,new_pt); + } + + last_hdle = new_hdle_out; + i+=2; + is_top = !is_top; + } + if ( i(last_top_hdle,linearSnake[comp][i],linearSnake[comp][i]); + res_comp_bot.appendNew(last_bot_hdle,linearSnake[comp][i],linearSnake[comp][i]); + }else{ + res_comp.appendNew(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 +LPERoughHatches::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 +LPERoughHatches::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-rough-hatches.h b/src/live_effects/lpe-rough-hatches.h new file mode 100644 index 000000000..23b2a0966 --- /dev/null +++ b/src/live_effects/lpe-rough-hatches.h @@ -0,0 +1,77 @@ +#ifndef INKSCAPE_LPE_ROUGH_HATCHES_H +#define INKSCAPE_LPE_ROUGH_HATCHES_H + +/** \file + * Fills an area with rough hatches. + */ + +/* + * 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 LPERoughHatches : public Effect { +public: + LPERoughHatches(LivePathEffectObject *lpeobject); + virtual ~LPERoughHatches(); + + virtual Geom::Piecewise > + doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); + + virtual void resetDefaults(SPItem * item); + + virtual void doBeforeEffect(SPLPEItem * item); + + std::vector + generateLevels(Geom::Interval const &domain); + + std::vector > + linearSnake(Geom::Piecewise > const &f); + + Geom::Piecewise > + smoothSnake(std::vector > 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; + + LPERoughHatches(const LPERoughHatches&); + LPERoughHatches& operator=(const LPERoughHatches&); +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif