From c883d7627a479c8c5b6a9f77b9841fa5631572ad Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Mon, 27 Apr 2015 19:39:29 -0400 Subject: 2Geom sync - initial commit (bzr r14059.2.1) --- src/helper/geom-pathstroke.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index eb0c432c6..df5e5a82b 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -34,7 +34,7 @@ int circle_circle_intersection(Point X0, double r0, Point X1, double r1, Point & static int circle_line_intersection(Circle C0, Point X0, Point X1, Point &p0, Point &p1) { /* equation of a circle: (x - h)^2 + (y - k)^2 = r^2 */ - Coord r = C0.ray(); + Coord r = C0.radius(); Coord h = C0.center()[X]; Coord k = C0.center()[Y]; @@ -252,8 +252,8 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter if (!inc_ls && !out_ls) { // Two circles - solutions = Geom::circle_circle_intersection(circle1.center(), circle1.ray(), - circle2.center(), circle2.ray(), + solutions = Geom::circle_circle_intersection(circle1.center(), circle1.radius(), + circle2.center(), circle2.radius(), points[0], points[1]); if (solutions == 2) { sol = pick_solution(points, tang2, endPt); @@ -486,7 +486,7 @@ void get_cubic_data(Geom::CubicBezier const& bez, double time, double& len, doub if (Geom::are_near(l, 0)) { return; // this isn't a segment... } - rad = 1e8; + rad = 1e8; } else { rad = -l * (Geom::dot(der2, der2) / Geom::cross(der3, der2)); } @@ -538,7 +538,7 @@ void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, dou // reached maximum recursive depth // don't bother with any more correction if (levels == 0) { - p.append(c, Geom::Path::STITCH_DISCONTINUOUS); + p.append(c); return; } @@ -570,7 +570,7 @@ void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double wi // cheat // it's faster // seriously - std::vector points = bez.points(); + std::vector points = bez.controlPoints(); Geom::Point b1 = points[0] + (2./3) * (points[1] - points[0]); Geom::Point b2 = b1 + (1./3) * (points[2] - points[0]); Geom::CubicBezier cub = Geom::CubicBezier(points[0], b1, b2, points[2]); @@ -658,7 +658,7 @@ Geom::PathVector outline(Geom::Path const& input, double width, double miter, Li Geom::PathBuilder res; Geom::Path with_dir = half_outline(input, width/2., miter, join); - Geom::Path against_dir = half_outline(input.reverse(), width/2., miter, join); + Geom::Path against_dir = half_outline(input.reversed(), width/2., miter, join); res.moveTo(with_dir[0].initialPoint()); res.append(with_dir); @@ -706,6 +706,9 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin Geom::Point start = input.initialPoint() + tang1 * width; Geom::Path temp; + res.setStitching(true); + temp.setStitching(true); + res.start(start); // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well -- cgit v1.2.3 From cfa7054c950050095e596edd18fedad53e7ed636 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 28 Apr 2015 19:02:19 -0400 Subject: Fix calls to Geom::cross() - sign change. (bzr r14059.2.2) --- src/helper/geom-pathstroke.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index df5e5a82b..97e3c6806 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -90,9 +90,9 @@ static int circle_line_intersection(Circle C0, Point X0, Point X1, Point &p0, Po static Point intersection_point(Point origin_a, Point vector_a, Point origin_b, Point 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 + vector_a*t; } return Point(infinity(), infinity()); @@ -322,7 +322,7 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter Geom::Ray end_ray(center, sol); Geom::Line limit_line(center, 0); // Angle set below - if (Geom::cross(start_ray.versor(), end_ray.versor()) > 0) { + if (Geom::cross(start_ray.versor(), end_ray.versor()) < 0) { limit_line.setAngle(start_ray.angle() - limit_angle); } else { limit_line.setAngle(start_ray.angle() + limit_angle); @@ -412,7 +412,7 @@ bool decide(Geom::Curve const& incoming, Geom::Curve const& outgoing) { Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); Geom::Point tang2 = outgoing.unitTangentAt(0.); - return (Geom::cross(tang1, tang2) < 0); + return (Geom::cross(tang1, tang2) > 0); } void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, bool on_outside, double miter, Inkscape::LineJoinType join) @@ -488,10 +488,10 @@ void get_cubic_data(Geom::CubicBezier const& bez, double time, double& len, doub } rad = 1e8; } else { - rad = -l * (Geom::dot(der2, der2) / Geom::cross(der3, der2)); + rad = -l * (Geom::dot(der2, der2) / Geom::cross(der2, der3)); } } else { - rad = -l * (Geom::dot(der1, der1) / Geom::cross(der2, der1)); + rad = -l * (Geom::dot(der1, der1) / Geom::cross(der1, der2)); } len = l; } -- cgit v1.2.3 From 6839dc4380abd4e892cf65600ffe4c63ed91eb67 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 28 Apr 2015 19:44:34 -0400 Subject: fix tangent sign problems in path outline code (bzr r14068) --- src/helper/geom-pathstroke.cpp | 159 ++++++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 65 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index eb0c432c6..6b35bb290 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -127,87 +127,104 @@ static Circle touching_circle( D2 const &curve, double t, double tol=0.0 namespace { -// Join functions may: -// - inspect any curve of the current path -// - append any type of curve to the current path -// - inspect the outgoing path -// -// Join functions must: -// - append the outgoing curve -// OR -// - end at outgoing.finalPoint - -typedef void join_func(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width); - -void bevel_join(Geom::Path& res, Geom::Curve const& outgoing, double /*miter*/, double /*width*/) +// Internal data structure + +struct join_data +{ + join_data(Geom::Path &_res, Geom::Path const&_outgoing, Geom::Point _in_tang, Geom::Point _out_tang, double _miter, double _width) + : res(_res), outgoing(_outgoing), in_tang(_in_tang) + , out_tang(_out_tang), miter(_miter), width(_width) {} + + // I/O + Geom::Path &res; + Geom::Path const& outgoing; + + // input tangents + Geom::Point in_tang; + Geom::Point out_tang; + + // line parameters + double miter; + double width; +}; + +// Join functions must append the outgoing path + +typedef void join_func(join_data jd); + +void bevel_join(join_data jd) { - res.appendNew(outgoing.initialPoint()); - res.append(outgoing); + jd.res.appendNew(jd.outgoing.initialPoint()); + jd.res.append(jd.outgoing); } -void round_join(Geom::Path& res, Geom::Curve const& outgoing, double /*miter*/, double width) +void round_join(join_data jd) { - res.appendNew(width, width, 0, false, width <= 0, outgoing.initialPoint()); - res.append(outgoing); + jd.res.appendNew(jd.width, jd.width, 0, false, jd.width <= 0, jd.outgoing.initialPoint()); + jd.res.append(jd.outgoing); } -void miter_join_internal(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width, bool clip) +void miter_join_internal(join_data jd, bool clip) { - Geom::Curve const& incoming = res.back(); - Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); - Geom::Point tang2 = outgoing.unitTangentAt(0); - Geom::Point p = Geom::intersection_point(incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2); + using namespace Geom; + + Curve const& incoming = jd.res.back(); + Curve const& outgoing = jd.outgoing.front(); + Path &res = jd.res; + double width = jd.width, miter = jd.miter; + + Point tang1 = jd.in_tang; + Point tang2 = jd.out_tang; + Point p = intersection_point(incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2); bool satisfied = false; bool inc_ls = res.back_open().degreesOfFreedom() <= 4; if (p.isFinite()) { // check size of miter - Geom::Point point_on_path = incoming.finalPoint() + Geom::rot90(tang1)*width; - satisfied = Geom::distance(p, point_on_path) <= miter * 2.0 * width; + Point point_on_path = incoming.finalPoint() + rot90(tang1)*width; + satisfied = distance(p, point_on_path) <= miter * 2.0 * width; if (satisfied) { // miter OK, check to see if we can do a relocation if (inc_ls) { res.setFinal(p); } else { - res.appendNew(p); + res.appendNew(p); } } else if (clip) { // miter needs clipping, find two points - Geom::Point bisector_versor = Geom::Line(point_on_path, p).versor(); - Geom::Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor; + Point bisector_versor = Line(point_on_path, p).versor(); + Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor; - Geom::Point p1 = Geom::intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw()); - Geom::Point p2 = Geom::intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw()); + Point p1 = intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw()); + Point p2 = intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw()); if (inc_ls) { res.setFinal(p1); } else { - res.appendNew(p1); + res.appendNew(p1); } - res.appendNew(p2); + res.appendNew(p2); } } - res.appendNew(outgoing.initialPoint()); + res.appendNew(outgoing.initialPoint()); // check if we can do another relocation bool out_ls = outgoing.degreesOfFreedom() <= 4; - if ( (satisfied || clip) && out_ls) { + if ((satisfied || clip) && out_ls) { res.setFinal(outgoing.finalPoint()); } else { res.append(outgoing); } -} -void miter_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) { - miter_join_internal( res, outgoing, miter, width, false ); + // either way, add the rest of the path + res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } -void miter_clip_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) { - miter_join_internal( res, outgoing, miter, width, true ); -} +void miter_join(join_data jd) { miter_join_internal(jd, false); } +void miter_clip_join(join_data jd) { miter_join_internal(jd, true); } Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point endPt) { @@ -225,15 +242,18 @@ Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point return sol; } -void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) +void extrapolate_join(join_data jd) { using namespace Geom; + Geom::Path &res = jd.res; Geom::Curve const& incoming = res.back(); + Geom::Curve const& outgoing = jd.outgoing.front(); Geom::Point startPt = incoming.finalPoint(); Geom::Point endPt = outgoing.initialPoint(); - Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); - Geom::Point tang2 = outgoing.unitTangentAt(0); + Geom::Point tang1 = jd.in_tang; + Geom::Point tang2 = jd.out_tang; + double width = jd.width, miter = jd.miter; Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.); Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0); @@ -280,7 +300,7 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter if (solutions != 2) // no solutions available, fall back to miter - return miter_clip_join(res, outgoing, miter, width); + return miter_clip_join(jd); // We have a solution, thus sol is defined. p1 = sol; @@ -381,14 +401,19 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter // Straight line segment: res.appendNew(outgoing.finalPoint()); } - + + // add the rest of the path + res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); + delete arc1; delete arc2; } -void join_inside(Geom::Path& res, Geom::Curve const& outgoing) +void join_inside(join_data jd) { + Geom::Path &res = jd.res; Geom::Curve const& incoming = res.back_open(); + Geom::Curve const& outgoing = jd.outgoing.front(); Geom::Crossings cross = Geom::crossings(incoming, outgoing); if (!cross.empty()) { @@ -406,28 +431,35 @@ void join_inside(Geom::Path& res, Geom::Curve const& outgoing) res.appendNew(outgoing.initialPoint()); res.append(outgoing); } + + // add the rest of the path + res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } -bool decide(Geom::Curve const& incoming, Geom::Curve const& outgoing) +void tangents(Geom::Point* tang, Geom::Curve const& incoming, Geom::Curve const& outgoing) { Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); Geom::Point tang2 = outgoing.unitTangentAt(0.); - return (Geom::cross(tang1, tang2) < 0); + tang[0] = tang1, tang[1] = tang2; } -void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, bool on_outside, double miter, Inkscape::LineJoinType join) +void outline_helper(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join) { - if (res.size() == 0 || to_add.size() == 0) + if (res.size() == 0 || temp.size() == 0) return; - Geom::Curve const& outgoing = to_add[0]; + Geom::Curve const& outgoing = temp.front(); if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { // if the points are /that/ close, just ignore this one - res.setFinal(outgoing.initialPoint()); - res.append(outgoing); + res.setFinal(temp.initialPoint()); + res.append(temp); return; } + join_data jd(res, temp, in_tang, out_tang, miter, width); + + bool on_outside = (Geom::cross(in_tang, out_tang) < 0); + if (on_outside) { join_func *jf; switch (join) { @@ -446,9 +478,9 @@ void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, boo default: jf = &miter_join; } - jf(res, outgoing, miter, width); + jf(jd); } else { - join_inside(res, outgoing); + join_inside(jd); } } @@ -705,6 +737,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin Geom::Point tang1 = input[0].unitTangentAt(0); Geom::Point start = input.initialPoint() + tang1 * width; Geom::Path temp; + Geom::Point tang[2]; res.start(start); @@ -720,20 +753,16 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin if (u == 0) { res.append(temp); } else { - bool on_outside = decide(input[u-1], input[u]); - outline_helper(res, temp, width, on_outside, miter, join); - if (temp.size() > 0) - res.insert(res.end(), ++temp.begin(), temp.end()); + tangents(tang, input[u-1], input[u]); + outline_helper(res, temp, tang[0], tang[1], width, miter, join); } // odd number of paths if (u < k - 1) { temp = Geom::Path(); offset_curve(temp, &input[u+1], width); - bool on_outside = decide(input[u], input[u+1]); - outline_helper(res, temp, width, on_outside, miter, join); - if (temp.size() > 0) - res.insert(res.end(), ++temp.begin(), temp.end()); + tangents(tang, input[u], input[u+1]); + outline_helper(res, temp, tang[0], tang[1], width, miter, join); } } @@ -744,8 +773,8 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin temp.append(c1); Geom::Path temp2; temp2.append(c2); - bool on_outside = decide(input.back(), input.front()); - outline_helper(temp, temp2, width, on_outside, miter, join); + tangents(tang, input.back(), input.front()); + outline_helper(temp, temp2, tang[0], tang[1], width, miter, join); res.erase(res.begin()); res.erase_last(); // -- cgit v1.2.3 From 5a3f7c27245b1a1858036210efbde031d199ebdc Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 28 Apr 2015 21:10:13 -0400 Subject: Catch more intersections (can still be improved somewhat I think) (bzr r14069) --- src/helper/geom-pathstroke.cpp | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index 6b35bb290..a33fb005b 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -412,31 +412,27 @@ void extrapolate_join(join_data jd) void join_inside(join_data jd) { Geom::Path &res = jd.res; - Geom::Curve const& incoming = res.back_open(); - Geom::Curve const& outgoing = jd.outgoing.front(); - Geom::Crossings cross = Geom::crossings(incoming, outgoing); - - if (!cross.empty()) { - // yeah if we could avoid allocing that'd be great - Geom::Curve *d1 = incoming.portion(0., cross[0].ta); - res.erase_last(); - res.append(*d1); - delete d1; - - Geom::Curve *d2 = outgoing.portion(cross[0].tb, 1.); - res.setFinal(d2->initialPoint()); - res.append(*d2); - delete d2; + Geom::Path const& temp = jd.outgoing; + Geom::Crossings cross = Geom::crossings(res, temp); + + if (cross.size() == 1) { + Geom::Path d1 = res.portion(0., cross[0].ta); + Geom::Path d2 = temp.portion(cross[0].tb, temp.size()); + + // Watch for bugs in 2geom crossing regarding severe inflection points + res.clear(); + res.append(d1); + res.setFinal(d2.initialPoint()); + res.append(d2); } else { - res.appendNew(outgoing.initialPoint()); - res.append(outgoing); + res.appendNew(temp.initialPoint()); + res.append(temp); + // add the rest of the path + res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } - - // add the rest of the path - res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } -void tangents(Geom::Point* tang, Geom::Curve const& incoming, Geom::Curve const& outgoing) +void tangents(Geom::Point tang[2], Geom::Curve const& incoming, Geom::Curve const& outgoing) { Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); Geom::Point tang2 = outgoing.unitTangentAt(0.); -- cgit v1.2.3 From 658291159764636339acd95389827eb8ae159ecb Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 28 Apr 2015 21:25:47 -0400 Subject: Increase precision (long thin paths had a ton of width variance), fix logic error (bzr r14070) --- src/helper/geom-pathstroke.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index a33fb005b..292ba3044 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -427,8 +427,6 @@ void join_inside(join_data jd) } else { res.appendNew(temp.initialPoint()); res.append(temp); - // add the rest of the path - res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } } @@ -607,7 +605,7 @@ void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double wi void offset_curve(Geom::Path& res, Geom::Curve const* current, double width) { - double const tolerance = 0.005; + double const tolerance = 0.0025; size_t levels = 8; if (current->isDegenerate()) return; // don't do anything -- cgit v1.2.3 From f4c56b0f307b4f0f2ab499e7f10cf2a9644688c4 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 29 Apr 2015 16:23:05 -0400 Subject: Better solution picking (bzr r14073) --- src/helper/geom-pathstroke.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index 292ba3044..1df17acf5 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -415,9 +415,28 @@ void join_inside(join_data jd) Geom::Path const& temp = jd.outgoing; Geom::Crossings cross = Geom::crossings(res, temp); - if (cross.size() == 1) { - Geom::Path d1 = res.portion(0., cross[0].ta); - Geom::Path d2 = temp.portion(cross[0].tb, temp.size()); + int solution = -1; // lol, really hope there aren't more than INT_MAX crossings + if (cross.size() == 1) solution = 0; + else if (cross.size() > 1) { + // I am not sure how well this will work -- we pick the join node closest + // to the cross point of the paths + Geom::Point original = res.finalPoint()+Geom::rot90(jd.in_tang)*jd.width; + Geom::Coord trial = Geom::L2(res.pointAt(cross[0].ta)-original); + solution = 0; + for (size_t i = 1; i < cross.size(); ++i) { + //printf("Trying %d\n", i); + Geom::Coord test = Geom::L2(res.pointAt(cross[i].ta)-original); + if (test < trial) { + trial = test; + solution = i; + //printf("Found improved solution: %f\n", trial); + } + } + } + + if (solution != -1) { + Geom::Path d1 = res.portion(0., cross[solution].ta); + Geom::Path d2 = temp.portion(cross[solution].tb, temp.size()); // Watch for bugs in 2geom crossing regarding severe inflection points res.clear(); -- cgit v1.2.3 From 25fa09178b7d0d0befa708e93ea5316ef381caa0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 22 May 2015 10:23:27 +0200 Subject: Update to 2Geom revision 2396 (bzr r14059.2.16) --- src/helper/geom-pathstroke.cpp | 130 +++++++++-------------------------------- 1 file changed, 28 insertions(+), 102 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index a152af62c..888e55180 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -10,83 +10,14 @@ #include <2geom/path-sink.h> #include <2geom/point.h> #include <2geom/bezier-curve.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/sbasis-to-bezier.h> // cubicbezierpath_from_sbasis #include <2geom/path-intersection.h> +#include <2geom/circle.h> #include "helper/geom-pathstroke.h" namespace Geom { -// 2geom/circle-circle.cpp, no header -int circle_circle_intersection(Point X0, double r0, Point X1, double r1, Point &p0, Point &p1); - -/** - * Determine the intersection points between a circle C0 and a line defined - * by two points, X0 and X1. - * - * Which intersection point is assigned to p0 or p1 is unspecified, and callers - * should not depend on any particular intersection always being assigned to p0. - * - * Returns: - * If the line and circle do not cross, 0 is returned. - * If solution(s) exist, 2 is returned, and the results are written to p0 and p1. - */ -static int circle_line_intersection(Circle C0, Point X0, Point X1, Point &p0, Point &p1) -{ - /* equation of a circle: (x - h)^2 + (y - k)^2 = r^2 */ - Coord r = C0.radius(); - Coord h = C0.center()[X]; - Coord k = C0.center()[Y]; - - Coord x0, y0; - Coord x1, y1; - - if (are_near(X1[X], X0[X])) { - /* slope is undefined (vertical line) */ - Coord c = X0[X]; - Coord det = r*r - (c-h)*(c-h); - - /* no intersection */ - if (det < 0) - return 0; - - /* solve for y */ - y0 = k + std::sqrt(det); - y1 = k - std::sqrt(det); - - // x == c (always) - x0 = c; - x1 = c; - } else { - /* equation of a line: y = mx + b */ - Coord m = (X1[Y] - X0[Y]) / (X1[X] - X0[X]); - Coord b = X0[Y] - m*X0[X]; - - /* obtain quadratic for x: */ - Coord A = m*m + 1; - Coord B = 2*h - 2*b*m + 2*k*m; - Coord C = b*b + h*h + k*k - r*r - 2*b*k; - - Coord det = B*B - 4*A*C; - - /* no intersection, circle and line do not cross */ - if (det < 0) - return 0; - - /* solve quadratic */ - x0 = (B + std::sqrt(det)) / (2*A); - x1 = (B - std::sqrt(det)) / (2*A); - - /* substitute the calculated x times to determine the y values */ - y0 = m*x0 + b; - y1 = m*x1 + b; - } - - p0 = Point(x0, y0); - p1 = Point(x1, y1); - - return 2; -} static Point intersection_point(Point origin_a, Point vector_a, Point origin_b, Point vector_b) { @@ -160,7 +91,7 @@ void bevel_join(join_data jd) void round_join(join_data jd) { - jd.res.appendNew(jd.width, jd.width, 0, false, jd.width <= 0, jd.outgoing.initialPoint()); + jd.res.appendNew(jd.width, jd.width, 0, false, jd.width <= 0, jd.outgoing.initialPoint()); jd.res.append(jd.outgoing); } @@ -226,18 +157,20 @@ void miter_join_internal(join_data jd, bool clip) void miter_join(join_data jd) { miter_join_internal(jd, false); } void miter_clip_join(join_data jd) { miter_join_internal(jd, true); } -Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point endPt) +Geom::Point pick_solution(std::vector points, Geom::Point tang2, Geom::Point endPt) { + assert(points.size() == 2); Geom::Point sol; - if ( dot(tang2,points[0]-endPt) > 0 ) { + if ( dot(tang2, points[0].point() - endPt) > 0 ) { // points[0] is bad, choose points[1] sol = points[1]; - } else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1] + } else if ( dot(tang2, points[1].point() - endPt) > 0 ) { // points[0] could be good, now check points[1] // points[1] is bad, choose points[0] sol = points[0]; } else { // both points are good, choose nearest - sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? points[0] : points[1]; + sol = ( distanceSq(endPt, points[0].point()) < distanceSq(endPt, points[1].point()) ) + ? points[0].point() : points[1].point(); } return sol; } @@ -261,9 +194,8 @@ void extrapolate_join(join_data jd) bool inc_ls = !circle1.center().isFinite(); bool out_ls = !circle2.center().isFinite(); - Geom::Point points[2]; + std::vector points; - int solutions = 0; Geom::EllipticalArc *arc1 = NULL; Geom::EllipticalArc *arc2 = NULL; Geom::Point sol; @@ -272,33 +204,29 @@ void extrapolate_join(join_data jd) if (!inc_ls && !out_ls) { // Two circles - solutions = Geom::circle_circle_intersection(circle1.center(), circle1.radius(), - circle2.center(), circle2.radius(), - points[0], points[1]); - if (solutions == 2) { + points = circle1.intersect(circle2); + if (points.size() == 2) { sol = pick_solution(points, tang2, endPt); - arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol, true); - arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol); + arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt); } } else if (inc_ls && !out_ls) { // Line and circle - solutions = Geom::circle_line_intersection(circle2, incoming.initialPoint(), incoming.finalPoint(), points[0], points[1]); - - if (solutions == 2) { + points = circle2.intersect(Line(incoming.initialPoint(), incoming.finalPoint())); + if (points.size() == 2) { sol = pick_solution(points, tang2, endPt); - arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt); } } else if (!inc_ls && out_ls) { // Circle and line - solutions = Geom::circle_line_intersection(circle1, outgoing.initialPoint(), outgoing.finalPoint(), points[0], points[1]); - - if (solutions == 2) { + points = circle1.intersect(Line(outgoing.initialPoint(), outgoing.finalPoint())); + if (points.size() == 2) { sol = pick_solution(points, tang2, endPt); - arc1 = circle1.arc(startPt, 0.5*(sol+startPt), sol, true); + arc1 = circle1.arc(startPt, 0.5*(sol+startPt), sol); } } - if (solutions != 2) + if (points.size() != 2) // no solutions available, fall back to miter return miter_clip_join(jd); @@ -348,19 +276,18 @@ void extrapolate_join(join_data jd) limit_line.setAngle(start_ray.angle() + limit_angle); } - Geom::EllipticalArc *arc_center = circle_center.arc(point_on_path, 0.5*(point_on_path + sol), sol, true); + Geom::EllipticalArc *arc_center = circle_center.arc(point_on_path, 0.5*(point_on_path + sol), sol); if (arc_center && arc_center->sweepAngle() > limit_angle) { // We need to clip clipped = true; if (!inc_ls) { // Incoming circular - solutions = Geom::circle_line_intersection(circle1, limit_line.pointAt(0), limit_line.pointAt(1), points[0], points[1]); - - if (solutions == 2) { + points = circle1.intersect(limit_line); + if (points.size() == 2) { p1 = pick_solution(points, tang2, endPt); delete arc1; - arc1 = circle1.arc(startPt, 0.5*(p1+startPt), p1, true); + arc1 = circle1.arc(startPt, 0.5*(p1+startPt), p1); } } else { p1 = Geom::intersection_point(startPt, tang1, limit_line.pointAt(0), limit_line.versor()); @@ -368,12 +295,11 @@ void extrapolate_join(join_data jd) if (!out_ls) { // Outgoing circular - solutions = Geom::circle_line_intersection(circle2, limit_line.pointAt(0), limit_line.pointAt(1), points[0], points[1]); - - if (solutions == 2) { + points = circle2.intersect(limit_line); + if (points.size() == 2) { p2 = pick_solution(points, tang1, endPt); delete arc2; - arc2 = circle2.arc(p2, 0.5*(p2+endPt), endPt, true); + arc2 = circle2.arc(p2, 0.5*(p2+endPt), endPt); } } else { p2 = Geom::intersection_point(endPt, tang2, limit_line.pointAt(0), limit_line.versor()); -- cgit v1.2.3 From 688ccdb666afbbe379a4b67c5765f557e019bdbc Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Mon, 25 May 2015 21:18:34 -0400 Subject: never let me try this again (bzr r14176) --- src/helper/geom-pathstroke.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index 1df17acf5..930737572 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -420,7 +420,7 @@ void join_inside(join_data jd) else if (cross.size() > 1) { // I am not sure how well this will work -- we pick the join node closest // to the cross point of the paths - Geom::Point original = res.finalPoint()+Geom::rot90(jd.in_tang)*jd.width; + /*Geom::Point original = res.finalPoint()+Geom::rot90(jd.in_tang)*jd.width; Geom::Coord trial = Geom::L2(res.pointAt(cross[0].ta)-original); solution = 0; for (size_t i = 1; i < cross.size(); ++i) { @@ -431,7 +431,7 @@ void join_inside(join_data jd) solution = i; //printf("Found improved solution: %f\n", trial); } - } + }*/ } if (solution != -1) { -- cgit v1.2.3 From 0ea72b9451e2544b4966080e70c9e9689edd3109 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 11 Jul 2015 14:20:59 -0400 Subject: Shit son, MROE FUCKING DOCS FUCKING EVERYWHERE IT'S A WONDER WE HAVE SPACE FOR A VECTOR GRAPHICS PROGRAM BETWEEN ALL THESE DOCS (bzr r14242) --- src/helper/geom-pathstroke.cpp | 103 +++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 51 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index e1038b03a..e5f207c66 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -1,7 +1,8 @@ -/* Author: +/* Authors: * Liam P. White + * Tavmjong Bah * - * Copyright (C) 2014-2015 Author + * Copyright (C) 2014-2015 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -60,14 +61,14 @@ namespace { // Internal data structure -struct join_data -{ +struct join_data { join_data(Geom::Path &_res, Geom::Path const&_outgoing, Geom::Point _in_tang, Geom::Point _out_tang, double _miter, double _width) - : res(_res), outgoing(_outgoing), in_tang(_in_tang) - , out_tang(_out_tang), miter(_miter), width(_width) {} + : res(_res), outgoing(_outgoing), in_tang(_in_tang), out_tang(_out_tang), miter(_miter), width(_width) {}; - // I/O + // contains the current path that is being built on Geom::Path &res; + + // contains the next curve to append Geom::Path const& outgoing; // input tangents @@ -382,47 +383,6 @@ void tangents(Geom::Point tang[2], Geom::Curve const& incoming, Geom::Curve cons tang[0] = tang1, tang[1] = tang2; } -void outline_helper(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join) -{ - if (res.size() == 0 || temp.size() == 0) - return; - - Geom::Curve const& outgoing = temp.front(); - if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { - // if the points are /that/ close, just ignore this one - res.setFinal(temp.initialPoint()); - res.append(temp); - return; - } - - join_data jd(res, temp, in_tang, out_tang, miter, width); - - bool on_outside = (Geom::cross(in_tang, out_tang) > 0); - - if (on_outside) { - join_func *jf; - switch (join) { - case Inkscape::JOIN_BEVEL: - jf = &bevel_join; - break; - case Inkscape::JOIN_ROUND: - jf = &round_join; - break; - case Inkscape::JOIN_EXTRAPOLATE: - jf = &extrapolate_join; - break; - case Inkscape::JOIN_MITER_CLIP: - jf = &miter_clip_join; - break; - default: - jf = &miter_join; - } - jf(jd); - } else { - join_inside(jd); - } -} - // Offsetting a line segment is mathematically stable and quick to do Geom::LineSegment offset_line(Geom::LineSegment const& l, double width) { @@ -696,7 +656,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin res.append(temp); } else { tangents(tang, input[u-1], input[u]); - outline_helper(res, temp, tang[0], tang[1], width, miter, join); + outline_join(res, temp, tang[0], tang[1], width, miter, join); } // odd number of paths @@ -704,7 +664,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin temp = Geom::Path(); offset_curve(temp, &input[u+1], width); tangents(tang, input[u], input[u+1]); - outline_helper(res, temp, tang[0], tang[1], width, miter, join); + outline_join(res, temp, tang[0], tang[1], width, miter, join); } } @@ -716,7 +676,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin Geom::Path temp2; temp2.append(c2); tangents(tang, input.back(), input.front()); - outline_helper(temp, temp2, tang[0], tang[1], width, miter, join); + outline_join(temp, temp2, tang[0], tang[1], width, miter, join); res.erase(res.begin()); res.erase_last(); // @@ -727,6 +687,47 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin return res; } +void outline_join(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join) +{ + if (res.size() == 0 || temp.size() == 0) + return; + + Geom::Curve const& outgoing = temp.front(); + if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { + // if the points are /that/ close, just ignore this one + res.setFinal(temp.initialPoint()); + res.append(temp); + return; + } + + join_data jd(res, temp, in_tang, out_tang, miter, width); + + bool on_outside = (Geom::cross(in_tang, out_tang) > 0); + + if (on_outside) { + join_func *jf; + switch (join) { + case Inkscape::JOIN_BEVEL: + jf = &bevel_join; + break; + case Inkscape::JOIN_ROUND: + jf = &round_join; + break; + case Inkscape::JOIN_EXTRAPOLATE: + jf = &extrapolate_join; + break; + case Inkscape::JOIN_MITER_CLIP: + jf = &miter_clip_join; + break; + default: + jf = &miter_join; + } + jf(jd); + } else { + join_inside(jd); + } +} + } // namespace Inkscape /* -- cgit v1.2.3 From b8027c4442f0e93903ff96c49fbd0c0e4d1444e3 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Thu, 16 Jul 2015 07:56:04 -0400 Subject: setStitching(), gajiosdfksdsfd (bzr r14249) --- src/helper/geom-pathstroke.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/helper/geom-pathstroke.cpp') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index e5f207c66..c73a9e9e7 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -647,7 +647,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin const size_t k = (input.back_closed().isDegenerate() && input.closed()) ?input.size_default()-1:input.size_default(); for (size_t u = 0; u < k; u += 2) { - temp = Geom::Path(); + temp.clear(); offset_curve(temp, &input[u], width); @@ -661,7 +661,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin // odd number of paths if (u < k - 1) { - temp = Geom::Path(); + temp.clear(); offset_curve(temp, &input[u+1], width); tangents(tang, input[u], input[u+1]); outline_join(res, temp, tang[0], tang[1], width, miter, join); @@ -671,7 +671,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin if (input.closed()) { Geom::Curve const &c1 = res.back(); Geom::Curve const &c2 = res.front(); - temp = Geom::Path(); + temp.clear(); temp.append(c1); Geom::Path temp2; temp2.append(c2); -- cgit v1.2.3