Code

renamed lpe-hatches to lpe-rough-hatches.
authorjfbarraud <jfbarraud@users.sourceforge.net>
Wed, 26 Nov 2008 20:56:08 +0000 (20:56 +0000)
committerjfbarraud <jfbarraud@users.sourceforge.net>
Wed, 26 Nov 2008 20:56:08 +0000 (20:56 +0000)
src/live_effects/CMakeLists.txt
src/live_effects/effect-enum.h
src/live_effects/effect.cpp
src/live_effects/lpe-hatches.cpp [deleted file]
src/live_effects/lpe-hatches.h [deleted file]
src/live_effects/lpe-rough-hatches.cpp [new file with mode: 0644]
src/live_effects/lpe-rough-hatches.h [new file with mode: 0644]

index 89b7b9e3a7f72afdf15907e75d8665ee27d94451..72d955586b8bc9ab023f78ea7d2a7790e69af1c1 100644 (file)
@@ -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
index 1e82954f8a4ca9295ae235d6963686aab640af02..4c0d9389f3436ec1f092a799218c29b8497a25c8 100644 (file)
@@ -21,7 +21,7 @@ enum EffectType {
     PATTERN_ALONG_PATH,
     FREEHAND_SHAPE,
     SKETCH,
-    HATCHES,
+    ROUGH_HATCHES,
     VONKOCH,
     KNOT,
 #ifdef LPE_ENABLE_TEST_EFFECTS
index bb5f0c55465b196b830d3395f0e7b04106ecfcdb..2a316a0bb243df282db5398e082590080833b89c 100644 (file)
@@ -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<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"},
@@ -100,7 +100,7 @@ const Util::EnumData<EffectType> LPETypeData[] = {
     {COPY_ROTATE,           N_("Rotate copies"),           "copy_rotate"},
     {RULER,                 N_("Ruler"),                   "ruler"},
     {SKETCH,                N_("Sketch"),                  "sketch"},
-    {HATCHES,               N_("Hatches"),                 "hatches"},
+    {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<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
deleted file mode 100644 (file)
index 2205d91..0000000
+++ /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 &times,\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
deleted file mode 100644 (file)
index 0298471..0000000
+++ /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
new file mode 100644 (file)
index 0000000..94d9669
--- /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 &times,\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
new file mode 100644 (file)
index 0000000..23b2a09
--- /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