From d20b73d611b6de99e0e0697ee47a760de437ee97 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 2 Apr 2014 17:18:40 -0400 Subject: Clean up code (bzr r13090.1.42) --- src/live_effects/pathoutlineprovider.cpp | 521 +++++++++++++++---------------- 1 file changed, 258 insertions(+), 263 deletions(-) mode change 100755 => 100644 src/live_effects/pathoutlineprovider.cpp (limited to 'src/live_effects/pathoutlineprovider.cpp') diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp old mode 100755 new mode 100644 index 6a47285a0..ad39a7416 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -9,133 +9,128 @@ #include <2geom/path-sink.h> #include -namespace Geom +namespace Geom { +/** +* 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). +*/ +static Circle touching_circle( D2 const &curve, double t, double tol=0.01 ) { - /** - * 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). - */ - static Circle touching_circle( D2 const &curve, double t, double tol=0.01 ) - { - D2 dM=derivative(curve); - if ( are_near(L2sq(dM(t)),0.) ) { - dM=derivative(dM); - } - if ( are_near(L2sq(dM(t)),0.) ) { // try second time - dM=derivative(dM); - } - Piecewise > unitv = unitVector(dM,tol); - Piecewise dMlength = dot(Piecewise >(dM),unitv); - Piecewise k = cross(derivative(unitv),unitv); - k = divide(k,dMlength,tol,3); - double curv = k(t); // note that this value is signed - - Geom::Point normal = unitTangentAt(curve, t).cw(); - double radius = 1/curv; - Geom::Point center = curve(t) + radius*normal; - return Geom::Circle(center, fabs(radius)); - } - - static std::vector split_at_cusps(const Geom::Path& in) - { - Geom::PathVector out = Geom::PathVector(); - Geom::Path temp = Geom::Path(); - - for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) - { - temp = Geom::Path(); - temp.append(in[path_descr]); - out.push_back(temp); - } - - return out; - } - - static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) - { - std::vector temp; - sbasis_to_bezier(temp, sbasis_in, 4); - return Geom::CubicBezier( temp ); - } - - static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, - Geom::Point const & origin_b, Geom::Point const & vector_b) - { - Geom::Coord denom = cross(vector_b, vector_a); - if (!Geom::are_near(denom,0.)){ - Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; - return origin_a + t * vector_a; - } - return boost::none; - } + D2 dM=derivative(curve); + if ( are_near(L2sq(dM(t)),0.) ) { + dM=derivative(dM); + } + if ( are_near(L2sq(dM(t)),0.) ) { // try second time + dM=derivative(dM); + } + Piecewise > unitv = unitVector(dM,tol); + Piecewise dMlength = dot(Piecewise >(dM),unitv); + Piecewise k = cross(derivative(unitv),unitv); + k = divide(k,dMlength,tol,3); + double curv = k(t); // note that this value is signed + + Geom::Point normal = unitTangentAt(curve, t).cw(); + double radius = 1/curv; + Geom::Point center = curve(t) + radius*normal; + return Geom::Circle(center, fabs(radius)); } -namespace Outline +static std::vector split_at_cusps(const Geom::Path& in) { + Geom::PathVector out = Geom::PathVector(); + Geom::Path temp = Geom::Path(); + + for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) { + temp = Geom::Path(); + temp.append(in[path_descr]); + out.push_back(temp); + } + + return out; +} + +static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) +{ + std::vector temp; + sbasis_to_bezier(temp, sbasis_in, 4); + return Geom::CubicBezier( temp ); +} + +static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, + Geom::Point const & origin_b, Geom::Point const & vector_b) +{ + Geom::Coord denom = cross(vector_b, vector_a); + if (!Geom::are_near(denom,0.)) { + Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; + return origin_a + t * vector_a; + } + return boost::none; +} +} + +namespace Outline { typedef Geom::D2 D2SB; typedef Geom::Piecewise PWD2; @@ -160,72 +155,70 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) unsigned order = bezierOrder(&cbc1); Geom::Point start_point; - Geom::Point cross_point = cbc1.finalPoint(); - Geom::Point end_point; - - //assert(cbc1.finalPoint() == cbc2.initialPoint()); - //short circuiting? - if (cbc1.finalPoint() != cbc2.initialPoint()) { - printf("There was an issue when asserting that one curve's end is the start of the other. Line %d, File %s\n" - "By default we are going to say that this is an inside join, so we cannot make a line join for it.\n", __LINE__, __FILE__); - return false; + Geom::Point cross_point = cbc1.finalPoint(); + Geom::Point end_point; + + //assert(cbc1.finalPoint() == cbc2.initialPoint()); + //short circuiting? + if (cbc1.finalPoint() != cbc2.initialPoint()) { + printf("There was an issue when asserting that one curve's end is the start of the other. Line %d, File %s\n" + "By default we are going to say that this is an inside join, so we cannot make a line join for it.\n", __LINE__, __FILE__); + return false; + } + switch (order) { + case 3: + start_point = (static_cast(&cbc1))->operator[] (2); + //major league b***f***ing + if (are_near(start_point, cross_point, 0.0000001)) { + start_point = (static_cast(&cbc1))->operator[] (1); } - switch (order) - { - case 3: - start_point = (static_cast(&cbc1))->operator[] (2); - //major league b***f***ing - if (are_near(start_point, cross_point, 0.0000001)) { - start_point = (static_cast(&cbc1))->operator[] (1); - } - break; - case 2: - //this never happens - start_point = (static_cast(&cbc1))->operator[] (1); - break; - case 1: - default: - start_point = cbc1.initialPoint(); - } - - order = Outline::bezierOrder(&cbc2); - - switch (order) - { - case 3: - end_point = (static_cast(&cbc2))->operator[] (1); - if (are_near(end_point, cross_point, 0.0000001)) { - end_point = (static_cast(&cbc2))->operator[] (2); - } - break; - case 2: - end_point = (static_cast(&cbc2))->operator[] (1); - break; - case 1: - default: - end_point = cbc2.finalPoint(); - } - //got our three points, now let's see what their clockwise angle is - - //Much credit to Wikipedia for the following ( http://en.wikipedia.org/wiki/Graham_scan ) - /******************************************************************** + break; + case 2: + //this never happens + start_point = (static_cast(&cbc1))->operator[] (1); + break; + case 1: + default: + start_point = cbc1.initialPoint(); + } + + order = Outline::bezierOrder(&cbc2); + + switch (order) { + case 3: + end_point = (static_cast(&cbc2))->operator[] (1); + if (are_near(end_point, cross_point, 0.0000001)) { + end_point = (static_cast(&cbc2))->operator[] (2); + } + break; + case 2: + end_point = (static_cast(&cbc2))->operator[] (1); + break; + case 1: + default: + end_point = cbc2.finalPoint(); + } + //got our three points, now let's see what their clockwise angle is + + //Much credit to Wikipedia for the following ( http://en.wikipedia.org/wiki/Graham_scan ) + /******************************************************************** # Three points are a counter-clockwise turn if ccw > 0, clockwise if # ccw < 0, and collinear if ccw = 0 because ccw is a determinant that # gives the signed area of the triangle formed by p1, p2 and p3. function ccw(p1, p2, p3): - return (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x) + return (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x) *********************************************************************/ - + double ccw = ( (cross_point.x() - start_point.x()) * (end_point.y() - start_point.y()) ) - ( (cross_point.y() - start_point.y()) * (end_point.x() - start_point.x()) ); if (ccw > 0) return true; return false; } -void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, +void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit, double line_width, bool outside = false) { - bool lineProblem = (dynamic_cast *>(cbc1)) || (dynamic_cast *>(cbc2)); + bool lineProblem = (dynamic_cast *>(cbc1)) || (dynamic_cast *>(cbc2)); if ( outside && !lineProblem ) { Geom::Path pth; pth.append(*cbc1); @@ -271,9 +264,8 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } } else { boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) - { + cbc2->initialPoint(), tang2); + if (p) { //check size of miter Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; Geom::Coord len = distance(*p, point_on_path); @@ -284,19 +276,18 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } path_builder.appendNew (endPt); } - } - if ( outside && lineProblem ) { - Geom::Path pth; + } + if ( outside && lineProblem ) { + Geom::Path pth; pth.append(*cbc1); - Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(pth.toPwSb()[0]), 0.); + Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(pth.toPwSb()[0]), 0.); pth = Geom::Path(); - pth.append( *cbc2 ); - Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); - - boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) - { + pth.append( *cbc2 ); + Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); + + boost::optional p = intersection_point (cbc1->finalPoint(), tang1, + cbc2->initialPoint(), tang2); + if (p) { //check size of miter Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; Geom::Coord len = distance(*p, point_on_path); @@ -306,13 +297,13 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } } path_builder.appendNew (endPt); - } - if ( !outside ) { - path_builder.appendNew (endPt); - } + } + if ( !outside ) { + path_builder.appendNew (endPt); + } } -void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, +void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit, double line_width, bool outside = false) { //the most important work for the reflected join is done here @@ -320,7 +311,7 @@ void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cb //determine where we are in the path. If we're on the inside, ignore //and just lineTo. On the outside, we'll do a little reflection magic :) Geom::Crossings cross; - + if (outside) { Geom::Path pth; pth.append(*cbc1); @@ -347,9 +338,8 @@ void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cb if ( cross.empty() ) { //curves didn't cross; default to miter boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) - { + cbc2->initialPoint(), tang2); + if (p) { //check size of miter Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; Geom::Coord len = distance(*p, point_on_path); @@ -388,27 +378,26 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double // NOTE: it is important to notice the distinction between a Geom::Path and a livarot Path here! // if you do not see "Geom::" there is a different function set! Geom::PathVector pv = split_at_cusps(path_in); - + Path to_outline; Path outlined_result; - + Geom::Path path_builder = Geom::Path(); //the path to store the result in Geom::PathVector * path_vec; //needed because livarot returns a goddamn pointer - + const unsigned k = path_in.size(); - - for (unsigned u = 0; u < k; u+=2) - { + + for (unsigned u = 0; u < k; u+=2) { to_outline = Path(); outlined_result = Path(); - + to_outline.LoadPath(pv[u], Geom::Affine(), false, false); to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); //now a curve has been outside outlined and loaded into outlined_result - + //get the Geom::Path path_vec = outlined_result.MakePathVector(); - + //thing to do on the first run through if (u == 0) { //I could use the pv->operator[] (0) notation but that looks terrible @@ -417,58 +406,64 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double //get the curves ready for the operation Geom::Curve * cbc1 = path_builder[path_builder.size() - 1].duplicate(); Geom::Curve * cbc2 = (*path_vec)[0] [0].duplicate(); - + //do the reflection/extrapolation: - if (extrapolate) { extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); } - else { reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); } + if (extrapolate) { + extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); + } else { + reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); + } } - + path_builder.append( (*path_vec)[0] ); - + //outline the next segment, but don't store it yet if (path_vec) delete path_vec; - + if (u < k - 1) { outlined_result = Path(); to_outline = Path(); - + to_outline.LoadPath(pv[u+1], Geom::Affine(), false, false); to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); - + path_vec = outlined_result.MakePathVector(); - + //get the curves ready for the operation Geom::Curve * cbc1 = path_builder[path_builder.size() - 1].duplicate(); Geom::Curve * cbc2 = (*path_vec)[0] [0].duplicate(); - + //do the reflection/extrapolation: - if (extrapolate) { extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); } - else { reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); } - + if (extrapolate) { + extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); + } else { + reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); + } + //Now we can store it. path_builder.append( (*path_vec)[0] ); - + if (cbc1) delete cbc1; if (cbc2) delete cbc2; if (path_vec) delete path_vec; } } - + return path_builder; } -Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, +Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtType butt, double miter_lim, bool extrapolate) { Geom::PathVector path_out; - + unsigned pv_size = path_in.size(); for (unsigned i = 0; i < pv_size; i++) { - + if (path_in[i].size() > 1) { //since you've made it this far, hopefully all this is obvious :P Geom::Path with_direction; @@ -484,8 +479,8 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, newPath = Geom::path_from_piecewise(pwd2, 0.01)[0]; //fuk this with_direction = Outline::doAdvHalfOutline( newPath, -line_width, miter_lim, extrapolate ); - against_direction = Outline::doAdvHalfOutline( newPath.reverse(), -line_width, miter_lim, extrapolate ); - + against_direction = Outline::doAdvHalfOutline( newPath.reverse(), -line_width, miter_lim, extrapolate ); + /*if (dynamic_cast *>(&newPath[newPath.size()])) { //delete the 'Z' newPath.erase_last(); @@ -497,54 +492,54 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, newPath.erase_last(); newPath.append(path_in[i][path_in[i].size() - 1]); newPath.appendNew(newPath.initialPoint()); - newPath.erase_last(); + newPath.erase_last(); }*/ } Geom::PathBuilder pb; - + //add in the...do I really need to say this? pb.moveTo(with_direction.initialPoint()); pb.append(with_direction); - + //add in our line caps if (!path_in[i].closed()) { switch (butt) { - case butt_straight: - pb.lineTo(against_direction.initialPoint()); - break; - case butt_round: - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, against_direction.initialPoint() ); - break; - case butt_pointy: - //I have ZERO idea what to do here. - pb.lineTo(against_direction.initialPoint()); - break; - case butt_square: - pb.lineTo(against_direction.initialPoint()); - break; + case butt_straight: + pb.lineTo(against_direction.initialPoint()); + break; + case butt_round: + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, against_direction.initialPoint() ); + break; + case butt_pointy: + //I have ZERO idea what to do here. + pb.lineTo(against_direction.initialPoint()); + break; + case butt_square: + pb.lineTo(against_direction.initialPoint()); + break; } } else { pb.moveTo(against_direction.initialPoint()); } - + pb.append(against_direction); - + //cap (if necessary) if (!path_in[i].closed()) { switch (butt) { - case butt_straight: - pb.lineTo(with_direction.initialPoint()); - break; - case butt_round: - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, with_direction.initialPoint() ); - break; - case butt_pointy: - //I have ZERO idea what to do here. - pb.lineTo(with_direction.initialPoint()); - break; - case butt_square: - pb.lineTo(with_direction.initialPoint()); - break; + case butt_straight: + pb.lineTo(with_direction.initialPoint()); + break; + case butt_round: + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, with_direction.initialPoint() ); + break; + case butt_pointy: + //I have ZERO idea what to do here. + pb.lineTo(with_direction.initialPoint()); + break; + case butt_square: + pb.lineTo(with_direction.initialPoint()); + break; } } pb.flush(); @@ -554,7 +549,7 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, } else { Path p = Path(); Path outlinepath = Path(); - + p.LoadPath(path_in[i], Geom::Affine(), false, false); p.Outline(&outlinepath, line_width / 2, static_cast(join), butt, miter_lim); Geom::PathVector *pv_p = outlinepath.MakePathVector(); -- cgit v1.2.3