summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2015-03-19 18:27:16 +0000
committerJabiertxof <jtx@jtx.marker.es>2015-03-19 18:27:16 +0000
commit6f389e1771b308f9e2686060f7dc292b7f65daa5 (patch)
tree35f5fae6ce272d446359fb2010861f07734e1ab6 /src
parentfixing a boring bug in path manipulator (diff)
parentui/tools: sp. fixes (cosmetic) (diff)
downloadinkscape-6f389e1771b308f9e2686060f7dc292b7f65daa5.tar.gz
inkscape-6f389e1771b308f9e2686060f7dc292b7f65daa5.zip
update to trunk
(bzr r13645.1.44)
Diffstat (limited to 'src')
-rw-r--r--src/2geom/sbasis-to-bezier.cpp21
-rw-r--r--src/extension/internal/cairo-renderer.cpp2
-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/knotholder.cpp3
-rw-r--r--src/live_effects/lpe-jointype.cpp56
-rw-r--r--src/live_effects/lpe-jointype.h4
-rw-r--r--src/live_effects/parameter/point.cpp2
-rw-r--r--src/sp-ellipse.cpp83
-rw-r--r--src/sp-item.cpp69
-rw-r--r--src/sp-item.h1
-rw-r--r--src/sp-rect.cpp24
-rw-r--r--src/ui/object-edit.cpp12
-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
-rw-r--r--src/ui/widget/page-sizer.cpp1
23 files changed, 725 insertions, 135 deletions
diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp
index 0525be04b..a2e4253d2 100644
--- a/src/2geom/sbasis-to-bezier.cpp
+++ b/src/2geom/sbasis-to-bezier.cpp
@@ -37,6 +37,7 @@
#include <2geom/choose.h>
#include <2geom/path-sink.h>
#include <2geom/exception.h>
+#include <2geom/convex-cover.h>
#include <iostream>
@@ -203,11 +204,8 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb)
THROW_RANGEERROR("size of sb is too small");
}
- bz.resize(4, Point(0,0));
- bz[0][X] = sb[X][0][0];
- bz[0][Y] = sb[Y][0][0];
- bz[3][X] = sb[X][0][1];
- bz[3][Y] = sb[Y][0][1];
+ sbasis_to_bezier(bz, sb, 4); // zeroth-order estimate
+ Geom::ConvexHull bezhull(bz);
// calculate first derivatives of x and y wrt t
@@ -231,17 +229,23 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb)
midx += (sb[X][i][0] + sb[X][i][1])/div;
div *= 4;
}
- midx = 8*midx - 4*bz[0][X] - 4*bz[3][X];
div = 2;
for (size_t i = 0; i < sb[Y].size(); ++i) {
midy += (sb[Y][i][0] + sb[Y][i][1])/div;
div *= 4;
}
- midy = 8*midy - 4*bz[0][Y] - 4*bz[3][Y];
+
+// is midpoint in hull: if not, the solution will be ill-conditioned, LP Bug 1428683
+
+ if (!bezhull.contains_point(Geom::Point(midx, midy)))
+ return;
// calculate Bezier control arms
+ midx = 8*midx - 4*bz[0][X] - 4*bz[3][X]; // re-define relative to center
+ midy = 8*midy - 4*bz[0][Y] - 4*bz[3][Y];
+
if ((std::abs(xprime[0]) < EPSILON) && (std::abs(yprime[0]) < EPSILON)
&& ((std::abs(xprime[1]) > EPSILON) || (std::abs(yprime[1]) > EPSILON))) { // degenerate handle at 0 : use distance of closest approach
numer = midx*xprime[1] + midy*yprime[1];
@@ -258,7 +262,8 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb)
dely[0] = yprime[0]*numer/denom;
delx[1] = 0;
dely[1] = 0;
- } else if (std::abs(xprime[1]*yprime[0] - yprime[1]*xprime[0]) > EPSILON) { // general case : fit mid fxn value
+ } else if (std::abs(xprime[1]*yprime[0] - yprime[1]*xprime[0]) > // general case : fit mid fxn value
+ 0.002 * std::abs(xprime[1]*xprime[0] + yprime[1]*yprime[0])) { // approx. 0.1 degree of angle
denom = xprime[1]*yprime[0] - yprime[1]*xprime[0];
for (int i = 0; i < 2; ++i) {
numer = xprime[1 - i]*midy - yprime[1 - i]*midx;
diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp
index 1f48d2097..7fbdc4296 100644
--- a/src/extension/internal/cairo-renderer.cpp
+++ b/src/extension/internal/cairo-renderer.cpp
@@ -517,7 +517,7 @@ static void sp_item_invoke_render(SPItem *item, CairoRenderContext *ctx)
SPStyle* style = item->style;
if((ctx->getFilterToBitmap() == TRUE) && (style->filter.set != 0)) {
- sp_asbitmap_render(item, ctx);
+ return sp_asbitmap_render(item, ctx);
}
SPRoot *root = dynamic_cast<SPRoot *>(item);
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/knotholder.cpp b/src/knotholder.cpp
index f46daa09e..a2d1cf017 100644
--- a/src/knotholder.cpp
+++ b/src/knotholder.cpp
@@ -165,7 +165,8 @@ KnotHolder::knot_clicked_handler(SPKnot *knot, guint state)
if (saved_item) { //increasingly aggressive sanity checks
if (saved_item->document) {
- if (object_verb <= SP_VERB_LAST && object_verb >= SP_VERB_INVALID) {
+ // enum is unsigned so can't be less than SP_VERB_INVALID
+ if (object_verb <= SP_VERB_LAST) {
DocumentUndo::done(saved_item->document, object_verb,
_("Change handle"));
}
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/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp
index 4564363db..4c4d2cd9c 100644
--- a/src/live_effects/parameter/point.cpp
+++ b/src/live_effects/parameter/point.cpp
@@ -141,7 +141,7 @@ PointParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint
class PointParamKnotHolderEntity : public KnotHolderEntity {
public:
PointParamKnotHolderEntity(PointParam *p) { this->pparam = p; }
- virtual ~PointParamKnotHolderEntity() {}
+ virtual ~PointParamKnotHolderEntity() { this->pparam->knoth = NULL;}
virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
virtual Geom::Point knot_get() const;
diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp
index 885fedafa..932a3a1b7 100644
--- a/src/sp-ellipse.cpp
+++ b/src/sp-ellipse.cpp
@@ -95,6 +95,10 @@ void SPGenericEllipse::build(SPDocument *document, Inkscape::XML::Node *repr)
std::cerr << "SPGenericEllipse::build() unknown defined type." << std::endl;
}
+ // std::cout << " cx: " << cx.write() << std::endl;
+ // std::cout << " cy: " << cy.write() << std::endl;
+ // std::cout << " rx: " << rx.write() << std::endl;
+ // std::cout << " ry: " << ry.write() << std::endl;
SPShape::build(document, repr);
}
@@ -103,29 +107,41 @@ void SPGenericEllipse::set(unsigned int key, gchar const *value)
// There are multiple ways to set internal cx, cy, rx, and ry (via SVG attributes or Sodipodi
// attributes) thus we don't want to unset them if a read fails (e.g., when we explicitly clear
// an attribute by setting it to NULL).
+
+ // We must update the SVGLengths immediately or nodes may be misplaced after they are moved.
+ double const w = viewport.width();
+ double const h = viewport.height();
+ double const d = hypot(w, h) / sqrt(2); // diagonal
+ double const em = style->font_size.computed;
+ double const ex = em * 0.5;
+
SVGLength t;
switch (key) {
case SP_ATTR_CX:
case SP_ATTR_SODIPODI_CX:
if( t.read(value) ) cx = t;
+ cx.update( em, ex, w );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_CY:
case SP_ATTR_SODIPODI_CY:
if( t.read(value) ) cy = t;
+ cy.update( em, ex, h );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_RX:
case SP_ATTR_SODIPODI_RX:
- if( t.read(value) && t.value > 0.0 ) this->rx = t;
+ if( t.read(value) && t.value > 0.0 ) rx = t;
+ rx.update( em, ex, w );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_RY:
case SP_ATTR_SODIPODI_RY:
- if( t.read(value) && t.value > 0.0 ) this->ry = t;
+ if( t.read(value) && t.value > 0.0 ) ry = t;
+ ry.update( em, ex, h );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
@@ -133,6 +149,8 @@ void SPGenericEllipse::set(unsigned int key, gchar const *value)
if( t.read(value) && t.value > 0.0 ) {
this->ry = this->rx = t;
}
+ rx.update( em, ex, d );
+ ry.update( em, ex, d );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
@@ -196,7 +214,7 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I
// << ")" << std::endl;
GenericEllipseType new_type = SP_GENERIC_ELLIPSE_UNDEFINED;
- if (this->_isSlice() || hasPathEffect() ) {
+ if (_isSlice() || hasPathEffect() ) {
new_type = SP_GENERIC_ELLIPSE_ARC;
} else if ( rx.computed == ry.computed ) {
new_type = SP_GENERIC_ELLIPSE_CIRCLE;
@@ -246,10 +264,10 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I
}
// std::cout << " type: " << g_quark_to_string( repr->code() ) << std::endl;
- // std::cout << " cx: " << cx.computed
- // << " cy: " << cy.computed
- // << " rx: " << rx.computed
- // << " ry: " << ry.computed << std::endl;
+ // std::cout << " cx: " << cx.write() << " " << cx.computed
+ // << " cy: " << cy.write() << " " << cy.computed
+ // << " rx: " << rx.write() << " " << rx.computed
+ // << " ry: " << ry.write() << " " << ry.computed << std::endl;
switch ( type ) {
case SP_GENERIC_ELLIPSE_UNDEFINED:
@@ -264,17 +282,17 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I
if (flags & SP_OBJECT_WRITE_EXT) {
repr->setAttribute("sodipodi:type", "arc");
- sp_repr_set_svg_double(repr, "sodipodi:cx", this->cx.computed);
- sp_repr_set_svg_double(repr, "sodipodi:cy", this->cy.computed);
- sp_repr_set_svg_double(repr, "sodipodi:rx", this->rx.computed);
- sp_repr_set_svg_double(repr, "sodipodi:ry", this->ry.computed);
+ sp_repr_set_svg_length(repr, "sodipodi:cx", cx);
+ sp_repr_set_svg_length(repr, "sodipodi:cy", cy);
+ sp_repr_set_svg_length(repr, "sodipodi:rx", rx);
+ sp_repr_set_svg_length(repr, "sodipodi:ry", ry);
// write start and end only if they are non-trivial; otherwise remove
- if (this->_isSlice()) {
- sp_repr_set_svg_double(repr, "sodipodi:start", this->start);
- sp_repr_set_svg_double(repr, "sodipodi:end", this->end);
+ if (_isSlice()) {
+ sp_repr_set_svg_double(repr, "sodipodi:start", start);
+ sp_repr_set_svg_double(repr, "sodipodi:end", end);
- repr->setAttribute("sodipodi:open", (!this->_closed) ? "true" : NULL);
+ repr->setAttribute("sodipodi:open", (!_closed) ? "true" : NULL);
} else {
repr->setAttribute("sodipodi:end", NULL);
repr->setAttribute("sodipodi:start", NULL);
@@ -283,13 +301,13 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I
}
// write d=
- this->set_elliptical_path_attribute(repr);
+ set_elliptical_path_attribute(repr);
break;
case SP_GENERIC_ELLIPSE_CIRCLE:
- sp_repr_set_svg_double(repr, "cx", this->cx.computed);
- sp_repr_set_svg_double(repr, "cy", this->cy.computed);
- sp_repr_set_svg_double(repr, "r", this->rx.computed);
+ sp_repr_set_svg_length(repr, "cx", cx);
+ sp_repr_set_svg_length(repr, "cy", cy);
+ sp_repr_set_svg_length(repr, "r", rx);
repr->setAttribute("rx", NULL );
repr->setAttribute("ry", NULL );
repr->setAttribute("sodipodi:cx", NULL );
@@ -304,10 +322,10 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I
break;
case SP_GENERIC_ELLIPSE_ELLIPSE:
- sp_repr_set_svg_double(repr, "cx", this->cx.computed);
- sp_repr_set_svg_double(repr, "cy", this->cy.computed);
- sp_repr_set_svg_double(repr, "rx", this->rx.computed);
- sp_repr_set_svg_double(repr, "ry", this->ry.computed);
+ sp_repr_set_svg_length(repr, "cx", cx);
+ sp_repr_set_svg_length(repr, "cy", cy);
+ sp_repr_set_svg_length(repr, "rx", rx);
+ sp_repr_set_svg_length(repr, "ry", ry);
repr->setAttribute("r", NULL );
repr->setAttribute("sodipodi:cx", NULL );
repr->setAttribute("sodipodi:cy", NULL );
@@ -324,11 +342,10 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I
std::cerr << "SPGenericEllipse::write: unknown type." << std::endl;
}
- this->set_shape(); // evaluate SPCurve
+ set_shape(); // evaluate SPCurve
SPShape::write(xml_doc, repr, flags);
- // std::cout << "SPGenericEllipse::write: Exit: " << g_quark_to_string(repr->code()) << "\n" << std::endl;
return repr;
}
@@ -339,8 +356,8 @@ const char *SPGenericEllipse::displayName() const
case SP_GENERIC_ELLIPSE_UNDEFINED:
case SP_GENERIC_ELLIPSE_ARC:
- if (this->_isSlice()) {
- if (this->_closed) {
+ if (_isSlice()) {
+ if (_closed) {
return _("Segment");
} else {
return _("Arc");
@@ -480,11 +497,11 @@ Geom::Affine SPGenericEllipse::set_transform(Geom::Affine const &xform)
}
if (this->rx._set) {
- this->rx = this->rx.computed * sw;
+ this->rx.scale( sw );
}
if (this->ry._set) {
- this->ry = this->ry.computed * sh;
+ this->ry.scale( sh );
}
/* Find start in item coords */
@@ -628,10 +645,10 @@ bool SPGenericEllipse::set_elliptical_path_attribute(Inkscape::XML::Node *repr)
void SPGenericEllipse::position_set(gdouble x, gdouble y, gdouble rx, gdouble ry)
{
- this->cx.computed = x;
- this->cy.computed = y;
- this->rx.computed = rx;
- this->ry.computed = ry;
+ this->cx = x;
+ this->cy = y;
+ this->rx = rx;
+ this->ry = ry;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
diff --git a/src/sp-item.cpp b/src/sp-item.cpp
index 5d181b80a..8c99e9bcf 100644
--- a/src/sp-item.cpp
+++ b/src/sp-item.cpp
@@ -75,18 +75,6 @@ static SPItemView* sp_item_view_list_remove(SPItemView *list,
SPItem::SPItem() : SPObject() {
- this->sensitive = 0;
- this->clip_ref = NULL;
- this->avoidRef = NULL;
- this->_is_evaluated = false;
- this->stop_paint = 0;
- this->_evaluated_status = StatusUnknown;
- this->bbox_valid = 0;
- this->freeze_stroke_width = false;
- this->transform_center_x = 0;
- this->transform_center_y = 0;
- this->display = NULL;
- this->mask_ref = NULL;
sensitive = TRUE;
bbox_valid = FALSE;
@@ -96,12 +84,13 @@ SPItem::SPItem() : SPObject() {
transform_center_x = 0;
transform_center_y = 0;
+ freeze_stroke_width = false;
+
_is_evaluated = true;
_evaluated_status = StatusUnknown;
transform = Geom::identity();
- doc_bbox = Geom::OptRect();
- freeze_stroke_width = false;
+ // doc_bbox = Geom::OptRect();
display = NULL;
@@ -670,54 +659,56 @@ void SPItem::stroke_ps_ref_changed(SPObject *old_ps, SPObject *ps, SPItem *item)
}
}
-void SPItem::update(SPCtx* /*ctx*/, guint flags) {
- SPItem *item = this;
- SPItem* object = item;
+void SPItem::update(SPCtx* ctx, guint flags) {
-// SPObject::onUpdate(ctx, flags);
+ SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx);
- // any of the modifications defined in sp-object.h might change bbox,
+ // Any of the modifications defined in sp-object.h might change bbox,
// so we invalidate it unconditionally
- item->bbox_valid = FALSE;
+ bbox_valid = FALSE;
+
+ viewport = ictx->viewport; // Cache viewport
- if (flags & (SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG)) {
+ if (flags & (SP_OBJECT_CHILD_MODIFIED_FLAG |
+ SP_OBJECT_MODIFIED_FLAG |
+ SP_OBJECT_STYLE_MODIFIED_FLAG) ) {
if (flags & SP_OBJECT_MODIFIED_FLAG) {
- for (SPItemView *v = item->display; v != NULL; v = v->next) {
- v->arenaitem->setTransform(item->transform);
+ for (SPItemView *v = display; v != NULL; v = v->next) {
+ v->arenaitem->setTransform(transform);
}
}
- SPClipPath *clip_path = item->clip_ref ? item->clip_ref->getObject() : NULL;
- SPMask *mask = item->mask_ref ? item->mask_ref->getObject() : NULL;
+ SPClipPath *clip_path = clip_ref ? clip_ref->getObject() : NULL;
+ SPMask *mask = mask_ref ? mask_ref->getObject() : NULL;
if ( clip_path || mask ) {
- Geom::OptRect bbox = item->geometricBounds();
+ Geom::OptRect bbox = geometricBounds();
if (clip_path) {
- for (SPItemView *v = item->display; v != NULL; v = v->next) {
+ for (SPItemView *v = display; v != NULL; v = v->next) {
clip_path->setBBox(v->arenaitem->key(), bbox);
}
}
if (mask) {
- for (SPItemView *v = item->display; v != NULL; v = v->next) {
+ for (SPItemView *v = display; v != NULL; v = v->next) {
mask->sp_mask_set_bbox(v->arenaitem->key(), bbox);
}
}
}
if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
- for (SPItemView *v = item->display; v != NULL; v = v->next) {
- v->arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(object->style->opacity.value));
- v->arenaitem->setAntialiasing(object->style->shape_rendering.computed != SP_CSS_SHAPE_RENDERING_CRISPEDGES);
- v->arenaitem->setIsolation( object->style->isolation.value );
- v->arenaitem->setBlendMode( object->style->mix_blend_mode.value );
- v->arenaitem->setVisible(!item->isHidden());
+ for (SPItemView *v = display; v != NULL; v = v->next) {
+ v->arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(style->opacity.value));
+ v->arenaitem->setAntialiasing(style->shape_rendering.computed != SP_CSS_SHAPE_RENDERING_CRISPEDGES);
+ v->arenaitem->setIsolation( style->isolation.value );
+ v->arenaitem->setBlendMode( style->mix_blend_mode.value );
+ v->arenaitem->setVisible(!isHidden());
}
}
}
/* Update bounding box in user space, used for filter and objectBoundingBox units */
- if (item->style->filter.set && item->display) {
- Geom::OptRect item_bbox = item->geometricBounds();
- SPItemView *itemview = item->display;
+ if (style->filter.set && display) {
+ Geom::OptRect item_bbox = geometricBounds();
+ SPItemView *itemview = display;
do {
if (itemview->arenaitem)
itemview->arenaitem->setItemBounds(item_bbox);
@@ -725,8 +716,8 @@ void SPItem::update(SPCtx* /*ctx*/, guint flags) {
}
// Update libavoid with item geometry (for connector routing).
- if (item->avoidRef)
- item->avoidRef->handleSettingChange();
+ if (avoidRef)
+ avoidRef->handleSettingChange();
}
void SPItem::modified(unsigned int /*flags*/)
diff --git a/src/sp-item.h b/src/sp-item.h
index b9d71c551..bdc6a0ad9 100644
--- a/src/sp-item.h
+++ b/src/sp-item.h
@@ -145,6 +145,7 @@ public:
Geom::Affine transform;
mutable Geom::OptRect doc_bbox;
+ Geom::Rect viewport; // Cache viewport information
SPClipPathReference *clip_ref;
SPMaskReference *mask_ref;
diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp
index 0128c248f..e17d7373c 100644
--- a/src/sp-rect.cpp
+++ b/src/sp-rect.cpp
@@ -52,22 +52,30 @@ void SPRect::build(SPDocument* doc, Inkscape::XML::Node* repr) {
void SPRect::set(unsigned key, gchar const *value) {
/* fixme: We need real error processing some time */
+ // We must update the SVGLengths immediately or nodes may be misplaced after they are moved.
+ double const w = viewport.width();
+ double const h = viewport.height();
+ double const em = style->font_size.computed;
+ double const ex = em * 0.5;
+
switch (key) {
case SP_ATTR_X:
- this->x.readOrUnset(value);
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ this->x.readOrUnset(value);
+ this->x.update( ex, em, w );
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_Y:
- this->y.readOrUnset(value);
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ this->y.readOrUnset(value);
+ this->y.update( ex, em, h );
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_WIDTH:
if (!this->width.read(value) || this->width.value < 0.0) {
this->width.unset();
}
-
+ this->width.update( ex, em, w );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
@@ -75,7 +83,7 @@ void SPRect::set(unsigned key, gchar const *value) {
if (!this->height.read(value) || this->height.value < 0.0) {
this->height.unset();
}
-
+ this->height.update( ex, em, h );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
@@ -83,7 +91,7 @@ void SPRect::set(unsigned key, gchar const *value) {
if (!this->rx.read(value) || this->rx.value <= 0.0) {
this->rx.unset();
}
-
+ this->rx.update( ex, em, w );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
@@ -91,7 +99,7 @@ void SPRect::set(unsigned key, gchar const *value) {
if (!this->ry.read(value) || this->ry.value <= 0.0) {
this->ry.unset();
}
-
+ this->ry.update( ex, em, h );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
diff --git a/src/ui/object-edit.cpp b/src/ui/object-edit.cpp
index 04ee13cef..0a6c792dc 100644
--- a/src/ui/object-edit.cpp
+++ b/src/ui/object-edit.cpp
@@ -903,10 +903,10 @@ ArcKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*origi
Geom::Point const s = snap_knot_position(p, state);
- ge->rx.computed = fabs( ge->cx.computed - s[Geom::X] );
+ ge->rx = fabs( ge->cx.computed - s[Geom::X] );
if ( state & GDK_CONTROL_MASK ) {
- ge->ry.computed = ge->rx.computed;
+ ge->ry = ge->rx.computed;
}
item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
@@ -928,7 +928,7 @@ ArcKnotHolderEntityRX::knot_click(unsigned int state)
g_assert(ge != NULL);
if (state & GDK_CONTROL_MASK) {
- ge->ry.computed = ge->rx.computed;
+ ge->ry = ge->rx.computed;
ge->updateRepr();
}
}
@@ -941,10 +941,10 @@ ArcKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*origi
Geom::Point const s = snap_knot_position(p, state);
- ge->ry.computed = fabs( ge->cy.computed - s[Geom::Y] );
+ ge->ry = fabs( ge->cy.computed - s[Geom::Y] );
if ( state & GDK_CONTROL_MASK ) {
- ge->rx.computed = ge->ry.computed;
+ ge->rx = ge->ry.computed;
}
item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
@@ -966,7 +966,7 @@ ArcKnotHolderEntityRY::knot_click(unsigned int state)
g_assert(ge != NULL);
if (state & GDK_CONTROL_MASK) {
- ge->rx.computed = ge->ry.computed;
+ ge->rx = ge->ry.computed;
ge->updateRepr();
}
}
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));
diff --git a/src/ui/widget/page-sizer.cpp b/src/ui/widget/page-sizer.cpp
index afece6df2..8e647ebb4 100644
--- a/src/ui/widget/page-sizer.cpp
+++ b/src/ui/widget/page-sizer.cpp
@@ -784,7 +784,6 @@ PageSizer::updateScaleUI()
_scaleLabel.set_text( "Unknown scale" );
}
- sleep( 0.1 );
_changeds_connection.unblock();
_called = false;