From 4f0165ebdaf2a07079d6b9f166a585fd89e8b064 Mon Sep 17 00:00:00 2001 From: Peter Moulder Date: Tue, 7 Apr 2009 06:32:25 +0000 Subject: noop: Set svn:eol-style to native on all .cpp and .h files under src. (find \( -name '*.cpp' -o -name '*.h' \) -print0 | xargs -0 svn propset svn:eol-style native) (bzr r7649) --- src/live_effects/lpe-rough-hatches.cpp | 1170 ++++++++++++++++---------------- src/live_effects/lpe-rough-hatches.h | 156 ++--- 2 files changed, 663 insertions(+), 663 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp index d75941b12..4cf3e35e6 100644 --- a/src/live_effects/lpe-rough-hatches.cpp +++ b/src/live_effects/lpe-rough-hatches.cpp @@ -1,585 +1,585 @@ -#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] );// a.pt[X] == b.pt[X] since we are supposed to be on the same level... - //return ( a.pt[X] < b.pt[X] || ( a.pt[X] == b.pt[X] && 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); - } - } - } - - void findFirstUnused(unsigned &level, unsigned &idx){ - level = size(); - idx = 0; - 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; - 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), - direction(_("Hatches width and dir"), _("Defines hatches frequency and direction"), "direction", &wr, this, Geom::Point(50,0)), - dist_rdm(_("Frequency randomness"), _("Variation of dist between hatches, in %."), "dist_rdm", &wr, this, 75), - growth(_("Growth"), _("Growth of distance between hatches."), "growth", &wr, this, 0.), -//FIXME: top/bottom names are inverted in the UI/svg and in the code!! - scale_tf(_("Half turns smoothness: 1st side, in"), _("Set smoothness/sharpness of path when reaching a 'bottom' halfturn. 0=sharp, 1=default"), "scale_bf", &wr, this, 1.), - scale_tb(_("1st side, out"), _("Set smoothness/sharpness of path when leaving a 'bottom' halfturn. 0=sharp, 1=default"), "scale_bb", &wr, this, 1.), - scale_bf(_("2nd side, in "), _("Set smoothness/sharpness of path when reaching a 'top' halfturn. 0=sharp, 1=default"), "scale_tf", &wr, this, 1.), - scale_bb(_("2nd side, out"), _("Set smoothness/sharpness of path when leaving a 'top' halfturn. 0=sharp, 1=default"), "scale_tb", &wr, this, 1.), - top_smth_variation(_("variance: 1st side"), _("Randomness of 'bottom' halfturns smoothness"), "top_smth_variation", &wr, this, 0), - bot_smth_variation(_("2nd side"), _("Randomness of 'top' halfturns smoothness"), "bottom_smth_variation", &wr, this, 0), -// - top_edge_variation(_("Magnitude jitter: 1st side"), _("Randomly moves 'bottom' halfsturns to produce magnitude variations."), "bottom_edge_variation", &wr, this, 0), - bot_edge_variation(_("2nd side"), _("Randomly moves 'top' halfsturns to produce magnitude variations."), "top_edge_variation", &wr, this, 0), - top_tgt_variation(_("Parallelism jitter: 1st side"), _("Add direction randomness by moving 'bottom' halfsturns tangentially to the boundary."), "bottom_tgt_variation", &wr, this, 0), - bot_tgt_variation(_("2nd side"), _("Add direction randomness by randomly moving 'top' halfsturns tangentially to the boundary."), "top_tgt_variation", &wr, this, 0), -// - do_bend(_("Bend hatches"), _("Add a global bend to the hatches (slower)"), "do_bend", &wr, this, true), - //bender(_("Global bending"), _("Relative position to ref point defines global bending direction and amount"), "bender", &wr, this, NULL, Geom::Point(-5,0)), - bender(_("Global bending"), _("Relative position to ref point defines global bending direction and amount"), "bender", &wr, this, Geom::Point(-5,0)), -// - fat_output(_("Generate thick/thin path"), _("Simulate a stroke of varrying width"), "fat_output", &wr, this, true), - stroke_width_top(_("Thikness: at 1st side"), _("Width at 'bottom' half turns"), "stroke_width_top", &wr, this, 1.), - stroke_width_bot(_("at 2nd side"), _("Width at 'top' halfturns"), "stroke_width_bottom", &wr, this, 1.), - front_thickness(_("from 2nd to 1st side"), _("Width of paths from 'top' to 'bottom' halfturns"), "front_thickness", &wr, this, 1.), - back_thickness(_("from 1st to 2nd side"), _("Width of paths from 'top' to 'bottom' halfturns"), "back_thickness", &wr, this, .25) -{ - registerParameter( dynamic_cast(&direction) ); - registerParameter( dynamic_cast(&dist_rdm) ); - registerParameter( dynamic_cast(&growth) ); - registerParameter( dynamic_cast(&do_bend) ); - registerParameter( dynamic_cast(&bender) ); - 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, 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 = false; - show_orig_path = true; -} - -LPERoughHatches::~LPERoughHatches() -{ - -} - -Geom::Piecewise > -LPERoughHatches::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in){ - - //std::cout<<"doEffect_pwd2:\n"; - - Piecewise > result; - - Piecewise > transformed_pwd2_in = pwd2_in; - Point start = pwd2_in.segs.front().at0(); - Point end = pwd2_in.segs.back().at1(); - if (end != start ){ - transformed_pwd2_in.push_cut( transformed_pwd2_in.cuts.back() + 1 ); - D2 stitch( SBasis( 1, Linear(end[X],start[X]) ), SBasis( 1, Linear(end[Y],start[Y]) ) ); - transformed_pwd2_in.push_seg( stitch ); - } - Point transformed_org = direction.getOrigin(); - 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(bender.getVector())); - double bend_amount = L2(bender.getVector()); - bend_mat = Matrix(-bend_dir[Y], bend_dir[X], bend_dir[X], bend_dir[Y],0,0); - transformed_pwd2_in = transformed_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; - transformed_org *= mat; - - std::vector > snakePoints; - snakePoints = linearSnake(transformed_pwd2_in, transformed_org); - 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, double x_org){ - std::vector result; - int n = int((domain.min()-x_org)/hatch_dist); - double x = x_org + n * hatch_dist; - //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, Point const &org){ - - //std::cout<<"linearSnake:\n"; - std::vector > result; - Piecewise x = make_cuts_independent(f)[X]; - //Remark: 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, org[X]); - 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; -//******************************************************************* - - LevelsCrossings lscs(times,f,dx); - - unsigned i,j; - lscs.findFirstUnused(i,j); - - std::vector result_component; - int n = int((range->min()-org[X])/hatch_dist); - - while ( i < lscs.size() ){ - int dir = 0; - //switch orientation of first segment according to starting point. - if (i % 2 == n%2 && j < lscs[i].size()-1 && !lscs[i][j].used){ - j += 1; - dir = 2; - } - - 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){ - 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; - //bool is_top = true;//Inversion here; due to downward y? - bool is_top = ( linearSnake[comp][0][Y] < linearSnake[comp][1][Y] ); - - 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) -{ - Effect::resetDefaults(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 ); - top_edge_variation.write_to_SVG(); - bot_edge_variation.write_to_SVG(); - } - //direction.set_and_write_new_values(origin, vector); - //bender.param_set_and_write_new_value( origin + Geom::Point(5,0) ); - direction.set_and_write_new_values(origin + Geom::Point(0,-5), vector); - bender.set_and_write_new_values( origin, Geom::Point(5,0) ); - hatch_dist = Geom::L2(vector)/2; -} - - -} //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 : +#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] );// a.pt[X] == b.pt[X] since we are supposed to be on the same level... + //return ( a.pt[X] < b.pt[X] || ( a.pt[X] == b.pt[X] && 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); + } + } + } + + void findFirstUnused(unsigned &level, unsigned &idx){ + level = size(); + idx = 0; + 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; + 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), + direction(_("Hatches width and dir"), _("Defines hatches frequency and direction"), "direction", &wr, this, Geom::Point(50,0)), + dist_rdm(_("Frequency randomness"), _("Variation of dist between hatches, in %."), "dist_rdm", &wr, this, 75), + growth(_("Growth"), _("Growth of distance between hatches."), "growth", &wr, this, 0.), +//FIXME: top/bottom names are inverted in the UI/svg and in the code!! + scale_tf(_("Half turns smoothness: 1st side, in"), _("Set smoothness/sharpness of path when reaching a 'bottom' halfturn. 0=sharp, 1=default"), "scale_bf", &wr, this, 1.), + scale_tb(_("1st side, out"), _("Set smoothness/sharpness of path when leaving a 'bottom' halfturn. 0=sharp, 1=default"), "scale_bb", &wr, this, 1.), + scale_bf(_("2nd side, in "), _("Set smoothness/sharpness of path when reaching a 'top' halfturn. 0=sharp, 1=default"), "scale_tf", &wr, this, 1.), + scale_bb(_("2nd side, out"), _("Set smoothness/sharpness of path when leaving a 'top' halfturn. 0=sharp, 1=default"), "scale_tb", &wr, this, 1.), + top_smth_variation(_("variance: 1st side"), _("Randomness of 'bottom' halfturns smoothness"), "top_smth_variation", &wr, this, 0), + bot_smth_variation(_("2nd side"), _("Randomness of 'top' halfturns smoothness"), "bottom_smth_variation", &wr, this, 0), +// + top_edge_variation(_("Magnitude jitter: 1st side"), _("Randomly moves 'bottom' halfsturns to produce magnitude variations."), "bottom_edge_variation", &wr, this, 0), + bot_edge_variation(_("2nd side"), _("Randomly moves 'top' halfsturns to produce magnitude variations."), "top_edge_variation", &wr, this, 0), + top_tgt_variation(_("Parallelism jitter: 1st side"), _("Add direction randomness by moving 'bottom' halfsturns tangentially to the boundary."), "bottom_tgt_variation", &wr, this, 0), + bot_tgt_variation(_("2nd side"), _("Add direction randomness by randomly moving 'top' halfsturns tangentially to the boundary."), "top_tgt_variation", &wr, this, 0), +// + do_bend(_("Bend hatches"), _("Add a global bend to the hatches (slower)"), "do_bend", &wr, this, true), + //bender(_("Global bending"), _("Relative position to ref point defines global bending direction and amount"), "bender", &wr, this, NULL, Geom::Point(-5,0)), + bender(_("Global bending"), _("Relative position to ref point defines global bending direction and amount"), "bender", &wr, this, Geom::Point(-5,0)), +// + fat_output(_("Generate thick/thin path"), _("Simulate a stroke of varrying width"), "fat_output", &wr, this, true), + stroke_width_top(_("Thikness: at 1st side"), _("Width at 'bottom' half turns"), "stroke_width_top", &wr, this, 1.), + stroke_width_bot(_("at 2nd side"), _("Width at 'top' halfturns"), "stroke_width_bottom", &wr, this, 1.), + front_thickness(_("from 2nd to 1st side"), _("Width of paths from 'top' to 'bottom' halfturns"), "front_thickness", &wr, this, 1.), + back_thickness(_("from 1st to 2nd side"), _("Width of paths from 'top' to 'bottom' halfturns"), "back_thickness", &wr, this, .25) +{ + registerParameter( dynamic_cast(&direction) ); + registerParameter( dynamic_cast(&dist_rdm) ); + registerParameter( dynamic_cast(&growth) ); + registerParameter( dynamic_cast(&do_bend) ); + registerParameter( dynamic_cast(&bender) ); + 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, 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 = false; + show_orig_path = true; +} + +LPERoughHatches::~LPERoughHatches() +{ + +} + +Geom::Piecewise > +LPERoughHatches::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in){ + + //std::cout<<"doEffect_pwd2:\n"; + + Piecewise > result; + + Piecewise > transformed_pwd2_in = pwd2_in; + Point start = pwd2_in.segs.front().at0(); + Point end = pwd2_in.segs.back().at1(); + if (end != start ){ + transformed_pwd2_in.push_cut( transformed_pwd2_in.cuts.back() + 1 ); + D2 stitch( SBasis( 1, Linear(end[X],start[X]) ), SBasis( 1, Linear(end[Y],start[Y]) ) ); + transformed_pwd2_in.push_seg( stitch ); + } + Point transformed_org = direction.getOrigin(); + 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(bender.getVector())); + double bend_amount = L2(bender.getVector()); + bend_mat = Matrix(-bend_dir[Y], bend_dir[X], bend_dir[X], bend_dir[Y],0,0); + transformed_pwd2_in = transformed_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; + transformed_org *= mat; + + std::vector > snakePoints; + snakePoints = linearSnake(transformed_pwd2_in, transformed_org); + 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, double x_org){ + std::vector result; + int n = int((domain.min()-x_org)/hatch_dist); + double x = x_org + n * hatch_dist; + //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, Point const &org){ + + //std::cout<<"linearSnake:\n"; + std::vector > result; + Piecewise x = make_cuts_independent(f)[X]; + //Remark: 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, org[X]); + 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; +//******************************************************************* + + LevelsCrossings lscs(times,f,dx); + + unsigned i,j; + lscs.findFirstUnused(i,j); + + std::vector result_component; + int n = int((range->min()-org[X])/hatch_dist); + + while ( i < lscs.size() ){ + int dir = 0; + //switch orientation of first segment according to starting point. + if (i % 2 == n%2 && j < lscs[i].size()-1 && !lscs[i][j].used){ + j += 1; + dir = 2; + } + + 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){ + 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; + //bool is_top = true;//Inversion here; due to downward y? + bool is_top = ( linearSnake[comp][0][Y] < linearSnake[comp][1][Y] ); + + 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) +{ + Effect::resetDefaults(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 ); + top_edge_variation.write_to_SVG(); + bot_edge_variation.write_to_SVG(); + } + //direction.set_and_write_new_values(origin, vector); + //bender.param_set_and_write_new_value( origin + Geom::Point(5,0) ); + direction.set_and_write_new_values(origin + Geom::Point(0,-5), vector); + bender.set_and_write_new_values( origin, Geom::Point(5,0) ); + hatch_dist = Geom::L2(vector)/2; +} + + +} //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 index 816955e4d..cbc3c3b26 100644 --- a/src/live_effects/lpe-rough-hatches.h +++ b/src/live_effects/lpe-rough-hatches.h @@ -1,78 +1,78 @@ -#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, double x_org); - - std::vector > - linearSnake(Geom::Piecewise > const &f, Geom::Point const &org); - - 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; - VectorParam bender; - - LPERoughHatches(const LPERoughHatches&); - LPERoughHatches& operator=(const LPERoughHatches&); -}; - -} //namespace LivePathEffect -} //namespace Inkscape - -#endif +#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, double x_org); + + std::vector > + linearSnake(Geom::Piecewise > const &f, Geom::Point const &org); + + 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; + VectorParam bender; + + LPERoughHatches(const LPERoughHatches&); + LPERoughHatches& operator=(const LPERoughHatches&); +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif -- cgit v1.2.3