summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2015-03-19 12:07:40 +0000
committerJabiertxof <jtx@jtx.marker.es>2015-03-19 12:07:40 +0000
commit6f82eefceb224c8d5d7c9b93289a21cc31ba411d (patch)
treee42ec37ac15fa39505f63ce9158110492231cfd6 /src
parentFixed compiling problems and removed ACTIVE DESKTOP from LPE (diff)
parentui/tools: sp. fixes (cosmetic) (diff)
downloadinkscape-6f82eefceb224c8d5d7c9b93289a21cc31ba411d.tar.gz
inkscape-6f82eefceb224c8d5d7c9b93289a21cc31ba411d.zip
update to trunk
(bzr r13879.1.14)
Diffstat (limited to 'src')
-rw-r--r--src/helper/CMakeLists.txt2
-rw-r--r--src/helper/Makefile_insert2
-rw-r--r--src/helper/geom-pathstroke.cpp505
-rw-r--r--src/helper/geom-pathstroke.h57
-rw-r--r--src/live_effects/lpe-jointype.cpp56
-rw-r--r--src/live_effects/lpe-jointype.h4
-rw-r--r--src/ui/tool/path-manipulator.cpp38
-rw-r--r--src/ui/tools/box3d-tool.h2
-rw-r--r--src/ui/tools/connector-tool.cpp2
-rw-r--r--src/ui/tools/dynamic-base.h2
-rw-r--r--src/ui/tools/gradient-tool.cpp2
-rw-r--r--src/ui/tools/node-tool.cpp2
-rw-r--r--src/ui/tools/pen-tool.cpp4
-rw-r--r--src/ui/tools/spray-tool.cpp2
14 files changed, 627 insertions, 53 deletions
diff --git a/src/helper/CMakeLists.txt b/src/helper/CMakeLists.txt
index 74ce2c85d..ff4760c24 100644
--- a/src/helper/CMakeLists.txt
+++ b/src/helper/CMakeLists.txt
@@ -13,6 +13,7 @@ set(helper_SRC
action-context.cpp
geom.cpp
geom-nodetype.cpp
+ geom-pathstroke.cpp
gnome-utils.cpp
pixbuf-ops.cpp
png-write.cpp
@@ -30,6 +31,7 @@ set(helper_SRC
action-context.h
geom-curves.h
geom-nodetype.h
+ geom-pathstroke.h
geom.h
gnome-utils.h
mathfns.h
diff --git a/src/helper/Makefile_insert b/src/helper/Makefile_insert
index 5cb4cea8d..e59fcfb70 100644
--- a/src/helper/Makefile_insert
+++ b/src/helper/Makefile_insert
@@ -12,6 +12,8 @@ ink_common_sources += \
helper/geom-curves.h \
helper/geom-nodetype.cpp \
helper/geom-nodetype.h \
+ helper/geom-pathstroke.cpp \
+ helper/geom-pathstroke.h \
helper/gnome-utils.cpp \
helper/gnome-utils.h \
helper/mathfns.h \
diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp
new file mode 100644
index 000000000..f41732a51
--- /dev/null
+++ b/src/helper/geom-pathstroke.cpp
@@ -0,0 +1,505 @@
+/* Author:
+ * Liam P. White
+ *
+ * Copyright (C) 2014-2015 Author
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <2geom/path-sink.h>
+#include <2geom/point.h>
+#include <2geom/bezier-curve.h>
+#include <2geom/svg-elliptical-arc.h>
+#include <2geom/sbasis-to-bezier.h> // cubicbezierpath_from_sbasis
+
+#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);
+
+static Point intersection_point(Point origin_a, Point vector_a, Point origin_b, Point vector_b)
+{
+ Coord denom = cross(vector_b, vector_a);
+ if (!are_near(denom,0.)) {
+ Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom;
+ return origin_a + vector_a*t;
+ }
+ return Point(infinity(), infinity());
+}
+
+/**
+* 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<SBasis> const &curve, double t, double tol=0.01 )
+{
+ D2<SBasis> 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<D2<SBasis> > unitv = unitVector(dM,tol);
+ Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv);
+ Piecewise<SBasis> 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 {
+
+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*/)
+{
+ res.appendNew<Geom::LineSegment>(outgoing.initialPoint());
+}
+
+void round_join(Geom::Path& res, Geom::Curve const& outgoing, double /*miter*/, double width)
+{
+ res.appendNew<Geom::SVGEllipticalArc>(width, width, 0, false, width > 0, outgoing.initialPoint());
+}
+
+void miter_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width)
+{
+ 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);
+ if (p.isFinite()) {
+ // check size of miter
+ Geom::Point point_on_path = incoming.finalPoint() - Geom::rot90(tang1)*width;
+ double len = Geom::distance(p, point_on_path);
+ if (len <= miter) {
+ // miter OK, check to see if we can do a relocation
+ // TODO FIXME
+ /*if (auto line = cast(const(LineSegment))res.back_open) {
+ Curve copy = line.duplicate;
+ copy.setFinal(p);
+ res.erase_last();
+ res.append(copy);
+ } else {*/
+ res.appendNew<Geom::LineSegment>(p);
+ //}
+ }
+ }
+ res.appendNew<Geom::LineSegment>(outgoing.initialPoint());
+}
+
+// might need a little reworking
+void extrapolate_join(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width)
+{
+ using namespace Geom;
+ Geom::Curve const& incoming = path_builder.back();
+ Geom::Point endPt = outgoing.initialPoint();
+
+ // The method used when extrapolating curves fails to work when either side of the join to be extrapolated
+ // is a line segment. When this situation is encountered, fall back to a regular miter join.
+ bool lineProblem = (dynamic_cast<LineSegment const *>(&incoming)) || (dynamic_cast<LineSegment const*>(&outgoing));
+ if (lineProblem == false) {
+ // Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(incoming.toSBasis()), 0.);
+ Geom::Point tang2 = Geom::unitTangentAt(outgoing.toSBasis(), 0);
+
+ Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
+ Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0);
+
+ Geom::Point points[2];
+ int solutions = Geom::circle_circle_intersection(circle1.center(), circle1.ray(),
+ circle2.center(), circle2.ray(),
+ points[0], points[1]);
+ if (solutions == 2) {
+ Geom::Point sol(0,0);
+ if ( dot(tang2,points[0]-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]
+ // 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];
+ }
+
+ Geom::EllipticalArc *arc0 = circle1.arc(incoming.finalPoint(), 0.5*(incoming.finalPoint()+sol), sol, true);
+ Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true);
+ try {
+ if (arc0) {
+ path_builder.append(*arc0);
+ delete arc0;
+ arc0 = NULL;
+ } else {
+ throw std::exception();
+ }
+
+ if (arc1) {
+ path_builder.append(*arc1);
+ delete arc1;
+ arc1 = NULL;
+ } else {
+ throw std::exception();
+ }
+
+ } catch (std::exception const & ex) {
+ printf("WARNING: Error extrapolating line join: %s\n", ex.what());
+ path_builder.appendNew<Geom::LineSegment>(endPt);
+ }
+ } else {
+ // 1 or no solutions found, default to miter
+ miter_join(path_builder, outgoing, miter_limit, line_width);
+ }
+ } else {
+ // Line segments exist
+ miter_join(path_builder, outgoing, miter_limit, line_width);
+ }
+}
+
+void join_inside(Geom::Path& res, Geom::Curve const& outgoing)
+{
+ res.appendNew<Geom::LineSegment>(outgoing.initialPoint());
+}
+
+void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, double miter, Inkscape::LineJoinType join)
+{
+ Geom::Point tang1 = -Geom::unitTangentAt(reverse(res.back().toSBasis()), 0.);
+ //Geom::Point tang2 = to_add[0].unitTangentAt(0);
+ Geom::Point discontinuity_vec = to_add.initialPoint() - res.finalPoint();
+ bool on_outside = (Geom::dot(tang1, discontinuity_vec) >= 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;
+ default:
+ jf = &miter_join;
+ }
+ jf(res, to_add[0], miter, width);
+ } else {
+ join_inside(res, to_add[0]);
+ }
+
+ res.append(to_add);
+}
+
+// Offsetting a line segment is mathematically stable and quick to do
+Geom::LineSegment offset_line(Geom::LineSegment const& l, double width)
+{
+ Geom::Point tang1 = Geom::rot90(l.unitTangentAt(0));
+ Geom::Point tang2 = Geom::rot90(unitTangentAt(reverse(l.toSBasis()), 0.));
+
+ Geom::Point start = l.initialPoint() + tang1 * width;
+ Geom::Point end = l.finalPoint() - tang2 * width;
+
+ return Geom::LineSegment(start, end);
+}
+
+void get_cubic_data(Geom::CubicBezier const& bez, double time, double& len, double& rad)
+{
+ // get derivatives
+ std::vector<Geom::Point> derivs = bez.pointAndDerivatives(time, 3);
+
+ Geom::Point der1 = derivs[1]; // first deriv (tangent vector)
+ Geom::Point der2 = derivs[2]; // second deriv (tangent's tangent)
+ double l = Geom::L2(der1); // length
+
+ len = rad = 0;
+
+ // TODO: we might want to consider using Geom::touching_circle to determine the
+ // curvature radius here. Less code duplication, but slower
+
+ if (Geom::are_near(l, 0, 1e-4)) {
+ l = Geom::L2(der2);
+ Geom::Point der3 = derivs.at(3); // try second time
+ if (Geom::are_near(l, 0, 1e-4)) {
+ l = Geom::L2(der3);
+ if (Geom::are_near(l, 0)) {
+ return; // this isn't a segment...
+ }
+ rad = 1e8;
+ } else {
+ rad = -l * (Geom::dot(der2, der2) / Geom::cross(der3, der2));
+ }
+ } else {
+ rad = -l * (Geom::dot(der1, der1) / Geom::cross(der2, der1));
+ }
+ len = l;
+}
+
+void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, double tol, size_t levels)
+{
+ using Geom::X;
+ using Geom::Y;
+
+ Geom::Point start_pos = bez.initialPoint();
+ Geom::Point end_pos = bez.finalPoint();
+
+ Geom::Point start_normal = Geom::rot90(bez.unitTangentAt(0));
+ Geom::Point end_normal = -Geom::rot90(Geom::unitTangentAt(Geom::reverse(bez.toSBasis()), 0.));
+
+ // offset the start and end control points out by the width
+ Geom::Point start_new = start_pos + start_normal*width;
+ Geom::Point end_new = end_pos + end_normal*width;
+
+ // --------
+ double start_rad, end_rad;
+ double start_len, end_len; // tangent lengths
+ get_cubic_data(bez, 0, start_len, start_rad);
+ get_cubic_data(bez, 1, end_len, end_rad);
+
+ double start_off = 1, end_off = 1;
+ // correction of the lengths of the tangent to the offset
+ if (!Geom::are_near(start_rad, 0))
+ start_off += width / start_rad;
+ if (!Geom::are_near(end_rad, 0))
+ end_off += width / end_rad;
+ start_off *= start_len;
+ end_off *= end_len;
+ // --------
+
+ Geom::Point mid1_new = start_normal.ccw()*start_off;
+ mid1_new = Geom::Point(start_new[X] + mid1_new[X]/3., start_new[Y] + mid1_new[Y]/3.);
+ Geom::Point mid2_new = end_normal.ccw()*end_off;
+ mid2_new = Geom::Point(end_new[X] - mid2_new[X]/3., end_new[Y] - mid2_new[Y]/3.);
+
+ // create the estimate curve
+ Geom::CubicBezier c = Geom::CubicBezier(start_new, mid1_new, mid2_new, end_new);
+
+ // reached maximum recursive depth
+ // don't bother with any more correction
+ if (levels == 0) {
+ p.append(c, Geom::Path::STITCH_DISCONTINUOUS);
+ return;
+ }
+
+ // check the tolerance for our estimate to be a parallel curve
+ Geom::Point chk = c.pointAt(.5);
+ Geom::Point req = bez.pointAt(.5) + Geom::rot90(bez.unitTangentAt(.5))*width; // required accuracy
+
+ Geom::Point const diff = req - chk;
+ double const err = Geom::dot(diff, diff);
+
+ if (err < tol) {
+ if (Geom::are_near(start_new, p.finalPoint())) {
+ p.setFinal(start_new); // if it isn't near, we throw
+ }
+
+ // we're good, curve is accurate enough
+ p.append(c);
+ return;
+ } else {
+ // split the curve in two
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> s = bez.subdivide(.5);
+ offset_cubic(p, s.first, width, tol, levels - 1);
+ offset_cubic(p, s.second, width, tol, levels - 1);
+ }
+}
+
+void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double width, double tol, size_t levels)
+{
+ // cheat
+ // it's faster
+ // seriously
+ std::vector<Geom::Point> points = bez.points();
+ 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[3]);
+ offset_cubic(p, cub, width, tol, levels);
+}
+
+void offset_curve(Geom::Path& res, Geom::Curve const* current, double width)
+{
+ double const tolerance = 0.0025;
+ size_t levels = 8;
+
+ // TODO: we can handle SVGEllipticalArc here as well, do that!
+
+ if (Geom::BezierCurve const *b = dynamic_cast<Geom::BezierCurve const*>(current)) {
+ size_t order = b->order();
+ switch (order) {
+ case 1:
+ res.append(offset_line(static_cast<Geom::LineSegment const&>(*current), width));
+ break;
+ case 2: {
+ Geom::QuadraticBezier const& q = static_cast<Geom::QuadraticBezier const&>(*current);
+ offset_quadratic(res, q, width, tolerance, levels);
+ break;
+ }
+ case 3: {
+ Geom::CubicBezier const& cb = static_cast<Geom::CubicBezier const&>(*current);
+ offset_cubic(res, cb, width, tolerance, levels);
+ break;
+ }
+ default: {
+ Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), 0.1);
+ for (size_t i = 0; i < sbasis_path.size(); ++i)
+ offset_curve(res, &sbasis_path[i], width);
+ break;
+ }
+ }
+ } else {
+ Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), 0.1);
+ for (size_t i = 0; i < sbasis_path.size(); ++i)
+ offset_curve(res, &sbasis_path[i], width);
+ }
+}
+
+}
+
+namespace Inkscape {
+
+Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join, LineCapType butt)
+{
+ if (input.size() == 0) return Geom::PathVector(); // nope, don't even try
+
+ 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);
+
+ res.moveTo(with_dir[0].initialPoint());
+ res.append(with_dir);
+
+ // glue caps
+ if (!input.closed()) {
+ switch (butt) {
+ case BUTT_ROUND:
+ res.arcTo((-width) / 2., (-width) / 2., 0., true, true, against_dir.initialPoint());
+ break;
+ case BUTT_SQUARE: {
+ Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(input[input.size()-1].toSBasis()), 0.);
+ double radius = 0.5 * Geom::distance(with_dir.finalPoint(), against_dir.initialPoint());
+ res.lineTo(with_dir.finalPoint() + end_deriv*radius);
+ res.lineTo(against_dir.initialPoint() + end_deriv*radius);
+ res.lineTo(against_dir.initialPoint());
+ break;
+ }
+ case BUTT_PEAK: {
+ Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(input[input.size()-1].toSBasis()), 0.);
+ double radius = 0.5 * Geom::distance(with_dir.finalPoint(), against_dir.initialPoint());
+ Geom::Point midpoint = ((with_dir.finalPoint() + against_dir.initialPoint()) * 0.5) + end_deriv*radius;
+ res.lineTo(midpoint);
+ res.lineTo(against_dir.initialPoint());
+ break;
+ }
+ case BUTT_FLAT:
+ default:
+ res.lineTo(against_dir.initialPoint());
+ break;
+ }
+ } else {
+ res.moveTo(against_dir.initialPoint());
+ }
+
+ res.append(against_dir);
+
+ if (!input.closed()) {
+ switch(butt) {
+ case BUTT_ROUND:
+ res.arcTo((-width) / 2., (-width) / 2., 0., true, true, with_dir.initialPoint());
+ break;
+ case BUTT_SQUARE: {
+ Geom::Point end_deriv = -input[0].unitTangentAt(0.);
+ double radius = 0.5 * Geom::distance(against_dir.finalPoint(), with_dir.initialPoint());
+ res.lineTo(against_dir.finalPoint() + end_deriv*radius);
+ res.lineTo(with_dir.initialPoint() + end_deriv*radius);
+ res.lineTo(with_dir.initialPoint());
+ break;
+ }
+ case BUTT_PEAK: {
+ Geom::Point end_deriv = -input[0].unitTangentAt(0.);
+ double radius = 0.5 * Geom::distance(against_dir.finalPoint(), with_dir.initialPoint());
+ Geom::Point midpoint = ((against_dir.finalPoint() + with_dir.initialPoint()) * 0.5) + end_deriv*radius;
+ res.lineTo(midpoint);
+ res.lineTo(with_dir.initialPoint());
+ break;
+ }
+ case BUTT_FLAT:
+ default:
+ res.lineTo(with_dir.initialPoint());
+ }
+ res.closePath();
+ }
+
+ res.flush();
+ return res.peek();
+}
+
+Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join)
+{
+ Geom::Path res;
+ if (input.size() == 0) return res;
+
+ Geom::Point tang1 = input[0].unitTangentAt(0);
+ Geom::Point start = input.initialPoint() + tang1 * width;
+ Geom::Path temp;
+
+ res.start(start);
+
+ // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well
+ const size_t k = input.size();
+ for (size_t u = 0; u < k; u += 2) {
+ temp = Geom::Path();
+
+ offset_curve(temp, &input[u], width);
+
+ // on the first run through, there isn't a join
+ if (u == 0) {
+ res.append(temp);
+ } else {
+ outline_helper(res, temp, width, miter, join);
+ }
+
+ // odd number of paths
+ if (u < k - 1) {
+ temp = Geom::Path();
+ offset_curve(temp, &input[u+1], width);
+ outline_helper(res, temp, width, miter, join);
+ }
+ }
+
+ if (input.closed()) {
+ Geom::Curve const &c1 = res[res.size()-1];
+ Geom::Curve const &c2 = res[0];
+ temp = Geom::Path();
+ temp.append(c1);
+ Geom::Path temp2;
+ temp2.append(c2);
+ outline_helper(temp, temp2, width, miter, join);
+ temp.erase_last(); // we already outlined c2
+ temp.erase(temp.begin()); // we already outlined c1
+
+ //
+ res.append(temp);
+ }
+
+ res.close();
+ return res;
+}
+
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8 :
diff --git a/src/helper/geom-pathstroke.h b/src/helper/geom-pathstroke.h
new file mode 100644
index 000000000..fe79e2777
--- /dev/null
+++ b/src/helper/geom-pathstroke.h
@@ -0,0 +1,57 @@
+#ifndef INKSCAPE_HELPER_PATH_STROKE_H
+#define INKSCAPE_HELPER_PATH_STROKE_H
+
+/* Author:
+ * Liam P. White
+ *
+ * Copyright (C) 2014-2015 Author
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <2geom/path.h>
+#include <2geom/pathvector.h>
+
+namespace Inkscape {
+
+enum LineJoinType {
+ JOIN_BEVEL,
+ JOIN_ROUND,
+ JOIN_MITER,
+ JOIN_EXTRAPOLATE,
+};
+
+enum LineCapType {
+ BUTT_FLAT,
+ BUTT_ROUND,
+ BUTT_SQUARE,
+ BUTT_PEAK, // ?
+};
+
+/**
+ * Offset the input path by @a width.
+ * Joins may behave oddly if the width is negative.
+ *
+ * @param input
+ * @param width Amount to offset.
+ * @param miter Miter limit. Only used with JOIN_EXTRAPOLATE and JOIN_MITER.
+ * @param join
+ */
+Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL);
+
+Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL, LineCapType cap = BUTT_FLAT);
+
+} // namespace Inkscape
+
+#endif // INKSCAPE_HELPER_PATH_STROKE_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 :
diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp
index bf2526986..291337da0 100644
--- a/src/live_effects/lpe-jointype.cpp
+++ b/src/live_effects/lpe-jointype.cpp
@@ -8,7 +8,7 @@
*/
#include "live_effects/parameter/enum.h"
-#include "live_effects/pathoutlineprovider.h"
+#include "helper/geom-pathstroke.h"
#include "sp-shape.h"
#include "style.h"
@@ -28,19 +28,18 @@ namespace Inkscape {
namespace LivePathEffect {
static const Util::EnumData<unsigned> JoinTypeData[] = {
- {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"},
- {LINEJOIN_ROUND, N_("Rounded"), "round"},
- {LINEJOIN_POINTY, N_("Miter"), "miter"},
- {LINEJOIN_REFLECTED, N_("Reflected"), "extrapolated"},
- {LINEJOIN_EXTRAPOLATED, N_("Extrapolated arc"), "extrp_arc"}
+ {JOIN_BEVEL, N_("Beveled"), "bevel"},
+ {JOIN_ROUND, N_("Rounded"), "round"},
+ {JOIN_MITER, N_("Miter"), "miter"},
+ {JOIN_EXTRAPOLATE, N_("Extrapolated arc"), "extrp_arc"},
};
static const Util::EnumData<unsigned> CapTypeData[] = {
- {BUTT_STRAIGHT, N_("Butt"), "butt"},
+ {BUTT_FLAT, N_("Butt"), "butt"},
{BUTT_ROUND, N_("Rounded"), "round"},
{BUTT_SQUARE, N_("Square"), "square"},
- {BUTT_POINTY, N_("Peak"), "peak"},
- {BUTT_LEANED, N_("Leaned"), "leaned"}
+ {BUTT_PEAK, N_("Peak"), "peak"},
+ //{BUTT_LEANED, N_("Leaned"), "leaned"}
};
static const Util::EnumDataConverter<unsigned> CapTypeConverter(CapTypeData, sizeof(CapTypeData)/sizeof(*CapTypeData));
@@ -50,9 +49,9 @@ LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
line_width(_("Line width"), _("Thickness of the stroke"), "line_width", &wr, this, 1.),
linecap_type(_("Line cap"), _("The end shape of the stroke"), "linecap_type", CapTypeConverter, &wr, this, butt_straight),
- linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED),
- start_lean(_("Start path lean"), _("Start path lean"), "start_lean", &wr, this, 0.),
- end_lean(_("End path lean"), _("End path lean"), "end_lean", &wr, this, 0.),
+ linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, JOIN_EXTRAPOLATE),
+ //start_lean(_("Start path lean"), _("Start path lean"), "start_lean", &wr, this, 0.),
+ //end_lean(_("End path lean"), _("End path lean"), "end_lean", &wr, this, 0.),
miter_limit(_("Miter limit:"), _("Maximum length of the miter join (in units of stroke width)"), "miter_limit", &wr, this, 100.),
attempt_force_join(_("Force miter"), _("Overrides the miter limit and forces a join."), "attempt_force_join", &wr, this, true)
{
@@ -60,17 +59,17 @@ LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) :
registerParameter(&linecap_type);
registerParameter(&line_width);
registerParameter(&linejoin_type);
- registerParameter(&start_lean);
- registerParameter(&end_lean);
+ //registerParameter(&start_lean);
+ //registerParameter(&end_lean);
registerParameter(&miter_limit);
registerParameter(&attempt_force_join);
was_initialized = false;
- start_lean.param_set_range(-1,1);
- start_lean.param_set_increments(0.1, 0.1);
- start_lean.param_set_digits(4);
- end_lean.param_set_range(-1,1);
- end_lean.param_set_increments(0.1, 0.1);
- end_lean.param_set_digits(4);
+ //start_lean.param_set_range(-1,1);
+ //start_lean.param_set_increments(0.1, 0.1);
+ //start_lean.param_set_digits(4);
+ //end_lean.param_set_range(-1,1);
+ //end_lean.param_set_increments(0.1, 0.1);
+ //end_lean.param_set_digits(4);
}
LPEJoinType::~LPEJoinType()
@@ -164,15 +163,18 @@ void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem)
}
}
-// NOTE: I originally had all the outliner functions defined in here, but they were actually useful
-// enough for other LPEs so I moved them all into pathoutlineprovider.cpp. The code here is just a
-// wrapper around it.
std::vector<Geom::Path> LPEJoinType::doEffect_path(std::vector<Geom::Path> const & path_in)
{
- return Outline::PathVectorOutline(path_in, line_width, static_cast<ButtTypeMod>(linecap_type.get_value()),
- static_cast<LineJoinType>(linejoin_type.get_value()),
- (attempt_force_join ? std::numeric_limits<double>::max() : miter_limit),
- start_lean/2 ,end_lean/2);
+ Geom::PathVector ret;
+ for (size_t i = 0; i < path_in.size(); ++i) {
+ Geom::PathVector tmp = Inkscape::outline(path_in[i], line_width,
+ (attempt_force_join ? std::numeric_limits<double>::max() : miter_limit),
+ static_cast<LineJoinType>(linejoin_type.get_value()),
+ static_cast<LineCapType>(linecap_type.get_value()));
+ ret.insert(ret.begin(), tmp.begin(), tmp.end());
+ }
+
+ return ret;
}
} // namespace LivePathEffect
diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h
index 73705666d..799901eb6 100644
--- a/src/live_effects/lpe-jointype.h
+++ b/src/live_effects/lpe-jointype.h
@@ -33,8 +33,8 @@ private:
ScalarParam line_width;
EnumParam<unsigned> linecap_type;
EnumParam<unsigned> linejoin_type;
- ScalarParam start_lean;
- ScalarParam end_lean;
+ //ScalarParam start_lean;
+ //ScalarParam end_lean;
ScalarParam miter_limit;
BoolParam attempt_force_join;
bool was_initialized;
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index c8b986824..dbcde240a 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -1221,10 +1221,13 @@ int PathManipulator::BSplineGetSteps() const {
LivePathEffect::LPEBSpline const *lpe_bsp = NULL;
- if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){
- Inkscape::LivePathEffect::Effect const *thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::BSPLINE);
- if(thisEffect){
- lpe_bsp = dynamic_cast<LivePathEffect::LPEBSpline const*>(thisEffect->getLPEObj()->get_lpe());
+ SPLPEItem * path = dynamic_cast<SPLPEItem *>(_path);
+ if (path){
+ if(path->hasPathEffect()){
+ Inkscape::LivePathEffect::Effect const *thisEffect = path->getPathEffectOfType(Inkscape::LivePathEffect::BSPLINE);
+ if(thisEffect){
+ lpe_bsp = dynamic_cast<LivePathEffect::LPEBSpline const*>(thisEffect->getLPEObj()->get_lpe());
+ }
}
}
int steps = 0;
@@ -1338,19 +1341,22 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE)
_spcurve->set_pathvector(pathv);
if (alert_LPE) {
/// \todo note that _path can be an Inkscape::LivePathEffect::Effect* too, kind of confusing, rework member naming?
- if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){
- Inkscape::LivePathEffect::Effect* thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE);
- if(thisEffect){
- LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>(thisEffect->getLPEObj()->get_lpe());
- if (lpe_pwr) {
- lpe_pwr->adjustForNewPath(pathv);
+ SPLPEItem * path = dynamic_cast<SPLPEItem *>(_path);
+ if (path){
+ if(path->hasPathEffect()){
+ Inkscape::LivePathEffect::Effect* thisEffect = path->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE);
+ if(thisEffect){
+ LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>(thisEffect->getLPEObj()->get_lpe());
+ if (lpe_pwr) {
+ lpe_pwr->adjustForNewPath(pathv);
+ }
}
- }
- thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER);
- if(thisEffect){
- LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(thisEffect->getLPEObj()->get_lpe());
- if (lpe_fll) {
- lpe_fll->adjustForNewPath(pathv);
+ thisEffect = path->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER);
+ if(thisEffect){
+ LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(thisEffect->getLPEObj()->get_lpe());
+ if (lpe_fll) {
+ lpe_fll->adjustForNewPath(pathv);
+ }
}
}
}
diff --git a/src/ui/tools/box3d-tool.h b/src/ui/tools/box3d-tool.h
index 1dd6bb5f8..33ae6d8e7 100644
--- a/src/ui/tools/box3d-tool.h
+++ b/src/ui/tools/box3d-tool.h
@@ -80,7 +80,7 @@ private:
Proj::Pt3 drag_ptC_proj;
bool ctrl_dragged; /* whether we are ctrl-dragging */
- bool extruded; /* whether shift-dragging already occured (i.e. the box is already extruded) */
+ bool extruded; /* whether shift-dragging already occurred (i.e. the box is already extruded) */
sigc::connection sel_changed_connection;
diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp
index d76b0d142..c3ef19507 100644
--- a/src/ui/tools/connector-tool.cpp
+++ b/src/ui/tools/connector-tool.cpp
@@ -49,7 +49,7 @@
* Much of the way connectors work for user-defined points has been
* changed so that it no longer defines special attributes to record
* the points. Instead it uses single node paths to define points
- * who are then seperate objects that can be fixed on the canvas,
+ * who are then separate objects that can be fixed on the canvas,
* grouped into objects and take full advantage of all transform, snap
* and align functionality of all other objects.
*
diff --git a/src/ui/tools/dynamic-base.h b/src/ui/tools/dynamic-base.h
index c948fa286..095af8f88 100644
--- a/src/ui/tools/dynamic-base.h
+++ b/src/ui/tools/dynamic-base.h
@@ -47,7 +47,7 @@ protected:
/** accumulated shape which ultimately goes in svg:path */
SPCurve *accumulated;
- /** canvas items for "comitted" segments */
+ /** canvas items for "committed" segments */
GSList *segments;
/** canvas item for red "leading" segment */
diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp
index 5be84eb76..b27859ebb 100644
--- a/src/ui/tools/gradient-tool.cpp
+++ b/src/ui/tools/gradient-tool.cpp
@@ -321,7 +321,7 @@ sp_gradient_context_add_stops_between_selected_stops (GradientTool *rc)
if (d->point_type == POINT_RG_FOCUS) {
/*
* There are 2 draggables at the center (start) of a radial gradient
- * To avoid creating 2 seperate stops, ignore this draggable point type
+ * To avoid creating 2 separate stops, ignore this draggable point type
*/
continue;
}
diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp
index f8045a029..a4b903960 100644
--- a/src/ui/tools/node-tool.cpp
+++ b/src/ui/tools/node-tool.cpp
@@ -75,7 +75,7 @@
* - ControlPointSelection: keeps track of node selection and a set of nodes that can potentially
* be selected. There can be more than one selection. Performs actions that require no
* knowledge about the path, only about the nodes, like dragging and transforms. It is not
- * specific to nodes and can accomodate any control point derived from SelectableControlPoint.
+ * specific to nodes and can accommodate any control point derived from SelectableControlPoint.
* Transforms nodes in response to transform handle events.
* - TransformHandleSet: displays nodeset transform handles and emits transform events. The aim
* is to eventually use a common class for object and control point transforms.
diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp
index d28b7c27a..d5f501163 100644
--- a/src/ui/tools/pen-tool.cpp
+++ b/src/ui/tools/pen-tool.cpp
@@ -2143,7 +2143,7 @@ bool PenTool::_undoLastPoint() {
this->p[1] = this->p[0];
}
- // asign the value in a third of the distance of the last segment.
+ // assign the value in a third of the distance of the last segment.
if (this->bspline){
this->p[1] = this->p[0] + (1./3)*(this->p[3] - this->p[0]);
}
@@ -2165,7 +2165,7 @@ bool PenTool::_undoLastPoint() {
this->green_curve->backspace();
}
- // assign the value of this->p[1] to the oposite of the green line last segment
+ // assign the value of this->p[1] to the opposite of the green line last segment
if (this->spiro){
Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(this->green_curve->last_segment());
if ( cubic ) {
diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp
index ec7d10e13..0399b1e55 100644
--- a/src/ui/tools/spray-tool.cpp
+++ b/src/ui/tools/spray-tool.cpp
@@ -406,7 +406,7 @@ static bool sp_spray_recursive(SPDesktop *desktop,
parent->appendChild(copy);
SPObject *new_obj = doc->getObjectByRepr(copy);
- item_copied = dynamic_cast<SPItem *>(new_obj); // Convertion object->item
+ item_copied = dynamic_cast<SPItem *>(new_obj); // Conversion object->item
Geom::Point center=item->getCenter();
sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(_scale,_scale));
sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(scale,scale));