X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Flive_effects%2Flpe-curvestitch.cpp;h=e72f1aac15026d7b57f63ca547c997f329b7849a;hb=64caa91f2899a6648503a75dc7310841955b74fd;hp=b0e8dc8f7106cc0333159a46e3f9339ea7a58120;hpb=c7e8a6c1f9a8bda454439dea4bff0638811c2409;p=inkscape.git diff --git a/src/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp index b0e8dc8f7..e72f1aac1 100644 --- a/src/live_effects/lpe-curvestitch.cpp +++ b/src/live_effects/lpe-curvestitch.cpp @@ -1,120 +1,211 @@ -#define INKSCAPE_LPE_EXPRESSION_CPP -/** \file - * SVG implementation, used as an example for a base starting class - * when implementing new LivePathEffects. - * - */ -/* - * Authors: - * Johan Engelen -* -* Copyright (C) Johan Engelen 2007 - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "live_effects/lpe-curvestitch.h" -#include "display/curve.h" -#include - -#include <2geom/path.h> -#include <2geom/piecewise.h> -#include <2geom/sbasis.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; - -LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) : - Effect(lpeobject), - strokepath(_("Stroke path"), _("The path that will be stroked, whatever, think of good text here."), "strokepath", &wr, this, "M0,0 L1,0"), - nrofpaths(_("Nr of paths"), _("The number of paths that will be generated."), "count", &wr, this, 5), - startpoint_variation(_("Startpoint variation"), _("..."), "startpoint_variation", &wr, this, 0), - endpoint_variation(_("Endpoint variation"), _("..."), "endpoint_variation", &wr, this, 0) -{ - registerParameter( dynamic_cast(&nrofpaths) ); - registerParameter( dynamic_cast(&startpoint_variation) ); - registerParameter( dynamic_cast(&endpoint_variation) ); - registerParameter( dynamic_cast(&strokepath) ); - - nrofpaths.param_make_integer(); - nrofpaths.param_set_range(2, NR_HUGE); - -// startpoint_variation.param_set_range(-NR_HUGE, 1); -// endpoint_variation.param_set_range(-1, NR_HUGE); -} - -LPECurveStitch::~LPECurveStitch() -{ - -} - -std::vector -LPECurveStitch::doEffect (std::vector & path_in) -{ - if (path_in.size() >= 2) { - D2 > stroke = make_cuts_independant(strokepath); - Interval bndsStroke = bounds_exact(stroke[0]); - gdouble scaling = bndsStroke.max() - bndsStroke.min(); - Interval bndsStrokeY = bounds_exact(stroke[1]); - Point stroke_origin(bndsStroke.min(), (bndsStrokeY.max()+bndsStrokeY.min())/2); - - std::vector path_out (nrofpaths); - - // do this for all permutations if there are more than 2 paths? realllly cool! - Piecewise > A = arc_length_parametrization(Piecewise >(path_in[0].toPwSb()),2,.1); - Piecewise > B = arc_length_parametrization(Piecewise >(path_in[1].toPwSb()),2,.1); - Interval bndsA = A.domain(); - Interval bndsB = B.domain(); - gdouble incrementA = (bndsA.max()-bndsA.min()) / (nrofpaths-1); - gdouble incrementB = (bndsB.max()-bndsB.min()) / (nrofpaths-1); - gdouble tA = bndsA.min(); - gdouble tB = bndsB.min(); - for (int i = 0; i < nrofpaths; i++) { - Point start = A(tA); - Point end = B(tB); - if (startpoint_variation != 0) - start = start + g_random_double_range(0, startpoint_variation) * (end - start); - if (endpoint_variation != 0) - end = end + g_random_double_range(0, endpoint_variation) * (end - start); - - Matrix transform; - transform.setXAxis( (end-start) / scaling ); - transform.setYAxis( rot90(unit_vector(end-start))); - transform.setTranslation( start ); - Piecewise > pwd2_out = (strokepath-stroke_origin) * transform; - std::vector result = Geom::path_from_piecewise(pwd2_out, LPE_CONVERSION_TOLERANCE); - path_out[i] = result[0]; - tA += incrementA; - tB += incrementB; - } - - return path_out; - } else { - return path_in; - } -} - -} //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_CURVESTITCH_CPP +/** \file + * LPE Curve Stitching implementation, used as an example for a base starting class + * when implementing new LivePathEffects. + * + */ +/* + * Authors: + * Johan Engelen +* +* Copyright (C) Johan Engelen 2007 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-curvestitch.h" +#include "display/curve.h" +#include +#include "sp-item.h" +#include "sp-path.h" +#include "live_effects/n-art-bpath-2geom.h" +#include "xml/repr.h" + +#include <2geom/path.h> +#include <2geom/piecewise.h> +#include <2geom/sbasis.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; + +LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + strokepath(_("Stroke path"), _("The path that will be used as stitch."), "strokepath", &wr, this, "M0,0 L1,0"), + nrofpaths(_("Number of paths"), _("The number of paths that will be generated."), "count", &wr, this, 5), + startpoint_edge_variation(_("Start edge variance"), _("The amount of random jitter to move the start points of the stitches inside & outside the guide path"), "startpoint_edge_variation", &wr, this, 0), + startpoint_spacing_variation(_("Start spacing variance"), _("The amount of random shifting to move the start points of the stitches back & forth along the guide path"), "startpoint_spacing_variation", &wr, this, 0), + endpoint_edge_variation(_("End edge variance"), _("The amount of randomness that moves the end points of the stitches inside & outside the guide path"), "endpoint_edge_variation", &wr, this, 0), + endpoint_spacing_variation(_("End spacing variance"), _("The amount of random shifting to move the end points of the stitches back & forth along the guide path"), "endpoint_spacing_variation", &wr, this, 0), + prop_scale(_("Scale width"), _("Scaling of the width of the stroke path"), "prop_scale", &wr, this, 1), + scale_y_rel(_("Scale width relative"), _("Scale the width of the stroke path relative to its length"), "scale_y_rel", &wr, this, false) +{ + registerParameter( dynamic_cast(&nrofpaths) ); + registerParameter( dynamic_cast(&startpoint_edge_variation) ); + registerParameter( dynamic_cast(&startpoint_spacing_variation) ); + registerParameter( dynamic_cast(&endpoint_edge_variation) ); + registerParameter( dynamic_cast(&endpoint_spacing_variation) ); + registerParameter( dynamic_cast(&strokepath) ); + registerParameter( dynamic_cast(&prop_scale) ); + registerParameter( dynamic_cast(&scale_y_rel) ); + + nrofpaths.param_make_integer(); + nrofpaths.param_set_range(2, NR_HUGE); + + prop_scale.param_set_digits(3); + prop_scale.param_set_increments(0.01, 0.10); +} + +LPECurveStitch::~LPECurveStitch() +{ + +} + +std::vector +LPECurveStitch::doEffect_path (std::vector & path_in) +{ + if (path_in.size() >= 2) { + startpoint_edge_variation.resetRandomizer(); + endpoint_edge_variation.resetRandomizer(); + startpoint_spacing_variation.resetRandomizer(); + endpoint_spacing_variation.resetRandomizer(); + + D2 > stroke = make_cuts_independant(strokepath); + Interval bndsStroke = bounds_exact(stroke[0]); + gdouble scaling = bndsStroke.max() - bndsStroke.min(); + Interval bndsStrokeY = bounds_exact(stroke[1]); + Point stroke_origin(bndsStroke.min(), (bndsStrokeY.max()+bndsStrokeY.min())/2); + + std::vector path_out; + + // do this for all permutations (ii,jj) if there are more than 2 paths? realllly cool! + for (int ii = 0 ; ii < path_in.size() - 1; ii++) + for (int jj = ii+1; jj < path_in.size(); jj++) + { + Piecewise > A = arc_length_parametrization(Piecewise >(path_in[ii].toPwSb()),2,.1); + Piecewise > B = arc_length_parametrization(Piecewise >(path_in[jj].toPwSb()),2,.1); + Interval bndsA = A.domain(); + Interval bndsB = B.domain(); + gdouble incrementA = (bndsA.max()-bndsA.min()) / (nrofpaths-1); + gdouble incrementB = (bndsB.max()-bndsB.min()) / (nrofpaths-1); + gdouble tA = bndsA.min(); + gdouble tB = bndsB.min(); + gdouble tAclean = tA; // the tA without spacing_variation + gdouble tBclean = tB; // the tB without spacing_variation + + for (int i = 0; i < nrofpaths; i++) { + Point start = A(tA); + Point end = B(tB); + if (startpoint_edge_variation.get_value() != 0) + start = start + (startpoint_edge_variation - startpoint_edge_variation.get_value()/2) * (end - start); + if (endpoint_edge_variation.get_value() != 0) + end = end + (endpoint_edge_variation - endpoint_edge_variation.get_value()/2)* (end - start); + + if (!Geom::are_near(start,end)) { + gdouble scaling_y = 1.0; + if (scale_y_rel.get_value()) { + scaling_y = (L2(end-start)/scaling)*prop_scale; + } else { + scaling_y = prop_scale; + } + + Matrix transform; + transform.setXAxis( (end-start) / scaling ); + transform.setYAxis( rot90(unit_vector(end-start)) * scaling_y); + transform.setTranslation( start ); + Piecewise > pwd2_out = (strokepath-stroke_origin) * transform; + + // add stuff to one big pw > and then outside the loop convert to path? + // No: this way, the separate result paths are kept separate which might come in handy some time! + std::vector result = Geom::path_from_piecewise(pwd2_out, LPE_CONVERSION_TOLERANCE); + path_out.push_back(result[0]); + } + gdouble svA = startpoint_spacing_variation - startpoint_spacing_variation.get_value()/2; + gdouble svB = endpoint_spacing_variation - endpoint_spacing_variation.get_value()/2; + tAclean += incrementA; + tBclean += incrementB; + tA = tAclean + incrementA * svA; + tB = tBclean + incrementB * svB; + if (tA > bndsA.max()) + tA = bndsA.max(); + if (tB > bndsB.max()) + tB = bndsB.max(); + } + } + + return path_out; + } else { + return path_in; + } +} + +void +LPECurveStitch::resetDefaults(SPItem * item) +{ + if (!SP_IS_PATH(item)) return; + + using namespace Geom; + + // set the stroke path to run horizontally in the middle of the bounding box of the original path + Piecewise > pwd2; + std::vector temppath = SVGD_to_2GeomPath( SP_OBJECT_REPR(item)->attribute("inkscape:original-d")); + for (unsigned int i=0; i < temppath.size(); i++) { + pwd2.concat( temppath[i].toPwSb() ); + } + + D2 > d2pw = make_cuts_independant(pwd2); + Interval bndsX = bounds_exact(d2pw[0]); + Interval bndsY = bounds_exact(d2pw[1]); + Point start(bndsX.min(), (bndsY.max()+bndsY.min())/2); + Point end(bndsX.max(), (bndsY.max()+bndsY.min())/2); + + if ( !Geom::are_near(start,end) ) { + Geom::Path path; + path.start( start ); + path.appendNew( end ); + strokepath.param_set_and_write_new_value( path.toPwSb() ); + } else { + // bounding box is too small to make decent path. set to default default. :-) + strokepath.param_set_and_write_default(); + } +} + +void +LPECurveStitch::transform_multiply(Geom::Matrix const& postmul, bool set) +{ + // only take translations into account + if (postmul.isTranslation()) { + strokepath.param_transform_multiply(postmul, set); + } else if (!scale_y_rel.get_value()) { + // this basically means that for this transformation, the result should be the same as normal scaling the result path + // don't know how to do this yet. +// Geom::Matrix new_postmul; + //new_postmul.setIdentity(); +// new_postmul.setTranslation(postmul.translation()); +// Effect::transform_multiply(new_postmul, set); + } +} + +} //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 :