diff options
| author | Johan B. C. Engelen <jbc.engelen@swissonline.ch> | 2011-06-26 22:11:01 +0000 |
|---|---|---|
| committer | Johan Engelen <goejendaagh@zonnet.nl> | 2011-06-26 22:11:01 +0000 |
| commit | babd2b5943341cf5731c4c7fa037267e10c68bab (patch) | |
| tree | 9dfb513f5b07c9331fae544fcd9932733ebcde1a /src | |
| parent | - Add a third group of snap sources/targets, called ¨others¨ (before we had... (diff) | |
| download | inkscape-babd2b5943341cf5731c4c7fa037267e10c68bab.tar.gz inkscape-babd2b5943341cf5731c4c7fa037267e10c68bab.zip | |
LPE PowerStroke: add linecap (let's see how well this behaves, it has some bugs/features)
(bzr r10373)
Diffstat (limited to 'src')
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 98 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke.h | 5 |
2 files changed, 86 insertions, 17 deletions
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 82f4ccdea..cd692f402 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -3,9 +3,9 @@ * @brief PowerStroke LPE implementation. Creates curves with modifiable stroke width. */ /* Authors: - * Johan Engelen <j.b.c.engelen@utwente.nl> + * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl> * - * Copyright (C) 2010 Authors + * Copyright (C) 2010-2011 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -20,6 +20,7 @@ #include <2geom/sbasis-geometric.h> #include <2geom/transforms.h> #include <2geom/bezier-utils.h> +#include <2geom/svg-elliptical-arc.h> #include "live_effects/bezctx.h" #include "live_effects/bezctx_intf.h" @@ -275,11 +276,24 @@ static const Util::EnumData<unsigned> InterpolatorTypeData[] = { }; static const Util::EnumDataConverter<unsigned> InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); +enum LineCapType { + LINECAP_BUTT, + LINECAP_ROUND, + LINECAP_SHARP +}; +static const Util::EnumData<unsigned> LineCapTypeData[] = { + {LINECAP_BUTT , N_("Butt"), "Butt"}, + {LINECAP_ROUND , N_("Round"), "Round"}, + {LINECAP_SHARP , N_("Sharp"), "Sharp"} +}; +static const Util::EnumDataConverter<unsigned> LineCapTypeConverter(LineCapTypeData, sizeof(LineCapTypeData)/sizeof(*LineCapTypeData)); + LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : Effect(lpeobject), offset_points(_("Offset points"), _("Offset points"), "offset_points", &wr, this), sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve."), "sort_points", &wr, this, true), - interpolator_type(_("Interpolator type"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path."), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN) + interpolator_type(_("Interpolator type"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path."), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN), + linecap_type(_("Line cap type"), _("Determines the shape of the path ends."), "linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND) { show_orig_path = true; @@ -288,6 +302,7 @@ LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&offset_points) ); registerParameter( dynamic_cast<Parameter *>(&sort_points) ); registerParameter( dynamic_cast<Parameter *>(&interpolator_type) ); + registerParameter( dynamic_cast<Parameter *>(&linecap_type) ); } LPEPowerStroke::~LPEPowerStroke() @@ -332,35 +347,88 @@ LPEPowerStroke::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & Piecewise<D2<SBasis> > output; if (!closed_path) { + LineCapType linecap = static_cast<LineCapType>(linecap_type.get_value()); + // perhaps use std::list instead of std::vector? std::vector<Geom::Point> ts(offset_points.data().size() + 2); - // first and last point coincide with input path (for now at least) - ts.front() = Point(pwd2_in.domain().min(),0); - ts.back() = Point(pwd2_in.domain().max(),0); for (unsigned int i = 0; i < offset_points.data().size(); ++i) { ts.at(i+1) = offset_points.data().at(i); } - if (sort_points) { - sort(ts.begin(), ts.end(), compare_offsets); + sort(ts.begin()+1, ts.end()-1, compare_offsets); + } + switch (linecap) { + case LINECAP_SHARP: + // first and last point coincide with input path to make sharp points on ends + ts.front() = Point(pwd2_in.domain().min(),0); + ts.back() = Point(pwd2_in.domain().max(),0); + break; + case LINECAP_BUTT: + case LINECAP_ROUND: + default: + // first and last point have same distance from path as second and second to last points, respectively. + ts.front() = Point(pwd2_in.domain().min(), (*(ts.begin()+1))[Geom::Y] ); + ts.back() = Point(pwd2_in.domain().max(), (*(ts.end()-2))[Geom::Y] ); + break; } // create stroke path where points (x,y) := (t, offset) Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value())); Geom::Path strokepath = interpolator->interpolateToPath(ts); - Geom::Path mirroredpath = strokepath.reverse() * Geom::Scale(1,-1); delete interpolator; - strokepath.append(mirroredpath, Geom::Path::STITCH_DISCONTINUOUS); - strokepath.close(); + switch (linecap) { + case LINECAP_SHARP: + case LINECAP_BUTT: + { + Geom::Path mirroredpath = strokepath.reverse() * Geom::Scale(1,-1); + strokepath.append(mirroredpath, Geom::Path::STITCH_DISCONTINUOUS); + strokepath.close(); - D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); - Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); - Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); + D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); + Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); + Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); - output = compose(pwd2_in,x) + y*compose(n,x); + output = compose(pwd2_in,x) + y*compose(n,x); + break; + } + case LINECAP_ROUND: + default: + { + D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); + Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); + Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); + + // find time values for which x lies outside path domain + // and only take portion of x and y that lies within those time values + std::vector< double > rtsmin = roots (x - pwd2_in.domain().min()); + std::vector< double > rtsmax = roots (x - pwd2_in.domain().max()); + if ( !rtsmin.empty() && !rtsmax.empty() ) { + x = portion(x, rtsmin.at(0), rtsmax.at(0)); + y = portion(y, rtsmin.at(0), rtsmax.at(0)); + } + + output = compose(pwd2_in,x) + y*compose(n,x); + x = reverse(x); + y = reverse(y); + Piecewise<D2<SBasis> > mirrorpath = compose(pwd2_in,x) - y*compose(n,x); + + double radius1 = 0.5 * distance(output.lastValue(), mirrorpath.firstValue()); + Geom::SVGEllipticalArc cap1(output.lastValue(), radius1, radius1, M_PI/2., false, false, mirrorpath.firstValue()); + output.continuousConcat(Piecewise<D2<SBasis> >(cap1.toSBasis())); + + output.continuousConcat(mirrorpath); + + double radius2 = 0.5 * distance(output.firstValue(), output.lastValue()); + Geom::SVGEllipticalArc cap2(output.lastValue(), radius2, radius2, M_PI/2., false, false, output.firstValue()); + output.continuousConcat(Piecewise<D2<SBasis> >(cap2.toSBasis())); + + break; + } + } } else { // path is closed + // linecap parameter can be ignored // perhaps use std::list instead of std::vector? std::vector<Geom::Point> ts = offset_points.data(); diff --git a/src/live_effects/lpe-powerstroke.h b/src/live_effects/lpe-powerstroke.h index 7a1f3829a..6f34e16e2 100644 --- a/src/live_effects/lpe-powerstroke.h +++ b/src/live_effects/lpe-powerstroke.h @@ -2,9 +2,9 @@ * @brief PowerStroke LPE effect, see lpe-powerstroke.cpp. */ /* Authors: - * Johan Engelen <j.b.c.engelen@utwente.nl> + * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl> * - * Copyright (C) 2010 Authors + * Copyright (C) 2010-2011 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -33,6 +33,7 @@ private: PowerStrokePointArrayParam offset_points; BoolParam sort_points; EnumParam<unsigned> interpolator_type; + EnumParam<unsigned> linecap_type; LPEPowerStroke(const LPEPowerStroke&); LPEPowerStroke& operator=(const LPEPowerStroke&); |
