diff options
| author | Johan B. C. Engelen <jbc.engelen@swissonline.ch> | 2012-02-26 21:59:20 +0000 |
|---|---|---|
| committer | Johan Engelen <goejendaagh@zonnet.nl> | 2012-02-26 21:59:20 +0000 |
| commit | 7fa31d75591543f64cb70b73f19533d5b7f35dba (patch) | |
| tree | 737f5efabbb21c605bdf818530227cb3d3de9dc4 /src | |
| parent | Import deprecated GtkRuler API. Probably worth tidying :-) (diff) | |
| download | inkscape-7fa31d75591543f64cb70b73f19533d5b7f35dba.tar.gz inkscape-7fa31d75591543f64cb70b73f19533d5b7f35dba.zip | |
powerstroke: work on cusps, so people can play with it a bit. it is not done yet ! so may change in future...
(partial update to latest 2geom, for reflection transform)
(bzr r11024)
Diffstat (limited to 'src')
| -rw-r--r-- | src/2geom/transforms.cpp | 11 | ||||
| -rw-r--r-- | src/2geom/transforms.h | 11 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 66 |
3 files changed, 72 insertions, 16 deletions
diff --git a/src/2geom/transforms.cpp b/src/2geom/transforms.cpp index b8355cadc..65df9b22f 100644 --- a/src/2geom/transforms.cpp +++ b/src/2geom/transforms.cpp @@ -5,8 +5,9 @@ * Authors: * ? <?@?.?> * Krzysztof Kosiński <tweenk.pl@gmail.com> + * Johan Engelen * - * Copyright ?-2009 Authors + * Copyright ?-2012 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -171,8 +172,16 @@ void check_transforms() m = z * t; m = z * s; m = z * r; m = z * h; m = z * v; m = z * z; } +Affine reflection(Point const & vector, Point const & origin) { + Geom::Point vec_norm = unit_vector(vector); + Affine mirror ( vec_norm[X]*vec_norm[X] - vec_norm[Y]*vec_norm[Y], 2 * vec_norm[X] * vec_norm[Y] , + 2 * vec_norm[X] * vec_norm[Y], vec_norm[Y]*vec_norm[Y] - vec_norm[X]*vec_norm[X] , + 0 ,0 ); + return Translate(-origin) * mirror * Translate(origin); } +} // namespace Geom + /* Local Variables: mode:c++ diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h index eaf869056..869e955c7 100644 --- a/src/2geom/transforms.h +++ b/src/2geom/transforms.h @@ -5,8 +5,9 @@ * Authors: * ? <?@?.?> * Krzysztof Kosiński <tweenk.pl@gmail.com> + * Johan Engelen * - * Copyright ?-2009 Authors + * Copyright ?-2012 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -280,7 +281,7 @@ inline bool are_near(VShear const &a, VShear const &b, Coord eps=EPSILON) { * The translation part is applied first, then the result is scaled from the new origin. * This way when the class is used to accumulate a zoom transform, trans always points * to the new origin in original coordinates. - * @ingroup Transform */ + * @ingroup Transforms */ class Zoom : public TransformOperations< Zoom > { @@ -338,6 +339,12 @@ inline Translate pow(Translate const &t, int n) { return ret; } + +/** @brief Reflects objects about line. + * The line, defined by a vector along the line and a point on it, acts as a mirror. + */ +Affine reflection(Point const & vector, Point const & origin); + //TODO: decomposition of Affine into some finite combination of the above classes } // end namespace Geom diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index e385febec..bb57dc2f7 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -24,7 +24,8 @@ #include <2geom/svg-elliptical-arc.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/svg-path.h> - +#include <2geom/path-intersection.h> +#include <2geom/crossing.h> namespace Inkscape { namespace LivePathEffect { @@ -56,12 +57,12 @@ static const Util::EnumDataConverter<unsigned> LineCapTypeConverter(LineCapTypeD enum LineCuspType { LINECUSP_BEVEL, LINECUSP_ROUND, - LINECUSP_SHARP + LINECUSP_CUSP }; static const Util::EnumData<unsigned> LineCuspTypeData[] = { - {LINECUSP_BEVEL , N_("Beveled"), "bevel"}, - {LINECUSP_ROUND , N_("Rounded"), "round"}, -// not yet supported {LINECUSP_SHARP , N_("Sharp"), "sharp"} + {LINECUSP_BEVEL , N_("Beveled"), "bevel"}, + {LINECUSP_ROUND , N_("Rounded"), "round"}, + {LINECUSP_CUSP , N_("Cusp"), "cusp"}, }; static const Util::EnumDataConverter<unsigned> LineCuspTypeConverter(LineCuspTypeData, sizeof(LineCuspTypeData)/sizeof(*LineCuspTypeData)); @@ -156,6 +157,7 @@ std::vector<discontinuity_data> find_discontinuities( Geom::Piecewise<Geom::D2<G Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> > const & B, std::vector<discontinuity_data> const & cusps, LineCuspType cusp_linecap, + bool forward_direction, double tol=Geom::EPSILON) { /* per definition, each discontinuity should be fixed with a cusp-ending, as defined by cusp_linecap_type @@ -165,14 +167,16 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> return pb.peek().front(); } - unsigned int cusp_i = 0; + double sign = forward_direction ? 1. : -1.; + + unsigned int cusp_i = forward_direction ? 0 : cusps.size()-1; Geom::Point start = B[0].at0(); pb.moveTo(start); build_from_sbasis(pb, B[0], tol, false); for (unsigned i=1; i < B.size(); i++) { if (!are_near(B[i-1].at1(), B[i].at0(), tol) ) { // discontinuity found, so fix it :-) - discontinuity_data const &cusp = cusps[cusp_i]; + discontinuity_data cusp = cusps[cusp_i]; switch (cusp_linecap) { case LINECUSP_ROUND: // properly bugged ^_^ @@ -180,14 +184,50 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> angle_between(cusp.der0, cusp.der1), false, cusp.width < 0, B[i].at0() ); break; - case LINECUSP_SHARP: // no clue yet what to do here :) + case LINECUSP_CUSP: { + // first figure out whether we are on the outside or inside of the corner in the path + if ( sign*cusp.width*angle_between(cusp.der0, cusp.der1) < 0.) { + // we are on the outside, do something complicated to make it look good ;) + + Geom::D2<Geom::SBasis> newcurve1 = + B[i-1] * Geom::reflection(rot90(derivative(B[i-1]).at1()), B[i-1].at1()); + newcurve1 = reverse(newcurve1); + std::vector<Geom::Point> temp; + sbasis_to_bezier(temp, newcurve1, 4); + Geom::CubicBezier bzr1( temp ); + + Geom::D2<Geom::SBasis> newcurve2 = + B[i] * Geom::reflection(rot90(derivative(B[i]).at0()), B[i].at0()); + newcurve2 = reverse(newcurve2); + sbasis_to_bezier(temp, newcurve2, 4); + Geom::CubicBezier bzr2( temp ); + + Geom::Crossings cross = crossings(bzr1, bzr2); + if (cross.empty()) { +g_message("empty crossing: decide what to do..."); + pb.curveTo(bzr1[1], bzr1[2], bzr1[3]); + pb.lineTo(bzr2[0]); + pb.curveTo(bzr2[1], bzr2[2], bzr2[3]); + } else { + std::pair<Geom::CubicBezier, Geom::CubicBezier> sub1 = bzr1.subdivide(cross[0].ta); + std::pair<Geom::CubicBezier, Geom::CubicBezier> sub2 = bzr2.subdivide(cross[0].tb); + pb.curveTo(sub1.first[1], sub1.first[2], sub1.first[3]); + pb.curveTo(sub2.second[1], sub2.second[2], sub2.second[3]); + } + + } else { + // we are on the inside, do a simple bevel to connect the paths + pb.lineTo(B[i].at0()); // default to bevel for too shallow cusp angles + } + break; + } case LINECUSP_BEVEL: default: pb.lineTo(B[i].at0()); break; } - cusp_i++; + cusp_i += forward_direction ? 1 : -1; } build_from_sbasis(pb, B[i], tol, false); } @@ -209,8 +249,8 @@ LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in) // for now, only regard first subpath and ignore the rest Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[0].toPwSb(); - Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in)); - Piecewise<D2<SBasis> > n = rot90(der); + Piecewise<D2<SBasis> > der = derivative(pwd2_in); + Piecewise<D2<SBasis> > n = rot90(unitVector(der)); offset_points.set_pwd2(pwd2_in, n); LineCapType end_linecap = static_cast<LineCapType>(end_linecap_type.get_value()); @@ -263,8 +303,8 @@ LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in) Piecewise<D2<SBasis> > pwd2_out = compose(pwd2_in,x) + y*compose(n,x); Piecewise<D2<SBasis> > mirrorpath = reverse(compose(pwd2_in,x) - y*compose(n,x)); - Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, cusps, cusp_linecap, LPE_CONVERSION_TOLERANCE); - Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, cusps, cusp_linecap, LPE_CONVERSION_TOLERANCE); + Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, cusps, cusp_linecap, true, LPE_CONVERSION_TOLERANCE); + Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, cusps, cusp_linecap, false, LPE_CONVERSION_TOLERANCE); if (path_in[0].closed()) { fixed_path.close(true); |
