diff options
| author | Johan B. C. Engelen <jbc.engelen@swissonline.ch> | 2012-04-14 15:22:15 +0000 |
|---|---|---|
| committer | Johan B. C. Engelen <j.b.c.engelen@alumnus.utwente.nl> | 2012-04-14 15:22:15 +0000 |
| commit | 10cd24ae4da25d86677622f847e6962cecf718d0 (patch) | |
| tree | ca7150c7a61a006384e32cb53e593ce989009844 /src | |
| parent | export dialog: type fix (diff) | |
| download | inkscape-10cd24ae4da25d86677622f847e6962cecf718d0.tar.gz inkscape-10cd24ae4da25d86677622f847e6962cecf718d0.zip | |
powerstroke: more robust method of determining parameters at joins. should fix some bugs. (may introduce new ones...)
(bzr r11247)
Diffstat (limited to 'src')
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 89 |
1 files changed, 18 insertions, 71 deletions
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 281376cde..a9cf22f6a 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -205,47 +205,8 @@ static bool compare_offsets (Geom::Point first, Geom::Point second) return first[Geom::X] < second[Geom::X]; } -// find discontinuities in input path -struct discontinuity_data { - Geom::Point der0; // unit derivative of 'left' side of join - Geom::Point der1; // unit derivative of 'right' side of join - double width; // intended stroke width at join -}; -std::vector<discontinuity_data> find_discontinuities( Geom::Piecewise<Geom::D2<Geom::SBasis> > const & der, - Geom::Piecewise<Geom::SBasis> const & x, - Geom::Piecewise<Geom::SBasis> const & y, - double eps=Geom::EPSILON ) -{ - std::vector<discontinuity_data> vect; - for(unsigned i = 1; i < der.size(); i++) { - if ( ! are_near(der[i-1].at1(), der[i].at0(), eps) ) { - discontinuity_data data; - - data.der0 = der[i-1].at1(); - data.der1 = der[i].at0(); - if ( Geom::are_near(data.der0.length(), 0) ) { - data.der0 = -unitTangentAt(reverse(der[i-1]),0.,2); // == unitTangentAt(der[i-1], 1, 2); - } - if ( Geom::are_near(data.der1.length(), 0) ) { - data.der1 = unitTangentAt(der[i], 0, 2); - } - - double t = der.cuts[i]; - std::vector< double > rts = roots (x - t); /// @todo this has multiple solutions for general strokewidth paths (generated by spiro interpolator...), ignore for now - if (!rts.empty()) { - data.width = y(rts.front()); - } else { - data.width = 1; - } - vect.push_back(data); - } - } - return vect; -} - - Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> > const & B, - std::vector<discontinuity_data> const & cusps, + Geom::Piecewise<Geom::SBasis> const & y, // width path LineJoinType jointype, double miter_limit, bool forward_direction, @@ -258,9 +219,6 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> return pb.peek().front(); } - 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); @@ -273,9 +231,12 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> } if (!are_near(B[prev_i].at1(), B[i].at0(), tol) ) { // discontinuity found, so fix it :-) - discontinuity_data cusp = cusps[cusp_i]; + double width = y( B.cuts[i] ); - bool on_outside = ( sign*cusp.width*angle_between(cusp.der0, cusp.der1) < 0. ); + Geom::Point tang1 = -unitTangentAt(reverse(B[prev_i]),0.); // = unitTangentAt(B[prev_i],1); + Geom::Point tang2 = unitTangentAt(B[i],0); + Geom::Point discontinuity_vec = B[i].at0() - B[prev_i].at1(); + bool on_outside = ( dot(tang1, discontinuity_vec) >= 0. ); switch (jointype) { case LINEJOIN_ROUND: { @@ -289,8 +250,6 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> A 2Geom method was created to do exactly this :) */ - Geom::Point tang1 = -unitTangentAt(reverse(B[prev_i]),0.); // = unitTangentAt(B[prev_i],1); - Geom::Point tang2 = unitTangentAt(B[i],0); boost::optional<Geom::Point> O = intersection_point( B[prev_i].at1(), tang1, B[i].at0(), tang2 ); if (!O) { @@ -301,7 +260,7 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> Geom::Ellipse ellipse = find_ellipse(B[prev_i].at1(), B[i].at0(), *O); pb.arcTo( ellipse.ray(Geom::X), ellipse.ray(Geom::Y), ellipse.rot_angle(), - false, cusp.width < 0, B[i].at0() ); + false, width < 0, B[i].at0() ); } 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 @@ -311,8 +270,7 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> /* case LINEJOIN_NONE: { if ( on_outside ) { // we are on the outside - Geom::Point der1 = -unitTangentAt(reverse(B[prev_i]),0.); // = unitTangentAt(B[prev_i],1); - Geom::Point point_on_path = B[prev_i].at1() - rot90(der1) * cusp.width; + Geom::Point point_on_path = B[prev_i].at1() - rot90(tang1) * width; pb.lineTo(point_on_path); pb.lineTo(B[i].at0()); } else { @@ -324,13 +282,10 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> if (on_outside) { // we are on the outside, do something complicated to make it look good ;) - Geom::Point der1 = -unitTangentAt(reverse(B[prev_i]),0.); // = unitTangentAt(B[prev_i],1); - Geom::Point der2 = unitTangentAt(B[i],0); - - Geom::D2<Geom::SBasis> newcurve1 = B[prev_i] * Geom::reflection(rot90(der1), B[prev_i].at1()); + Geom::D2<Geom::SBasis> newcurve1 = B[prev_i] * Geom::reflection(rot90(tang1), B[prev_i].at1()); Geom::CubicBezier bzr1 = sbasis_to_cubicbezier( reverse(newcurve1) ); - Geom::D2<Geom::SBasis> newcurve2 = B[i] * Geom::reflection(rot90(der2), B[i].at0()); + Geom::D2<Geom::SBasis> newcurve2 = B[i] * Geom::reflection(rot90(tang2), B[i].at0()); Geom::CubicBezier bzr2 = sbasis_to_cubicbezier( reverse(newcurve2) ); Geom::Crossings cross = crossings(bzr1, bzr2); @@ -339,9 +294,9 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> pb.lineTo(B[i].at0()); } else { // check size of miter - Geom::Point point_on_path = B[prev_i].at1() - rot90(der1) * cusp.width; + Geom::Point point_on_path = B[prev_i].at1() - rot90(tang1) * width; Geom::Coord len = distance(bzr1.pointAt(cross[0].ta), point_on_path); - if (len > fabs(cusp.width) * miter_limit) { + if (len > fabs(width) * miter_limit) { // miter too big: default to bevel pb.lineTo(B[i].at0()); } else { @@ -362,15 +317,13 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> if (on_outside) { // we are on the outside, do something complicated to make it look good ;) - Geom::Point der1 = -unitTangentAt(reverse(B[prev_i]),0.); // = unitTangentAt(B[prev_i],1); - Geom::Point der2 = unitTangentAt(B[i],0); - boost::optional<Geom::Point> p = intersection_point( B[prev_i].at1(), der1, - B[i].at0(), der2 ); + boost::optional<Geom::Point> p = intersection_point( B[prev_i].at1(), tang1, + B[i].at0(), tang2 ); if (p) { // check size of miter - Geom::Point point_on_path = B[prev_i].at1() - rot90(der1) * cusp.width; + Geom::Point point_on_path = B[prev_i].at1() - rot90(tang1) * width; Geom::Coord len = distance(*p, point_on_path); - if (len <= fabs(cusp.width) * miter_limit) { + if (len <= fabs(width) * miter_limit) { // miter OK pb.lineTo(*p); } @@ -384,9 +337,6 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> } case LINEJOIN_SPIRO: { if (on_outside) { - Geom::Point tang1 = -unitTangentAt(reverse(B[prev_i]),0.); // = unitTangentAt(B[prev_i],1); - Geom::Point tang2 = unitTangentAt(B[i],0); - Geom::Point direction = B[i].at0() - B[prev_i].at1(); double tang1_sign = dot(direction,tang1); double tang2_sign = dot(direction,tang2); @@ -419,8 +369,6 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> pb.lineTo(B[i].at0()); break; } - - cusp_i += forward_direction ? 1 : -1; } build_from_sbasis(pb, B[i], tol, false); prev_i = i; @@ -491,14 +439,13 @@ LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in) y = portion(y, rtsmin.at(0), rtsmax.at(0)); } - std::vector<discontinuity_data> cusps = find_discontinuities(der, x, y); LineJoinType jointype = static_cast<LineJoinType>(linejoin_type.get_value()); 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, jointype, miter_limit, true, LPE_CONVERSION_TOLERANCE); - Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, cusps, jointype, miter_limit, false, LPE_CONVERSION_TOLERANCE); + Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, y, jointype, miter_limit, LPE_CONVERSION_TOLERANCE); + Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, reverse(y), jointype, miter_limit, LPE_CONVERSION_TOLERANCE); if (path_in[0].closed()) { fixed_path.close(true); |
