diff options
Diffstat (limited to 'src/live_effects/lpe-powerstroke.cpp')
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 122 |
1 files changed, 30 insertions, 92 deletions
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 5d9d224e8..f90d67d4e 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -27,12 +27,13 @@ #include <2geom/sbasis-geometric.h> #include <2geom/transforms.h> #include <2geom/bezier-utils.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/path-sink.h> #include <2geom/path-intersection.h> #include <2geom/crossing.h> #include <2geom/ellipse.h> +#include <2geom/circle.h> #include <2geom/math-utils.h> #include <math.h> @@ -46,9 +47,9 @@ namespace Geom { static boost::optional<Point> intersection_point( Point const & origin_a, Point const & vector_a, Point const & origin_b, Point const & vector_b) { - Coord denom = cross(vector_b, vector_a); + Coord denom = cross(vector_a, vector_b); if (!are_near(denom,0.)){ - Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; + Coord t = (cross(vector_b, origin_a) + cross(origin_b, vector_b)) / denom; return origin_a + t * vector_a; } return boost::none; @@ -94,71 +95,6 @@ static Ellipse find_ellipse(Point P, Point Q, Point O) } /** - * Refer to: Weisstein, Eric W. "Circle-Circle Intersection." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/Circle-CircleIntersection.html - * - * @return 0 if no intersection - * @return 1 if one circle is contained in the other - * @return 2 if intersections are found (they are written to p0 and p1) - */ -static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, - Point & p0, Point & p1) -{ - Point X0 = circle0.center(); - double r0 = circle0.ray(); - Point X1 = circle1.center(); - double r1 = circle1.ray(); - - /* dx and dy are the vertical and horizontal distances between - * the circle centers. - */ - Point D = X1 - X0; - - /* Determine the straight-line distance between the centers. */ - double d = L2(D); - - /* Check for solvability. */ - if (d > (r0 + r1)) - { - /* no solution. circles do not intersect. */ - return 0; - } - if (d <= fabs(r0 - r1)) - { - /* no solution. one circle is contained in the other */ - return 1; - } - - /* 'point 2' is the point where the line through the circle - * intersection points crosses the line between the circle - * centers. - */ - - /* Determine the distance from point 0 to point 2. */ - double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; - - /* Determine the coordinates of point 2. */ - Point p2 = X0 + D * (a/d); - - /* Determine the distance from point 2 to either of the - * intersection points. - */ - double h = std::sqrt((r0*r0) - (a*a)); - - /* Now determine the offsets of the intersection points from - * point 2. - */ - Point r = (h/d)*rot90(D); - - /* Determine the absolute intersection points. */ - p0 = p2 + r; - p1 = p2 - r; - - return 2; -} - -/** * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). */ @@ -313,7 +249,7 @@ LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) Geom::Path const &path = pathv.front(); Geom::Path::size_type const size = path.size_default(); if (!path.closed()) { - points.push_back( Geom::Point(0.2,width) ); + points.push_back( Geom::Point(0.2,width) ); } points.push_back( Geom::Point(0.5*size,width) ); if (!path.closed()) { @@ -362,7 +298,7 @@ void LPEPowerStroke::doOnRemove(SPLPEItem const* lpeitem) } void -LPEPowerStroke::adjustForNewPath(std::vector<Geom::Path> const & path_in) +LPEPowerStroke::adjustForNewPath(Geom::PathVector const & path_in) { if (!path_in.empty()) { offset_points.recalculate_controlpoints_for_new_pwd2(path_in[0].toPwSb()); @@ -387,6 +323,8 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom:: return pb.peek().front(); } + pb.setStitching(true); + Geom::Point start = B[0].at0(); pb.moveTo(start); build_from_sbasis(pb, B[0], tol, false); @@ -446,7 +384,7 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom:: break; } - pb.arcTo( ellipse.ray(Geom::X), ellipse.ray(Geom::Y), ellipse.rot_angle(), + pb.arcTo( ellipse.ray(Geom::X), ellipse.ray(Geom::Y), ellipse.rotationAngle(), false, width < 0, B[i].at0() ); break; @@ -482,24 +420,24 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom:: // Extrapolate using the curvature at the end of the path segments to join Geom::Circle circle1 = Geom::touching_circle(reverse(B[prev_i]), 0.0); Geom::Circle circle2 = Geom::touching_circle(B[i], 0.0); - Geom::Point points[2]; - int solutions = circle_circle_intersection(circle1, circle2, points[0], points[1]); - if (solutions == 2) { + std::vector<Geom::ShapeIntersection> solutions; + solutions = circle1.intersect(circle2); + if (solutions.size() == 2) { Geom::Point sol(0.,0.); - if ( dot(tang2,points[0]-B[i].at0()) > 0 ) { + if ( dot(tang2, solutions[0].point() - B[i].at0()) > 0 ) { // points[0] is bad, choose points[1] - sol = points[1]; - } else if ( dot(tang2,points[1]-B[i].at0()) > 0 ) { // points[0] could be good, now check points[1] + sol = solutions[1].point(); + } else if ( dot(tang2, solutions[1].point() - B[i].at0()) > 0 ) { // points[0] could be good, now check points[1] // points[1] is bad, choose points[0] - sol = points[0]; + sol = solutions[0].point(); } else { // both points are good, choose nearest - sol = ( distanceSq(B[i].at0(), points[0]) < distanceSq(B[i].at0(), points[1]) ) ? - points[0] : points[1]; + sol = ( distanceSq(B[i].at0(), solutions[0].point()) < distanceSq(B[i].at0(), solutions[1].point()) ) ? + solutions[0].point() : solutions[1].point(); } - Geom::EllipticalArc *arc0 = circle1.arc(B[prev_i].at1(), 0.5*(B[prev_i].at1()+sol), sol, true); - Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+B[i].at0()), B[i].at0(), true); + Geom::EllipticalArc *arc0 = circle1.arc(B[prev_i].at1(), 0.5*(B[prev_i].at1()+sol), sol); + Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+B[i].at0()), B[i].at0()); if (arc0) { build_from_sbasis(pb,arc0->toSBasis(), tol, false); @@ -574,7 +512,7 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom:: Geom::Path spiro; Spiro::spiro_run(controlpoints, 4, spiro); - pb.append(spiro.portion(1,spiro.size_open()-1), Geom::Path::STITCH_DISCONTINUOUS); + pb.append(spiro.portion(1, spiro.size_open() - 1)); break; } case LINEJOIN_BEVEL: @@ -593,15 +531,15 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom:: if (cross.size() != 1) { // empty crossing or too many crossings: default to bevel pb.lineTo(B[i].at0()); - pb.append(bzr2, Geom::Path::STITCH_DISCONTINUOUS); + pb.append(bzr2); } else { // :-) quick hack: for (unsigned i=0; i < bzr1.size_open(); ++i) { pb.backspace(); } - pb.append( bzr1.portion(0, cross[0].ta), Geom::Path::STITCH_DISCONTINUOUS ); - pb.append( bzr2.portion(cross[0].tb, bzr2.size_open()), Geom::Path::STITCH_DISCONTINUOUS ); + pb.append( bzr1.portion(0, cross[0].ta) ); + pb.append( bzr2.portion(cross[0].tb, bzr2.size_open()) ); } } } else { @@ -615,12 +553,12 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom:: } -std::vector<Geom::Path> -LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in) +Geom::PathVector +LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) { using namespace Geom; - std::vector<Geom::Path> path_out; + Geom::PathVector path_out; if (path_in.empty()) { return path_out; } @@ -737,12 +675,12 @@ LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in) default: { double radius1 = 0.5 * distance(pwd2_out.lastValue(), mirrorpath.firstValue()); - fixed_path.appendNew<SVGEllipticalArc>( radius1, radius1, M_PI/2., false, y.lastValue() < 0, mirrorpath.firstValue() ); + fixed_path.appendNew<EllipticalArc>( radius1, radius1, M_PI/2., false, y.lastValue() < 0, mirrorpath.firstValue() ); break; } } - fixed_path.append(fixed_mirrorpath, Geom::Path::STITCH_DISCONTINUOUS); + fixed_path.append(fixed_mirrorpath); switch (start_linecap) { case LINECAP_ZERO_WIDTH: @@ -775,7 +713,7 @@ LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in) default: { double radius2 = 0.5 * distance(pwd2_out.firstValue(), mirrorpath.lastValue()); - fixed_path.appendNew<SVGEllipticalArc>( radius2, radius2, M_PI/2., false, y.firstValue() < 0, pwd2_out.firstValue() ); + fixed_path.appendNew<EllipticalArc>( radius2, radius2, M_PI/2., false, y.firstValue() < 0, pwd2_out.firstValue() ); break; } } |
