lpe-powerstroke.cpp revision e736a7d039d68eaf2a38a02e97587ec19c43898e
359a38ce40498397028473d956691915ed3e849atavmjong-free * @brief PowerStroke LPE implementation. Creates curves with modifiable stroke width.
359a38ce40498397028473d956691915ed3e849atavmjong-free * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>
359a38ce40498397028473d956691915ed3e849atavmjong-free * Copyright (C) 2010-2011 Authors
359a38ce40498397028473d956691915ed3e849atavmjong-free * Released under GNU GPL, read the file 'COPYING' for more information
359a38ce40498397028473d956691915ed3e849atavmjong-free/// @TODO Move this to 2geom
d1561c248f49dc3508ae9e6557fc0d371928e394Markus Engel virtual ~Interpolator() {};
359a38ce40498397028473d956691915ed3e849atavmjong-free static Interpolator* create(InterpolatorType type);
359a38ce40498397028473d956691915ed3e849atavmjong-free// virtual Piecewise<D2<SBasis> > interpolateToPwD2Sb(std::vector<Point> points) = 0;
359a38ce40498397028473d956691915ed3e849atavmjong-free virtual Geom::Path interpolateToPath(std::vector<Point> points) = 0;
359a38ce40498397028473d956691915ed3e849atavmjong-free virtual ~Linear() {};
359a38ce40498397028473d956691915ed3e849atavmjong-free virtual Path interpolateToPath(std::vector<Point> points) {
359a38ce40498397028473d956691915ed3e849atavmjong-free for (unsigned int i = 1 ; i < points.size(); ++i) {
359a38ce40498397028473d956691915ed3e849atavmjong-free path.appendNew<Geom::LineSegment>(points.at(i));
359a38ce40498397028473d956691915ed3e849atavmjong-free// this class is terrible
359a38ce40498397028473d956691915ed3e849atavmjong-free virtual Path interpolateToPath(std::vector<Point> points) {
359a38ce40498397028473d956691915ed3e849atavmjong-free // worst case gives us 2 segment per point
359a38ce40498397028473d956691915ed3e849atavmjong-free Geom::Point * b = g_new(Geom::Point, max_segs);
359a38ce40498397028473d956691915ed3e849atavmjong-free Geom::Point * points_array = g_new(Geom::Point, 4*n_points);
359a38ce40498397028473d956691915ed3e849atavmjong-free for (unsigned i = 0; i < n_points; ++i) {
359a38ce40498397028473d956691915ed3e849atavmjong-free double tolerance_sq = 0; // this value is just a random guess
359a38ce40498397028473d956691915ed3e849atavmjong-free int const n_segs = Geom::bezier_fit_cubic_r(b, points_array, n_points,
359a38ce40498397028473d956691915ed3e849atavmjong-free for (int c = 0; c < n_segs; c++) {
359a38ce40498397028473d956691915ed3e849atavmjong-free fit.appendNew<Geom::CubicBezier>(b[4*c+1], b[4*c+2], b[4*c+3]);
359a38ce40498397028473d956691915ed3e849atavmjong-free CubicBezierFit& operator=(const CubicBezierFit&);
359a38ce40498397028473d956691915ed3e849atavmjong-free/// @todo invent name for this class
359a38ce40498397028473d956691915ed3e849atavmjong-free virtual Path interpolateToPath(std::vector<Point> points) {
359a38ce40498397028473d956691915ed3e849atavmjong-free for (unsigned int i = 1; i < points.size(); ++i) {
359a38ce40498397028473d956691915ed3e849atavmjong-free fit.appendNew<CubicBezier>(p0+0.2*dx, p1-0.2*dx, p1);
359a38ce40498397028473d956691915ed3e849atavmjong-free CubicBezierJohan& operator=(const CubicBezierJohan&);
359a38ce40498397028473d956691915ed3e849atavmjong-freeclass SpiroInterpolator : public Interpolator {
359a38ce40498397028473d956691915ed3e849atavmjong-free virtual Path interpolateToPath(std::vector<Point> points) {
359a38ce40498397028473d956691915ed3e849atavmjong-free spiro_cp *controlpoints = g_new (spiro_cp, len);
359a38ce40498397028473d956691915ed3e849atavmjong-free for (unsigned int i = 0; i < len; ++i) {
359a38ce40498397028473d956691915ed3e849atavmjong-free typedef struct {
359a38ce40498397028473d956691915ed3e849atavmjong-free static void bezctx_ink_moveto(bezctx *bc, double x, double y, int /*is_open*/)
359a38ce40498397028473d956691915ed3e849atavmjong-free static void bezctx_ink_lineto(bezctx *bc, double x, double y)
359a38ce40498397028473d956691915ed3e849atavmjong-free bi->path->appendNew<LineSegment>( Point(x, y) );
359a38ce40498397028473d956691915ed3e849atavmjong-free static void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3)
359a38ce40498397028473d956691915ed3e849atavmjong-free if ( IS_FINITE(xm) && IS_FINITE(ym) && IS_FINITE(x3) && IS_FINITE(y3) ) {
359a38ce40498397028473d956691915ed3e849atavmjong-free bi->path->appendNew<QuadraticBezier>(Point(xm, ym), Point(x3, y3));
359a38ce40498397028473d956691915ed3e849atavmjong-free static void bezctx_ink_curveto(bezctx *bc, double x1, double y1, double x2, double y2,
359a38ce40498397028473d956691915ed3e849atavmjong-free if ( IS_FINITE(x1) && IS_FINITE(y1) && IS_FINITE(x2) && IS_FINITE(y2) ) {
359a38ce40498397028473d956691915ed3e849atavmjong-free bi->path->appendNew<CubicBezier>(Point(x1, y1), Point(x2, y2), Point(x3, y3));
359a38ce40498397028473d956691915ed3e849atavmjong-free SpiroInterpolator& operator=(const SpiroInterpolator&);
359a38ce40498397028473d956691915ed3e849atavmjong-free return new Geom::Interpolate::CubicBezierFit();
359a38ce40498397028473d956691915ed3e849atavmjong-free return new Geom::Interpolate::CubicBezierJohan();
359a38ce40498397028473d956691915ed3e849atavmjong-free return new Geom::Interpolate::SpiroInterpolator();
359a38ce40498397028473d956691915ed3e849atavmjong-free} //namespace Interpolate
359a38ce40498397028473d956691915ed3e849atavmjong-free} //namespace Geom
359a38ce40498397028473d956691915ed3e849atavmjong-freestatic const Util::EnumData<unsigned> InterpolatorTypeData[] = {
359a38ce40498397028473d956691915ed3e849atavmjong-free {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"},
359a38ce40498397028473d956691915ed3e849atavmjong-free {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"},
359a38ce40498397028473d956691915ed3e849atavmjong-free {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"},
359a38ce40498397028473d956691915ed3e849atavmjong-free {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"}
bf9ec3e969ba6b11cbbc613545aedc63cc886973Matthew Petroffstatic const Util::EnumDataConverter<unsigned> InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData));
359a38ce40498397028473d956691915ed3e849atavmjong-freestatic const Util::EnumData<unsigned> LineCapTypeData[] = {
359a38ce40498397028473d956691915ed3e849atavmjong-freestatic const Util::EnumDataConverter<unsigned> LineCapTypeConverter(LineCapTypeData, sizeof(LineCapTypeData)/sizeof(*LineCapTypeData));
359a38ce40498397028473d956691915ed3e849atavmjong-freestatic const Util::EnumData<unsigned> LineCuspTypeData[] = {
359a38ce40498397028473d956691915ed3e849atavmjong-freestatic const Util::EnumDataConverter<unsigned> LineCuspTypeConverter(LineCuspTypeData, sizeof(LineCuspTypeData)/sizeof(*LineCuspTypeData));
359a38ce40498397028473d956691915ed3e849atavmjong-freeLPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) :
359a38ce40498397028473d956691915ed3e849atavmjong-free offset_points(_("Offset points"), _("Offset points"), "offset_points", &wr, this),
359a38ce40498397028473d956691915ed3e849atavmjong-free sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve."), "sort_points", &wr, this, true),
359a38ce40498397028473d956691915ed3e849atavmjong-free 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),
359a38ce40498397028473d956691915ed3e849atavmjong-free start_linecap_type(_("Start line cap type"), _("Determines the shape of the path's start."), "start_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND),
359a38ce40498397028473d956691915ed3e849atavmjong-free cusp_linecap_type(_("Cusp line cap type"), _("Determines the shape of the cusps along the path."), "cusp_linecap_type", LineCuspTypeConverter, &wr, this, LINECUSP_ROUND),
359a38ce40498397028473d956691915ed3e849atavmjong-free end_linecap_type(_("End line cap type"), _("Determines the shape of the path's end."), "end_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND)
359a38ce40498397028473d956691915ed3e849atavmjong-free /// @todo offset_points are initialized with empty path, is that bug-save?
359a38ce40498397028473d956691915ed3e849atavmjong-free registerParameter( dynamic_cast<Parameter *>(&offset_points) );
359a38ce40498397028473d956691915ed3e849atavmjong-free registerParameter( dynamic_cast<Parameter *>(&sort_points) );
359a38ce40498397028473d956691915ed3e849atavmjong-free registerParameter( dynamic_cast<Parameter *>(&interpolator_type) );
359a38ce40498397028473d956691915ed3e849atavmjong-free registerParameter( dynamic_cast<Parameter *>(&start_linecap_type) );
359a38ce40498397028473d956691915ed3e849atavmjong-free //registerParameter( dynamic_cast<Parameter *>(&cusp_linecap_type) );
359a38ce40498397028473d956691915ed3e849atavmjong-free registerParameter( dynamic_cast<Parameter *>(&end_linecap_type) );
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White Geom::Path::size_type size = SP_SHAPE(lpeitem)->curve->get_pathvector().front().size_open();
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White offset_points.param_set_and_write_new_value(points);
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. Whitestatic bool compare_offsets (Geom::Point first, Geom::Point second)
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. WhiteLPEPowerStroke::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White using namespace Geom;
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in));
359a38ce40498397028473d956691915ed3e849atavmjong-free // see if we should treat the path as being closed.
359a38ce40498397028473d956691915ed3e849atavmjong-free if ( are_near(pwd2_in.firstValue(), pwd2_in.lastValue()) ) {
359a38ce40498397028473d956691915ed3e849atavmjong-free LineCapType start_linecap = static_cast<LineCapType>(start_linecap_type.get_value());
359a38ce40498397028473d956691915ed3e849atavmjong-free LineCapType end_linecap = static_cast<LineCapType>(end_linecap_type.get_value());
if (sort_points) {
switch (start_linecap) {
case LINECAP_PEAK:
case LINECAP_SQUARE:
case LINECAP_BUTT:
case LINECAP_ROUND:
// first and last point have same distance from path as second and second to last points, respectively.
switch (end_linecap) {
case LINECAP_PEAK:
case LINECAP_SQUARE:
case LINECAP_BUTT:
case LINECAP_ROUND:
Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value()));
delete interpolator;
x = reverse(x);
y = reverse(y);
switch (end_linecap) {
case LINECAP_PEAK:
case LINECAP_SQUARE:
Geom::LineSegment cap12(output.lastValue() + radius*end_deriv, mirrorpath.firstValue() + radius*end_deriv);
case LINECAP_BUTT:
case LINECAP_ROUND:
Geom::SVGEllipticalArc cap1(output.lastValue(), radius1, radius1, M_PI/2., false, y.firstValue() < 0, mirrorpath.firstValue()); // note that y is reversed above!
switch (start_linecap) {
case LINECAP_PEAK:
case LINECAP_SQUARE:
Geom::LineSegment cap22(output.lastValue() - radius*start_deriv, output.firstValue() - radius*start_deriv);
case LINECAP_BUTT:
case LINECAP_ROUND:
Geom::SVGEllipticalArc cap2(output.lastValue(), radius2, radius2, M_PI/2., false, y.lastValue() < 0, output.firstValue()); // note that y is reversed above!
if (sort_points) {
Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value()));
delete interpolator;
x = reverse(x);
y = reverse(y);
return output;