summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2015-04-09 18:54:52 +0000
committerJabiertxof <jtx@jtx.marker.es>2015-04-09 18:54:52 +0000
commit42569eeea6a78406c723a0c2139a6adbb5f9c9cc (patch)
tree480aff49241ce0c5b30837bf8bd6137e0a9f2789 /src
parentupdate to trunk (diff)
parentCleaned up cmake files to build successfully on Linux. (diff)
downloadinkscape-42569eeea6a78406c723a0c2139a6adbb5f9c9cc.tar.gz
inkscape-42569eeea6a78406c723a0c2139a6adbb5f9c9cc.zip
update to trunk
(bzr r12588.1.40)
Diffstat (limited to 'src')
-rw-r--r--src/2geom/line.h17
-rw-r--r--src/CMakeLists.txt44
-rw-r--r--src/document.cpp11
-rw-r--r--src/document.h1
-rw-r--r--src/helper/CMakeLists.txt2
-rw-r--r--src/helper/Makefile_insert2
-rw-r--r--src/helper/geom-pathstroke.cpp770
-rw-r--r--src/helper/geom-pathstroke.h58
-rw-r--r--src/inkgc/CMakeLists.txt5
-rw-r--r--src/livarot/ShapeMisc.cpp8
-rw-r--r--src/live_effects/CMakeLists.txt51
-rw-r--r--src/live_effects/Makefile_insert2
-rw-r--r--src/live_effects/lpe-bspline.cpp50
-rw-r--r--src/live_effects/lpe-bspline.h3
-rw-r--r--src/live_effects/lpe-jointype.cpp129
-rw-r--r--src/live_effects/lpe-jointype.h5
-rw-r--r--src/live_effects/lpe-perspective-envelope.cpp12
-rw-r--r--src/live_effects/lpe-powerstroke.cpp33
-rw-r--r--src/live_effects/lpe-taperstroke.cpp204
-rw-r--r--src/live_effects/pathoutlineprovider.cpp803
-rw-r--r--src/live_effects/pathoutlineprovider.h55
-rw-r--r--src/svg-profile.h2
-rw-r--r--src/trace/potrace/auxiliary.h31
-rw-r--r--src/trace/potrace/bitmap.h33
-rw-r--r--src/trace/potrace/bitops.h83
-rw-r--r--src/trace/potrace/curve.cpp26
-rw-r--r--src/trace/potrace/curve.h2
-rw-r--r--src/trace/potrace/decompose.cpp29
-rw-r--r--src/trace/potrace/decompose.h2
-rw-r--r--src/trace/potrace/greymap.cpp61
-rw-r--r--src/trace/potrace/greymap.h5
-rw-r--r--src/trace/potrace/lists.h2
-rw-r--r--src/trace/potrace/potracelib.cpp2
-rw-r--r--src/trace/potrace/potracelib.h2
-rw-r--r--src/trace/potrace/progress.h2
-rw-r--r--src/trace/potrace/render.cpp4
-rw-r--r--src/trace/potrace/render.h2
-rw-r--r--src/trace/potrace/trace.cpp66
-rw-r--r--src/trace/potrace/trace.h2
-rw-r--r--src/ui/CMakeLists.txt29
-rw-r--r--src/ui/dialog/filter-effects-dialog.cpp2
-rw-r--r--src/ui/tool/curve-drag-point.cpp4
-rw-r--r--src/ui/tool/multi-path-manipulator.h2
-rw-r--r--src/ui/tool/node.cpp15
-rw-r--r--src/ui/tool/path-manipulator.cpp44
-rw-r--r--src/ui/tool/path-manipulator.h2
-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.cpp169
-rw-r--r--src/ui/widget/page-sizer.h21
-rw-r--r--src/uri-references.cpp2
56 files changed, 1553 insertions, 1374 deletions
diff --git a/src/2geom/line.h b/src/2geom/line.h
index ade67f818..cbd68fa08 100644
--- a/src/2geom/line.h
+++ b/src/2geom/line.h
@@ -35,6 +35,7 @@
#define LIB2GEOM_SEEN_LINE_H
#include <cmath>
+#include <iostream>
#include <boost/optional.hpp>
#include <2geom/bezier-curve.h> // for LineSegment
#include <2geom/rect.h>
@@ -258,9 +259,19 @@ public:
dist = -dot(n, m_origin);
return n;
}
- /// @}
+
+ friend inline std::ostream &operator<< (std::ostream &out_file, const Geom::Line &in_line);
+/// @}
}; // end class Line
+/** @brief Output operator for lines.
+ * Prints out representation (point + versor)
+ */
+inline std::ostream &operator<< (std::ostream &out_file, const Geom::Line &in_line) {
+ out_file << "X: " << in_line.m_origin[X] << " Y: " << in_line.m_origin[Y]
+ << " dX: " << in_line.m_versor[X] << " dY: " << in_line.m_versor[Y];
+ return out_file;
+}
inline
double distance(Point const& _point, Line const& _line)
@@ -365,6 +376,10 @@ inline
Line make_angle_bisector_line(Point const& A, Point const& O, Point const& B)
{
Point M = middle_point(A,B);
+ if (are_near(O,M)) {
+ Line l(A,B);
+ M += (make_orthogonal_line(O,l)).versor();
+ }
return Line(O,M);
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6659e8c0a..27c5e49db 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,3 @@
-
# -----------------------------------------------------------------------------
# Define the main source
# -----------------------------------------------------------------------------
@@ -33,8 +32,8 @@ set(sp_SRC
sp-gradient-reference.cpp
sp-gradient.cpp
sp-guide.cpp
- sp-hatch.cpp
sp-hatch-path.cpp
+ sp-hatch.cpp
sp-image.cpp
sp-item-group.cpp
sp-item-notify-moveto.cpp
@@ -47,10 +46,10 @@ set(sp_SRC
sp-lpe-item.cpp
sp-marker.cpp
sp-mask.cpp
- sp-mesh.cpp
sp-mesh-array.cpp
sp-mesh-patch.cpp
sp-mesh-row.cpp
+ sp-mesh.cpp
sp-metadata.cpp
sp-missing-glyph.cpp
sp-namedview.cpp
@@ -75,6 +74,9 @@ set(sp_SRC
sp-style-elem.cpp
sp-switch.cpp
sp-symbol.cpp
+ sp-tag-use-reference.cpp
+ sp-tag-use.cpp
+ sp-tag.cpp
sp-text.cpp
sp-title.cpp
sp-tref-reference.cpp
@@ -119,8 +121,8 @@ set(sp_SRC
sp-guide-attachment.h
sp-guide-constraint.h
sp-guide.h
- sp-hatch.h
sp-hatch-path.h
+ sp-hatch.h
sp-image.h
sp-item-group.h
sp-item-notify-moveto.h
@@ -131,13 +133,13 @@ set(sp_SRC
sp-line.h
sp-linear-gradient.h
sp-lpe-item.h
- sp-marker.h
sp-marker-loc.h
+ sp-marker.h
sp-mask.h
- sp-mesh.h
sp-mesh-array.h
sp-mesh-patch.h
sp-mesh-row.h
+ sp-mesh.h
sp-metadata.h
sp-missing-glyph.h
sp-namedview.h
@@ -203,21 +205,17 @@ set(inkscape_SRC
filter-enums.cpp
gc-anchored.cpp
gc-finalized.cpp
- gc.cpp
gradient-chemistry.cpp
gradient-drag.cpp
graphlayout.cpp
guide-snapper.cpp
help.cpp
id-clash.cpp
- # ige-mac-menu.c
inkscape.cpp
- inkscape.rc
- interface.cpp
knot-holder-entity.cpp
+ knot-ptr.cpp
knot.cpp
knotholder.cpp
- knot-ptr.cpp
layer-fns.cpp
layer-manager.cpp
layer-model.cpp
@@ -257,8 +255,8 @@ set(inkscape_SRC
snapped-line.cpp
snapped-point.cpp
snapper.cpp
- style.cpp
style-internal.cpp
+ style.cpp
svg-view-widget.cpp
svg-view.cpp
text-chemistry.cpp
@@ -313,18 +311,12 @@ set(inkscape_SRC
event.h
extract-uri-test.h
extract-uri.h
- factory.h
file.h
fill-or-stroke.h
filter-chemistry.h
filter-enums.h
- gc-alloc.h
- gc-allocator.h
gc-anchored.h
- gc-core.h
gc-finalized.h
- gc-managed.h
- gc-soft-ptr.h
gradient-chemistry.h
gradient-drag.h
graphlayout.h
@@ -333,16 +325,14 @@ set(inkscape_SRC
helper-fns.h
icon-size.h
id-clash.h
- # ige-mac-menu.h
inkscape-version.h
inkscape.h
- interface.h
isinf.h
knot-enums.h
knot-holder-entity.h
+ knot-ptr.h
knot.h
knotholder.h
- knot-ptr.h
layer-fns.h
layer-manager.h
layer-model.h
@@ -351,7 +341,6 @@ set(inkscape_SRC
macros.h
main-cmdlineact.h
marker-test.h
- marker.h
media.h
menus-skeleton.h
message-context.h
@@ -376,7 +365,6 @@ set(inkscape_SRC
profile-manager.h
proj_pt.h
rdf.h
- registrytool.h
remove-last.h
removeoverlap.h
require-config.h
@@ -403,10 +391,10 @@ set(inkscape_SRC
splivarot.h
streq.h
strneq.h
- style-test.h
- style.h
style-enums.h
style-internal.h
+ style-test.h
+ style.h
svg-profile.h
svg-view-widget.h
svg-view.h
@@ -430,8 +418,10 @@ set(inkscape_SRC
if(WIN32)
list(APPEND inkscape_SRC
+ inkscape.rc
registrytool.cpp
#deptool.cpp
+ winconsole.cpp
winmain.cpp
)
endif()
@@ -471,7 +461,6 @@ list(APPEND inkscape_SRC
# All folders for internal inkscape
# these call add_inkscape_source
add_subdirectory(debug)
-add_subdirectory(dialogs)
add_subdirectory(display)
add_subdirectory(extension)
add_subdirectory(filters)
@@ -545,6 +534,8 @@ target_link_libraries(inkscape
uemf_LIB
2geom_LIB
depixelize_LIB
+ util_LIB
+ gc_LIB
${INKSCAPE_LIBS}
)
@@ -553,4 +544,3 @@ target_link_libraries(inkscape
# make executable for INKVIEW
#add_executable(inkview inkview.cpp)
# ...
-
diff --git a/src/document.cpp b/src/document.cpp
index 62e2f5b46..1c6bb76de 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -764,6 +764,17 @@ void SPDocument::setHeight(const Inkscape::Util::Quantity &height, bool changeSi
root->updateRepr();
}
+Geom::Rect SPDocument::getViewBox() const
+{
+ Geom::Rect viewBox;
+ if (root->viewBox_set) {
+ viewBox = root->viewBox;
+ } else {
+ viewBox = Geom::Rect::from_xywh( 0, 0, getWidth().value("px"), getHeight().value("px"));
+ }
+ return viewBox;
+}
+
void SPDocument::setViewBox(const Geom::Rect &viewBox)
{
root->viewBox_set = true;
diff --git a/src/document.h b/src/document.h
index ed19d123b..74dcfa75e 100644
--- a/src/document.h
+++ b/src/document.h
@@ -247,6 +247,7 @@ public:
Geom::Scale getDocumentScale() const;
Inkscape::Util::Quantity getWidth() const;
Inkscape::Util::Quantity getHeight() const;
+ Geom::Rect getViewBox() const;
Geom::Point getDimensions() const;
Geom::OptRect preferredBounds() const;
void setWidthAndHeight(const Inkscape::Util::Quantity &width, const Inkscape::Util::Quantity &height, bool changeSize=true);
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..eb0c432c6
--- /dev/null
+++ b/src/helper/geom-pathstroke.cpp
@@ -0,0 +1,770 @@
+/* Author:
+ * Liam P. White
+ *
+ * Copyright (C) 2014-2015 Author
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <iomanip>
+#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 <2geom/path-intersection.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.ray();
+ 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)
+{
+ 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 {
+
+// 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*/)
+{
+ res.appendNew<Geom::LineSegment>(outgoing.initialPoint());
+ res.append(outgoing);
+}
+
+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());
+ res.append(outgoing);
+}
+
+void miter_join_internal(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width, 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);
+
+ 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;
+ if (satisfied) {
+ // miter OK, check to see if we can do a relocation
+ if (inc_ls) {
+ res.setFinal(p);
+ } else {
+ res.appendNew<Geom::LineSegment>(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;
+
+ 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());
+
+ if (inc_ls) {
+ res.setFinal(p1);
+ } else {
+ res.appendNew<Geom::LineSegment>(p1);
+ }
+ res.appendNew<Geom::LineSegment>(p2);
+ }
+ }
+
+ res.appendNew<Geom::LineSegment>(outgoing.initialPoint());
+
+ // check if we can do another relocation
+ bool out_ls = outgoing.degreesOfFreedom() <= 4;
+
+ 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 );
+}
+
+void miter_clip_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) {
+ miter_join_internal( res, outgoing, miter, width, true );
+}
+
+Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point endPt)
+{
+ Geom::Point sol;
+ 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];
+ }
+ return sol;
+}
+
+void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width)
+{
+ using namespace Geom;
+
+ Geom::Curve const& incoming = res.back();
+ 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::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
+ Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0);
+
+ bool inc_ls = !circle1.center().isFinite();
+ bool out_ls = !circle2.center().isFinite();
+
+ Geom::Point points[2];
+
+ int solutions = 0;
+ Geom::EllipticalArc *arc1 = NULL;
+ Geom::EllipticalArc *arc2 = NULL;
+ Geom::Point sol;
+ Geom::Point p1;
+ Geom::Point p2;
+
+ if (!inc_ls && !out_ls) {
+ // Two circles
+ solutions = Geom::circle_circle_intersection(circle1.center(), circle1.ray(),
+ circle2.center(), circle2.ray(),
+ points[0], points[1]);
+ if (solutions == 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);
+ }
+ } 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) {
+ sol = pick_solution(points, tang2, endPt);
+ arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true);
+ }
+ } 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) {
+ sol = pick_solution(points, tang2, endPt);
+ arc1 = circle1.arc(startPt, 0.5*(sol+startPt), sol, true);
+ }
+ }
+
+ if (solutions != 2)
+ // no solutions available, fall back to miter
+ return miter_clip_join(res, outgoing, miter, width);
+
+ // We have a solution, thus sol is defined.
+ p1 = sol;
+
+ // See if we need to clip. Miter length is measured along a circular arc that is tangent to the
+ // bisector of the incoming and out going angles and passes through the end point (sol) of the
+ // line join.
+
+ // Center of circle is intersection of a line orthogonal to bisector and a line bisecting
+ // a chord connecting the path end point (point_on_path) and the join end point (sol).
+ Geom::Point point_on_path = startPt + Geom::rot90(tang1)*width;
+ Geom::Line bisector = make_angle_bisector_line(startPt, point_on_path, endPt);
+ Geom::Line ortho = make_orthogonal_line(point_on_path, bisector);
+
+ Geom::LineSegment chord(point_on_path, sol);
+ Geom::Line bisector_chord = make_bisector_line(chord);
+
+ Geom::Line limit_line;
+ double miter_limit = 2.0 * width * miter;
+ bool clipped = false;
+
+ if (are_parallel(bisector_chord, ortho)) {
+ // No intersection (can happen if curvatures are equal but opposite)
+ if (Geom::distance(point_on_path, sol) > miter_limit) {
+ clipped = true;
+ Geom::Point limit_point = point_on_path + miter_limit * bisector.versor();
+ limit_line = make_parallel_line( limit_point, ortho );
+ }
+ } else {
+ Geom::Point center =
+ Geom::intersection_point( bisector_chord.pointAt(0), bisector_chord.versor(),
+ ortho.pointAt(0), ortho.versor() );
+ Geom::Coord radius = distance(center, point_on_path);
+ Geom::Circle circle_center(center, radius);
+
+ double limit_angle = miter_limit / radius;
+
+ Geom::Ray start_ray(center, point_on_path);
+ 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) {
+ limit_line.setAngle(start_ray.angle() - limit_angle);
+ } else {
+ 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);
+ 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) {
+ p1 = pick_solution(points, tang2, endPt);
+ delete arc1;
+ arc1 = circle1.arc(startPt, 0.5*(p1+startPt), p1, true);
+ }
+ } else {
+ p1 = Geom::intersection_point(startPt, tang1, limit_line.pointAt(0), limit_line.versor());
+ }
+
+ 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) {
+ p2 = pick_solution(points, tang1, endPt);
+ delete arc2;
+ arc2 = circle2.arc(p2, 0.5*(p2+endPt), endPt, true);
+ }
+ } else {
+ p2 = Geom::intersection_point(endPt, tang2, limit_line.pointAt(0), limit_line.versor());
+ }
+ }
+ }
+
+ // Add initial
+ if (arc1) {
+ res.append(*arc1);
+ } else {
+ // Straight line segment: move last point
+ res.setFinal(p1);
+ }
+
+ if (clipped) {
+ res.appendNew<Geom::LineSegment>(p2);
+ }
+
+ // Add outgoing
+ if (arc2) {
+ res.append(*arc2);
+ res.append(outgoing);
+ } else {
+ // Straight line segment:
+ res.appendNew<Geom::LineSegment>(outgoing.finalPoint());
+ }
+
+ delete arc1;
+ delete arc2;
+}
+
+void join_inside(Geom::Path& res, Geom::Curve const& outgoing)
+{
+ Geom::Curve const& incoming = res.back_open();
+ 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;
+ } else {
+ res.appendNew<Geom::LineSegment>(outgoing.initialPoint());
+ res.append(outgoing);
+ }
+}
+
+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);
+}
+
+void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, bool on_outside, double miter, Inkscape::LineJoinType join)
+{
+ if (res.size() == 0 || to_add.size() == 0)
+ return;
+
+ Geom::Curve const& outgoing = to_add[0];
+ 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);
+ return;
+ }
+
+ 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(res, outgoing, miter, width);
+ } else {
+ join_inside(res, outgoing);
+ }
+}
+
+// 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[2]);
+ offset_cubic(p, cub, width, tol, levels);
+}
+
+void offset_curve(Geom::Path& res, Geom::Curve const* current, double width)
+{
+ double const tolerance = 0.005;
+ size_t levels = 8;
+
+ if (current->isDegenerate()) return; // don't do anything
+
+ // 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(), tolerance);
+ 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);
+ }
+}
+
+typedef void cap_func(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path const& against_dir, double width);
+
+void flat_cap(Geom::PathBuilder& res, Geom::Path const&, Geom::Path const& against_dir, double)
+{
+ res.lineTo(against_dir.initialPoint());
+}
+
+void round_cap(Geom::PathBuilder& res, Geom::Path const&, Geom::Path const& against_dir, double width)
+{
+ res.arcTo(width / 2., width / 2., 0., true, false, against_dir.initialPoint());
+}
+
+void square_cap(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path const& against_dir, double width)
+{
+ width /= 2.;
+ Geom::Point normal_1 = -Geom::unitTangentAt(Geom::reverse(with_dir.back().toSBasis()), 0.);
+ Geom::Point normal_2 = -against_dir[0].unitTangentAt(0.);
+ res.lineTo(with_dir.finalPoint() + normal_1*width);
+ res.lineTo(against_dir.initialPoint() + normal_2*width);
+ res.lineTo(against_dir.initialPoint());
+}
+
+void peak_cap(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path const& against_dir, double width)
+{
+ width /= 2.;
+ Geom::Point normal_1 = -Geom::unitTangentAt(Geom::reverse(with_dir.back().toSBasis()), 0.);
+ Geom::Point normal_2 = -against_dir[0].unitTangentAt(0.);
+ Geom::Point midpoint = ((with_dir.finalPoint() + normal_1*width) + (against_dir.initialPoint() + normal_2*width)) * 0.5;
+ res.lineTo(midpoint);
+ res.lineTo(against_dir.initialPoint());
+}
+
+} // namespace
+
+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);
+
+ cap_func *cf;
+ switch (butt) {
+ case BUTT_ROUND:
+ cf = &round_cap;
+ break;
+ case BUTT_SQUARE:
+ cf = &square_cap;
+ break;
+ case BUTT_PEAK:
+ cf = &peak_cap;
+ break;
+ default:
+ cf = &flat_cap;
+ }
+
+ // glue caps
+ if (!input.closed()) {
+ cf(res, with_dir, against_dir, width);
+ } else {
+ res.closePath();
+ res.moveTo(against_dir.initialPoint());
+ }
+
+ res.append(against_dir);
+
+ if (!input.closed()) {
+ cf(res, against_dir, with_dir, width);
+ }
+
+ 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.back_closed().isDegenerate() && input.closed())
+ ?input.size_default()-1:input.size_default();
+ 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 {
+ 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());
+ }
+
+ // 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());
+ }
+ }
+
+ if (input.closed()) {
+ Geom::Curve const &c1 = res.back();
+ Geom::Curve const &c2 = res.front();
+ temp = Geom::Path();
+ 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);
+ res.erase(res.begin());
+ res.erase_last();
+ //
+ 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..0cfb9f817
--- /dev/null
+++ b/src/helper/geom-pathstroke.h
@@ -0,0 +1,58 @@
+#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_MITER_CLIP,
+ 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_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE.
+ * @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/inkgc/CMakeLists.txt b/src/inkgc/CMakeLists.txt
index 22dd464e1..a4b96d5ee 100644
--- a/src/inkgc/CMakeLists.txt
+++ b/src/inkgc/CMakeLists.txt
@@ -1,11 +1,10 @@
-
set(libgc_SRC
gc.cpp
-
+
# -------
# Headers
gc-alloc.h
- gc-anchored.h
+ ../gc-anchored.h
gc-core.h
gc-managed.h
gc-soft-ptr.h
diff --git a/src/livarot/ShapeMisc.cpp b/src/livarot/ShapeMisc.cpp
index c0bfe9428..4f63007e7 100644
--- a/src/livarot/ShapeMisc.cpp
+++ b/src/livarot/ShapeMisc.cpp
@@ -371,9 +371,9 @@ Shape::ConvertToFormeNested (Path * dest, int nbP, Path * *orig, int /*wildPath*
int searchInd = 0;
int lastPtUsed = 0;
+ int parentContour=-1;
do
{
- int parentContour=-1;
int childEdge = -1;
bool foundChild = false;
int startBord = -1;
@@ -389,8 +389,10 @@ Shape::ConvertToFormeNested (Path * dest, int nbP, Path * *orig, int /*wildPath*
if (askTo < 0 || askTo >= numberOfEdges() ) {
parentContour=-1;
} else {
- parentContour = GPOINTER_TO_INT(swdData[askTo].misc);
- parentContour-=1; // pour compenser le decalage
+ if (getEdge(askTo).prevS >= 0) {
+ parentContour = GPOINTER_TO_INT(swdData[askTo].misc);
+ parentContour-=1; // pour compenser le decalage
+ }
childEdge = getPoint(fi).incidentEdge[FIRST];
}
}
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt
index c8a02c810..c4b92e579 100644
--- a/src/live_effects/CMakeLists.txt
+++ b/src/live_effects/CMakeLists.txt
@@ -1,4 +1,3 @@
-
set(live_effects_SRC
effect.cpp
lpe-angle_bisector.cpp
@@ -6,6 +5,7 @@ set(live_effects_SRC
lpe-bendpath.cpp
lpe-boolops.cpp
lpe-bounding-box.cpp
+ lpe-bspline.cpp
lpe-circle_3pts.cpp
lpe-circle_with_radius.cpp
lpe-clone-original.cpp
@@ -13,7 +13,7 @@ set(live_effects_SRC
lpe-copy_rotate.cpp
lpe-curvestitch.cpp
lpe-dynastroke.cpp
- lpe-ellipse-5pts.cpp
+ lpe-ellipse_5pts.cpp
lpe-envelope.cpp
lpe-extrude.cpp
lpe-fill-between-many.cpp
@@ -21,8 +21,11 @@ set(live_effects_SRC
lpe-fillet-chamfer.cpp
lpe-gears.cpp
lpe-interpolate.cpp
+ lpe-interpolate_points.cpp
+ lpe-jointype.cpp
lpe-knot.cpp
lpe-lattice.cpp
+ lpe-lattice2.cpp
lpe-line_segment.cpp
lpe-mirror_symmetry.cpp
lpe-offset.cpp
@@ -30,43 +33,43 @@ set(live_effects_SRC
lpe-path_length.cpp
lpe-patternalongpath.cpp
lpe-perp_bisector.cpp
- lpe-perspective_path.cpp
lpe-perspective-envelope.cpp
+ lpe-perspective_path.cpp
lpe-powerstroke.cpp
lpe-recursiveskeleton.cpp
lpe-rough-hatches.cpp
+ lpe-roughen.cpp
lpe-ruler.cpp
lpe-show_handles.cpp
lpe-simplify.cpp
- # lpe-skeleton.cpp
+ lpe-skeleton.cpp
lpe-sketch.cpp
lpe-spiro.cpp
- lpe-roughen.cpp
lpe-tangent_to_curve.cpp
+ lpe-taperstroke.cpp
lpe-test-doEffect-stack.cpp
- lpe-bspline.cpp
lpe-text_label.cpp
- lpe-vonkoch.cpp
lpegroupbbox.cpp
lpeobject-reference.cpp
+ lpe-vonkoch.cpp
lpeobject.cpp
- spiro.cpp
spiro-converters.cpp
+ spiro.cpp
parameter/array.cpp
parameter/bool.cpp
parameter/filletchamferpointarray.cpp
- parameter/parameter.cpp
- parameter/path.cpp
parameter/originalpath.cpp
parameter/originalpatharray.cpp
+ parameter/parameter.cpp
parameter/path-reference.cpp
+ parameter/path.cpp
parameter/point.cpp
parameter/powerstrokepointarray.cpp
parameter/random.cpp
parameter/text.cpp
- paramter/transformedpoint.cpp
parameter/togglebutton.cpp
+ parameter/transformedpoint.cpp
parameter/unit.cpp
parameter/vector.cpp
@@ -80,6 +83,7 @@ set(live_effects_SRC
lpe-bendpath.h
lpe-boolops.h
lpe-bounding-box.h
+ lpe-bspline.h
lpe-circle_3pts.h
lpe-circle_with_radius.h
lpe-clone-original.h
@@ -87,7 +91,7 @@ set(live_effects_SRC
lpe-copy_rotate.h
lpe-curvestitch.h
lpe-dynastroke.h
- lpe-ellipse-5pts.h
+ lpe-ellipse_5pts.h
lpe-envelope.h
lpe-extrude.h
lpe-fill-between-many.h
@@ -95,8 +99,11 @@ set(live_effects_SRC
lpe-fillet-chamfer.h
lpe-gears.h
lpe-interpolate.h
+ lpe-interpolate_points.h
+ lpe-jointype.h
lpe-knot.h
lpe-lattice.h
+ lpe-lattice2.h
lpe-line_segment.h
lpe-mirror_symmetry.h
lpe-offset.h
@@ -104,47 +111,47 @@ set(live_effects_SRC
lpe-path_length.h
lpe-patternalongpath.h
lpe-perp_bisector.h
- lpe-perspective_path.h
lpe-perspective-envelope.h
- lpe-powerstroke.h
+ lpe-perspective_path.h
lpe-powerstroke-interpolators.h
+ lpe-powerstroke.h
lpe-recursiveskeleton.h
lpe-rough-hatches.h
+ lpe-roughen.h
lpe-ruler.h
- lpe-simplify.h
lpe-show_handles.h
+ lpe-simplify.h
lpe-skeleton.h
lpe-sketch.h
lpe-spiro.h
- lpe-roughen.h
lpe-tangent_to_curve.h
+ lpe-taperstroke.h
lpe-test-doEffect-stack.h
- lpe-bspline.h
lpe-text_label.h
lpe-vonkoch.h
lpegroupbbox.h
lpeobject-reference.h
lpeobject.h
- spiro.h
spiro-converters.h
+ spiro.h
parameter/array.h
parameter/bool.h
- parameter/filletchamferpointarray.h
parameter/enum.h
+ parameter/filletchamferpointarray.h
+ parameter/originalpath.h
+ parameter/originalpatharray.h
parameter/parameter.h
parameter/path-reference.h
parameter/path.h
- parameter/originalpath.h
- parameter/originalpatharray.h
parameter/point.h
parameter/powerstrokepointarray.h
parameter/random.h
parameter/text.h
parameter/togglebutton.h
+ parameter/transformedpoint.h
parameter/unit.h
parameter/vector.h
-
)
# add_inkscape_lib(live_effects_LIB "${live_effects_SRC}")
diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert
index 8f0a3ac57..dace45739 100644
--- a/src/live_effects/Makefile_insert
+++ b/src/live_effects/Makefile_insert
@@ -109,8 +109,6 @@ ink_common_sources += \
live_effects/lpe-fill-between-many.h \
live_effects/lpe-ellipse_5pts.cpp \
live_effects/lpe-ellipse_5pts.h \
- live_effects/pathoutlineprovider.cpp \
- live_effects/pathoutlineprovider.h \
live_effects/lpe-jointype.cpp \
live_effects/lpe-jointype.h \
live_effects/lpe-taperstroke.cpp \
diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp
index b924d8a23..5d5a6e616 100644
--- a/src/live_effects/lpe-bspline.cpp
+++ b/src/live_effects/lpe-bspline.cpp
@@ -1,48 +1,16 @@
/*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include <gtkmm.h>
-
-#if WITH_GLIBMM_2_32
-# include <glibmm/threads.h>
-#endif
-
-#include <glib.h>
-#include <glibmm/i18n.h>
-
-
-#include "display/curve.h"
-#include <2geom/bezier-curve.h>
-#include <2geom/point.h>
-#include "helper/geom-curves.h"
#include "live_effects/lpe-bspline.h"
-#include "live_effects/lpeobject.h"
-#include "live_effects/parameter/parameter.h"
#include "ui/widget/scalar.h"
-#include "xml/repr.h"
-#include "svg/svg.h"
+#include "display/curve.h"
+#include "helper/geom-curves.h"
#include "sp-path.h"
-#include "style.h"
-#include "document-private.h"
-#include "document.h"
-#include "document-undo.h"
-#include "verbs.h"
-#include "sp-lpe-item.h"
-#include "sp-namedview.h"
-#include "display/sp-canvas.h"
-#include <typeinfo>
-#include <vector>
-#include "util/units.h"
-// For handling un-continuous paths:
-#include "message-stack.h"
-#include "inkscape.h"
-
-using Inkscape::DocumentUndo;
+#include "svg/svg.h"
+#include "xml/repr.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -106,13 +74,15 @@ void LPEBSpline::doEffect(SPCurve *curve)
}
// Make copy of old path as it is changed during processing
Geom::PathVector const original_pathv = curve->get_pathvector();
+
curve->reset();
for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
path_it != original_pathv.end(); ++path_it) {
- if (path_it->empty())
+ if (path_it->empty()){
continue;
-
+ }
+ hp.push_back(*path_it);
Geom::Path::const_iterator curve_it1 = path_it->begin();
Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
Geom::Path::const_iterator curve_endit = path_it->end_default();
diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h
index 642562b24..8017e39ef 100644
--- a/src/live_effects/lpe-bspline.h
+++ b/src/live_effects/lpe-bspline.h
@@ -6,9 +6,8 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
#include "live_effects/effect.h"
-#include "live_effects/parameter/bool.h"
+
#include <vector>
namespace Inkscape {
diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp
index bf2526986..0111a0f99 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,19 @@ 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_MITER_CLIP, N_("Miter Clip"), "miter-clip"},
+ {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 +50,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 +60,16 @@ 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()
@@ -87,38 +86,30 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem)
double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.;
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (true) {
- if (lpeitem->style->stroke.isPaintserver()) {
- SPPaintServer * server = lpeitem->style->getStrokePaintServer();
- if (server) {
- Glib::ustring str;
- str += "url(#";
- str += server->getId();
- str += ")";
- sp_repr_css_set_property (css, "fill", str.c_str());
- }
- } else if (lpeitem->style->stroke.isColor()) {
- gchar c[64];
- sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value)));
- sp_repr_css_set_property (css, "fill", c);
- } else {
- sp_repr_css_set_property (css, "fill", "none");
+ if (lpeitem->style->stroke.isPaintserver()) {
+ SPPaintServer * server = lpeitem->style->getStrokePaintServer();
+ if (server) {
+ Glib::ustring str;
+ str += "url(#";
+ str += server->getId();
+ str += ")";
+ sp_repr_css_set_property (css, "fill", str.c_str());
}
+ } else if (lpeitem->style->stroke.isColor()) {
+ gchar c[64];
+ sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value)));
+ sp_repr_css_set_property (css, "fill", c);
} else {
- sp_repr_css_unset_property (css, "fill");
+ sp_repr_css_set_property (css, "fill", "none");
}
+ sp_repr_css_set_property(css, "fill-rule", "nonzero");
sp_repr_css_set_property(css, "stroke", "none");
sp_desktop_apply_css_recursive(item, css, true);
sp_repr_css_attr_unref (css);
- if (!was_initialized)
- {
- was_initialized = true;
- line_width.param_set_value(width);
- }
- } else {
- g_warning("LPE Join Type can only be applied to paths (not groups).");
+
+ line_width.param_set_value(width);
}
}
@@ -126,30 +117,25 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem)
void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem)
{
-
if (SP_IS_SHAPE(lpeitem)) {
SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem);
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (true) {
- if (lpeitem->style->fill.isPaintserver()) {
- SPPaintServer * server = lpeitem->style->getFillPaintServer();
- if (server) {
- Glib::ustring str;
- str += "url(#";
- str += server->getId();
- str += ")";
- sp_repr_css_set_property (css, "stroke", str.c_str());
- }
- } else if (lpeitem->style->fill.isColor()) {
- gchar c[64];
- sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value)));
- sp_repr_css_set_property (css, "stroke", c);
- } else {
- sp_repr_css_set_property (css, "stroke", "none");
+ if (lpeitem->style->fill.isPaintserver()) {
+ SPPaintServer * server = lpeitem->style->getFillPaintServer();
+ if (server) {
+ Glib::ustring str;
+ str += "url(#";
+ str += server->getId();
+ str += ")";
+ sp_repr_css_set_property (css, "stroke", str.c_str());
}
+ } else if (lpeitem->style->fill.isColor()) {
+ gchar c[64];
+ sp_svg_write_color (c, sizeof(c), lpeitem->style->fill.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->fill_opacity.value)));
+ sp_repr_css_set_property (css, "stroke", c);
} else {
- sp_repr_css_unset_property (css, "stroke");
+ sp_repr_css_set_property (css, "stroke", "none");
}
Inkscape::CSSOStringStream os;
@@ -164,15 +150,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..bca0961c9 100644
--- a/src/live_effects/lpe-jointype.h
+++ b/src/live_effects/lpe-jointype.h
@@ -33,11 +33,10 @@ 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;
};
} //namespace LivePathEffect
diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp
index d60a13c23..b5885bdb3 100644
--- a/src/live_effects/lpe-perspective-envelope.cpp
+++ b/src/live_effects/lpe-perspective-envelope.cpp
@@ -48,11 +48,11 @@ LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject)
Down_Right_Point(_("Down Right"), _("Down Right - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "Down_Right_Point", &wr, this)
{
// register all your parameters here, so Inkscape knows which parameters this effect has:
- registerParameter( dynamic_cast<Parameter *>(&deform_type));
- registerParameter( dynamic_cast<Parameter *>(&Up_Left_Point) );
- registerParameter( dynamic_cast<Parameter *>(&Up_Right_Point) );
- registerParameter( dynamic_cast<Parameter *>(&Down_Left_Point) );
- registerParameter( dynamic_cast<Parameter *>(&Down_Right_Point) );
+ registerParameter(&deform_type);
+ registerParameter(&Up_Left_Point);
+ registerParameter(&Up_Right_Point);
+ registerParameter(&Down_Left_Point);
+ registerParameter(&Down_Right_Point);
}
LPEPerspectiveEnvelope::~LPEPerspectiveEnvelope()
@@ -340,8 +340,8 @@ LPEPerspectiveEnvelope::resetDefaults(SPItem const* item)
{
Effect::resetDefaults(item);
original_bbox(SP_LPE_ITEM(item));
- resetGrid();
setDefaults();
+ resetGrid();
}
void
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index f7fe9592d..5d9d224e8 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -297,7 +297,8 @@ LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem)
} else {
sp_repr_css_unset_property (css, "fill");
}
-
+
+ sp_repr_css_set_property(css, "fill-rule", "nonzero");
sp_repr_css_set_property(css, "stroke", "none");
sp_desktop_apply_css_recursive(item, css, true);
@@ -330,25 +331,21 @@ void LPEPowerStroke::doOnRemove(SPLPEItem const* lpeitem)
if (SP_IS_SHAPE(lpeitem)) {
SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem);
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (true) {
- if (lpeitem->style->fill.isPaintserver()) {
- SPPaintServer * server = lpeitem->style->getFillPaintServer();
- if (server) {
- Glib::ustring str;
- str += "url(#";
- str += server->getId();
- str += ")";
- sp_repr_css_set_property (css, "stroke", str.c_str());
- }
- } else if (lpeitem->style->fill.isColor()) {
- gchar c[64];
- sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value)));
- sp_repr_css_set_property (css, "stroke", c);
- } else {
- sp_repr_css_set_property (css, "stroke", "none");
+ if (lpeitem->style->fill.isPaintserver()) {
+ SPPaintServer * server = lpeitem->style->getFillPaintServer();
+ if (server) {
+ Glib::ustring str;
+ str += "url(#";
+ str += server->getId();
+ str += ")";
+ sp_repr_css_set_property (css, "stroke", str.c_str());
}
+ } else if (lpeitem->style->fill.isColor()) {
+ char c[64] = {0};
+ sp_svg_write_color (c, sizeof(c), lpeitem->style->fill.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->fill_opacity.value)));
+ sp_repr_css_set_property (css, "stroke", c);
} else {
- sp_repr_css_unset_property (css, "stroke");
+ sp_repr_css_set_property (css, "stroke", "none");
}
Inkscape::CSSOStringStream os;
diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp
index 7a024147c..2c74af6d6 100644
--- a/src/live_effects/lpe-taperstroke.cpp
+++ b/src/live_effects/lpe-taperstroke.cpp
@@ -19,7 +19,8 @@
#include <2geom/circle.h>
#include <2geom/sbasis-to-bezier.h>
-#include "pathoutlineprovider.h"
+#include "helper/geom-nodetype.h"
+#include "helper/geom-pathstroke.h"
#include "display/curve.h"
#include "sp-shape.h"
#include "style.h"
@@ -60,11 +61,10 @@ namespace TpS {
} // TpS
static const Util::EnumData<unsigned> JoinType[] = {
- {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"},
- {LINEJOIN_ROUND, N_("Rounded"), "round"},
- {LINEJOIN_REFLECTED, N_("Reflected"), "reflected"},
- {LINEJOIN_POINTY, N_("Miter"), "miter"},
- {LINEJOIN_EXTRAPOLATED, N_("Extrapolated"), "extrapolated"}
+ {JOIN_BEVEL, N_("Beveled"), "bevel"},
+ {JOIN_ROUND, N_("Rounded"), "round"},
+ {JOIN_MITER, N_("Miter"), "miter"},
+ {JOIN_EXTRAPOLATE, N_("Extrapolated"), "extrapolated"},
};
static const Util::EnumDataConverter<unsigned> JoinTypeConverter(JoinType, sizeof (JoinType)/sizeof(*JoinType));
@@ -75,7 +75,7 @@ LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) :
attach_start(_("Start offset:"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2),
attach_end(_("End offset:"), _("The ending position of the taper"), "end_offset", &wr, this, 0.2),
smoothing(_("Taper smoothing:"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.5),
- join_type(_("Join type:"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED),
+ join_type(_("Join type:"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, JOIN_EXTRAPOLATE),
miter_limit(_("Miter limit:"), _("Limit for miter joins"), "miter_limit", &wr, this, 100.)
{
show_orig_path = true;
@@ -102,27 +102,24 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem)
double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.;
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (true) {
- if (lpeitem->style->stroke.isPaintserver()) {
- SPPaintServer * server = lpeitem->style->getStrokePaintServer();
- if (server) {
- Glib::ustring str;
- str += "url(#";
- str += server->getId();
- str += ")";
- sp_repr_css_set_property (css, "fill", str.c_str());
- }
- } else if (lpeitem->style->stroke.isColor()) {
- gchar c[64];
- sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value)));
- sp_repr_css_set_property (css, "fill", c);
- } else {
- sp_repr_css_set_property (css, "fill", "none");
+ if (lpeitem->style->stroke.isPaintserver()) {
+ SPPaintServer * server = lpeitem->style->getStrokePaintServer();
+ if (server) {
+ Glib::ustring str;
+ str += "url(#";
+ str += server->getId();
+ str += ")";
+ sp_repr_css_set_property (css, "fill", str.c_str());
}
+ } else if (lpeitem->style->stroke.isColor()) {
+ gchar c[64];
+ sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value)));
+ sp_repr_css_set_property (css, "fill", c);
} else {
- sp_repr_css_unset_property (css, "fill");
+ sp_repr_css_set_property (css, "fill", "none");
}
+ sp_repr_css_set_property(css, "fill-rule", "nonzero");
sp_repr_css_set_property(css, "stroke", "none");
sp_desktop_apply_css_recursive(item, css, true);
@@ -130,7 +127,7 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem)
line_width.param_set_value(width);
} else {
- printf("WARNING: It only makes sense to apply Join Type to paths (not groups).\n");
+ printf("WARNING: It only makes sense to apply Taper stroke to paths (not groups).\n");
}
}
@@ -142,25 +139,21 @@ void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem)
SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem);
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (true) {
- if (lpeitem->style->fill.isPaintserver()) {
- SPPaintServer * server = lpeitem->style->getFillPaintServer();
- if (server) {
- Glib::ustring str;
- str += "url(#";
- str += server->getId();
- str += ")";
- sp_repr_css_set_property (css, "stroke", str.c_str());
- }
- } else if (lpeitem->style->fill.isColor()) {
- gchar c[64];
- sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value)));
- sp_repr_css_set_property (css, "stroke", c);
- } else {
- sp_repr_css_set_property (css, "stroke", "none");
+ if (lpeitem->style->fill.isPaintserver()) {
+ SPPaintServer * server = lpeitem->style->getFillPaintServer();
+ if (server) {
+ Glib::ustring str;
+ str += "url(#";
+ str += server->getId();
+ str += ")";
+ sp_repr_css_set_property (css, "stroke", str.c_str());
}
+ } else if (lpeitem->style->fill.isColor()) {
+ gchar c[64];
+ sp_svg_write_color (c, sizeof(c), lpeitem->style->fill.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->fill_opacity.value)));
+ sp_repr_css_set_property (css, "stroke", c);
} else {
- sp_repr_css_unset_property (css, "stroke");
+ sp_repr_css_set_property (css, "stroke", "none");
}
Inkscape::CSSOStringStream os;
@@ -179,15 +172,22 @@ using Geom::D2;
using Geom::SBasis;
// leave Geom::Path
-Geom::Path return_at_first_cusp(Geom::Path const & path_in, double /*smooth_tolerance*/ = 0.05) {
- return Geom::split_at_cusps(path_in)[0];
+static Geom::Path return_at_first_cusp(Geom::Path const & path_in, double /*smooth_tolerance*/ = 0.05)
+{
+ Geom::Path temp;
+
+ for (unsigned i = 0; i < path_in.size(); i++) {
+ temp.append(path_in[i]);
+ if (Geom::get_nodetype(path_in[i], path_in[i + 1]) != Geom::NODE_SMOOTH ) {
+ break;
+ }
+ }
+
+ return temp;
}
Piecewise<D2<SBasis> > stretch_along(Piecewise<D2<SBasis> > pwd2_in, Geom::Path pattern, double width);
-// references to pointers
-void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second);
-
// actual effect
Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in)
@@ -285,7 +285,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in)
// although this seems obvious, it can probably lead to bugs.
if (!metInMiddle) {
// append the outside outline of the path (goes with the direction of the path)
- throwaway_path = Outline::PathOutsideOutline(pathv_out[1], -fabs(line_width), static_cast<LineJoinType>(join_type.get_value()), miter_limit);
+ throwaway_path = half_outline(pathv_out[1], fabs(line_width)/2., miter_limit, static_cast<LineJoinType>(join_type.get_value()));
if (!zeroStart && real_path.size() >= 1 && throwaway_path.size() >= 1) {
if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint())) {
real_path.appendNew<Geom::LineSegment>(throwaway_path.initialPoint());
@@ -317,7 +317,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in)
if (!metInMiddle) {
// append the inside outline of the path (against direction)
- throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), -fabs(line_width), static_cast<LineJoinType>(join_type.get_value()), miter_limit);
+ throwaway_path = half_outline(pathv_out[1].reverse(), fabs(line_width)/2., miter_limit, static_cast<LineJoinType>(join_type.get_value()));
if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint()) && real_path.size() >= 1) {
real_path.appendNew<Geom::LineSegment>(throwaway_path.initialPoint());
@@ -347,85 +347,18 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in)
*/
Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & path_in)
{
- size_t size = path_in[0].size();
-
- unsigned loc = (unsigned)attach_start;
- Geom::Curve * curve_start = path_in[0] [loc].duplicate();
-
- std::vector<Geom::Path> pathv_out;
- Geom::Path path_out = Geom::Path();
-
- Geom::Path trimmed_start = Geom::Path();
- Geom::Path trimmed_end = Geom::Path();
-
- for (size_t i = 0; i < loc; ++i) {
- trimmed_start.append(path_in[0] [i]);
- }
-
- Geom::Curve * temp;
- subdivideCurve(curve_start, attach_start - loc, temp, curve_start);
- trimmed_start.append(*temp);
- if (temp) delete temp; temp = 0;
-
- // special case: path is one segment long
- // special case: what if the two knots occupy the same segment?
- if ((size == 1) || ( size - unsigned(attach_end) - 1 == loc )) {
-
- // If you look into it, I don't actually think there is a working way to do this
- // with only point math. So we use nearest_point instead.
- Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_start);
-
- // it is just a dumb segment
- // we have to do some shifting here because the value changed when we reduced the length
- // of the previous segment.
-
- subdivideCurve(curve_start, t, curve_start, temp);
- trimmed_end.append(*temp);
- if (temp) delete temp; temp = 0;
-
- for (size_t j = (size - attach_end) + 1; j < size; ++j) {
- trimmed_end.append(path_in[0] [j]);
- }
+ Geom::Coord endTime = path_in[0].size() - attach_end;
- path_out.append(*curve_start);
- pathv_out.push_back(trimmed_start);
- pathv_out.push_back(path_out);
- pathv_out.push_back(trimmed_end);
- return pathv_out;
- }
-
- pathv_out.push_back(trimmed_start);
-
- // append almost all of the rest of the path, ignore the curves that the knot is past (we'll get to it in a minute)
- path_out.append(*curve_start);
-
- for (size_t k = loc + 1; k < (size - unsigned(attach_end)) - 1; ++k) {
- path_out.append(path_in[0] [k]);
- }
-
- // deal with the last segment in a very similar fashion to the first
- loc = size - attach_end;
-
- Geom::Curve * curve_end = path_in[0] [loc].duplicate();
-
- Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_end);
-
- subdivideCurve(curve_end, t, curve_end, temp);
- trimmed_end.append(*temp);
- if (temp) delete temp; temp = 0;
-
- for (size_t j = (size - attach_end) + 1; j < size; ++j) {
- trimmed_end.append(path_in[0] [j]);
- }
-
- path_out.append(*curve_end);
- pathv_out.push_back(path_out);
-
- pathv_out.push_back(trimmed_end);
-
- if (curve_end) delete curve_end;
- if (curve_start) delete curve_start;
- return pathv_out;
+ Geom::Path p1 = path_in[0].portion(0., attach_start);
+ Geom::Path p2 = path_in[0].portion(attach_start, endTime);
+ Geom::Path p3 = path_in[0].portion(endTime, path_in[0].size());
+
+ Geom::PathVector out;
+ out.push_back(p1);
+ out.push_back(p2);
+ out.push_back(p3);
+
+ return out;
}
@@ -513,23 +446,6 @@ Piecewise<D2<SBasis> > stretch_along(Piecewise<D2<SBasis> > pwd2_in, Geom::Path
}
}
-void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second)
-{
- if (Geom::LineSegment* linear = dynamic_cast<Geom::LineSegment*>(curve_in)) {
- // special case for line segments
- std::pair<Geom::LineSegment, Geom::LineSegment> seg_pair = linear->subdivide(t);
- val_first = seg_pair.first.duplicate();
- val_second = seg_pair.second.duplicate();
- } else {
- // all other cases:
- Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(curve_in->toSBasis());
- std::pair<Geom::CubicBezier, Geom::CubicBezier> cubic_pair = cubic.subdivide(t);
- val_first = cubic_pair.first.duplicate();
- val_second = cubic_pair.second.duplicate();
- }
-}
-
-
void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
{
KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this);
diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp
deleted file mode 100644
index 21a0fb809..000000000
--- a/src/live_effects/pathoutlineprovider.cpp
+++ /dev/null
@@ -1,803 +0,0 @@
-/* Author:
- * Liam P. White <inkscapebrony@gmail.com>
- *
- * Copyright (C) 2014 Author
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include <2geom/angle.h>
-#include <2geom/path.h>
-#include <2geom/circle.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/shape.h>
-#include <2geom/transforms.h>
-#include <2geom/path-sink.h>
-#include <cstdio>
-
-#include "pathoutlineprovider.h"
-#include "livarot/path-description.h"
-#include "helper/geom-nodetype.h"
-#include "svg/svg.h"
-
-namespace Geom {
-/**
-* Refer to: Weisstein, Eric W. "Circle-Circle Intersection."
- From MathWorld--A Wolfram Web Resource.
- http://mathworld.wolfram.com/Circle-CircleIntersection.html
-*
-* @return 0 if no intersection
-* @return 1 if one circle is contained in the other
-* @return 2 if intersections are found (they are written to p0 and p1)
-*/
-static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, Point & p0, Point & p1)
-{
- Point X0 = circle0.center();
- double r0 = circle0.ray();
- Point X1 = circle1.center();
- double r1 = circle1.ray();
-
- /* dx and dy are the vertical and horizontal distances between
- * the circle centers.
- */
- Point D = X1 - X0;
-
- /* Determine the straight-line distance between the centers. */
- double d = L2(D);
-
- /* Check for solvability. */
- if (d > (r0 + r1)) {
- /* no solution. circles do not intersect. */
- return 0;
- }
- if (d <= fabs(r0 - r1)) {
- /* no solution. one circle is contained in the other */
- return 1;
- }
-
- /* 'point 2' is the point where the line through the circle
- * intersection points crosses the line between the circle
- * centers.
- */
-
- /* Determine the distance from point 0 to point 2. */
- double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ;
-
- /* Determine the coordinates of point 2. */
- Point p2 = X0 + D * (a/d);
-
- /* Determine the distance from point 2 to either of the
- * intersection points.
- */
- double h = std::sqrt((r0*r0) - (a*a));
-
- /* Now determine the offsets of the intersection points from
- * point 2.
- */
- Point r = (h/d)*rot90(D);
-
- /* Determine the absolute intersection points. */
- p0 = p2 + r;
- p1 = p2 - r;
-
- return 2;
-}
-/**
-* Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t.
-* Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt).
-*/
-static Circle touching_circle( D2<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));
-}
-
-std::vector<Geom::Path> split_at_cusps(const Geom::Path& in)
-{
- PathVector out = PathVector();
- Path temp = Path();
-
- for (unsigned i = 0; i < in.size(); i++) {
- temp.append(in[i]);
- if ( get_nodetype(in[i], in[i + 1]) != Geom::NODE_SMOOTH ) {
- out.push_back(temp);
- temp = Path();
- }
- }
- if (temp.size() > 0) {
- out.push_back(temp);
- }
- return out;
-}
-
-Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2<Geom::SBasis> const & sbasis_in)
-{
- std::vector<Geom::Point> temp;
- sbasis_to_bezier(temp, sbasis_in, 4);
- return Geom::CubicBezier( temp );
-}
-
-static boost::optional<Geom::Point> intersection_point(Geom::Point const & origin_a, Geom::Point const & vector_a, Geom::Point const & origin_b, Geom::Point const & vector_b)
-{
- Geom::Coord denom = cross(vector_b, vector_a);
- if (!Geom::are_near(denom,0.)) {
- Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom;
- return origin_a + t * vector_a;
- }
- return boost::none;
-}
-
-} // namespace Geom
-
-namespace Outline {
-
-typedef Geom::D2<Geom::SBasis> D2SB;
-typedef Geom::Piecewise<D2SB> PWD2;
-
-// UTILITY
-
-unsigned bezierOrder (const Geom::Curve* curve_in)
-{
- using namespace Geom;
- if ( const BezierCurve* bz = dynamic_cast<const BezierCurve*>(curve_in) ) {
- return bz->order();
- }
- return 0;
-}
-
-/**
- * @return true if the angle formed by the curves and their handles is greater than 180 degrees clockwise, otherwise false.
- */
-bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2)
-{
- Geom::Point start_point;
- Geom::Point cross_point = cbc1.finalPoint();
- Geom::Point end_point;
-
- if (cross_point != cbc2.initialPoint()) {
- printf("WARNING: Non-contiguous path in Outline::outside_angle()");
- return false;
- }
-
- Geom::CubicBezier cubicBezier = Geom::sbasis_to_cubicbezier(cbc1.toSBasis());
- start_point = cubicBezier [2];
-
- /*
- * Because the node editor does not yet support true quadratics, paths are converted to
- * cubic beziers in the node tool with degenerate handles on one side.
- */
-
- if (are_near(start_point, cross_point, 0.0000001)) {
- start_point = cubicBezier [1];
- }
- cubicBezier = Geom::sbasis_to_cubicbezier(cbc2.toSBasis());
- end_point = cubicBezier [1];
- if (are_near(end_point, cross_point, 0.0000001)) {
- end_point = cubicBezier [2];
- }
-
- // got our three points, now let's see what their clockwise angle is
-
- // Definition of a Graham scan
-
- /********************************************************************
- # Three points are a counter-clockwise turn if ccw > 0, clockwise if
- # ccw < 0, and collinear if ccw = 0 because ccw is a determinant that
- # gives the signed area of the triangle formed by p1, p2 and p3.
- function ccw(p1, p2, p3):
- return (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x)
- *********************************************************************/
-
- double ccw = ( (cross_point.x() - start_point.x()) * (end_point.y() - start_point.y()) ) -
- ( (cross_point.y() - start_point.y()) * (end_point.x() - start_point.x()) );
- return ccw > 0;
-}
-
-// LINE JOINS
-
-typedef Geom::BezierCurveN<1u> BezierLine;
-
-/**
- * Removes the crossings on an interior join.
- * @param path_builder Contains the incoming segment; result is appended to this
- * @param outgoing The outgoing segment
- */
-void joinInside(Geom::Path& path_builder, Geom::Curve const& outgoing)
-{
- Geom::Curve const& incoming = path_builder.back();
-
- // Using Geom::crossings to find intersections between two curves
- Geom::Crossings cross = Geom::crossings(incoming, outgoing);
- if (!cross.empty()) {
- // Crossings found, create the join
- Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(incoming.toSBasis());
- cubic = cubic.subdivide(cross[0].ta).first;
- // erase the last segment, as we're going to overwrite it now
- path_builder.erase_last();
- path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS);
-
- cubic = Geom::sbasis_to_cubicbezier(outgoing.toSBasis());
- cubic = cubic.subdivide(cross[0].tb).second;
- path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS);
- } else {
- // No crossings occurred, or Geom::crossings() failed; default to bevel
- if (Geom::are_near(incoming.finalPoint(), outgoing.initialPoint())) {
- path_builder.appendNew<BezierLine>(outgoing.initialPoint());
- } else {
- path_builder.setFinal(outgoing.initialPoint());
- }
- }
-}
-
-/**
- * Try to create a miter join. Falls back to bevel if no miter can be created.
- * @param path_builder Path to append curves to; back() is the incoming curve
- * @param outgoing Outgoing curve.
- * @param miter_limit When mitering, don't exceed this length
- * @param line_width The thickness of the line.
- */
-void miter_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width)
-{
- using namespace Geom;
- Curve const& incoming = path_builder.back();
- Point tang1 = unitTangentAt(Geom::reverse(incoming.toSBasis()), 0.);
- Point tang2 = unitTangentAt(outgoing.toSBasis(), 0);
-
- boost::optional <Point> p = intersection_point (incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2);
- if (p) {
- // check size of miter
- Point point_on_path = incoming.finalPoint() - rot90(tang1) * line_width;
- Coord len = distance(*p, point_on_path);
- if (len <= miter_limit) {
- // miter OK
- path_builder.appendNew<BezierLine>(*p);
- }
- }
- path_builder.appendNew<BezierLine>(outgoing.initialPoint());
-}
-
-/**
- * Smoothly extrapolate curves along a circular route. Falls back to miter if necessary.
- * @param path_builder Path to append curves to; back() is the incoming curve
- * @param outgoing Outgoing curve.
- * @param miter_limit When mitering, don't exceed this length
- * @param line_width The thickness of the line. Used for miter fallback.
- */
-void extrapolate_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width)
-{
- 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<const BezierLine *>(&incoming)) || (dynamic_cast<const BezierLine *>(&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, circle2, 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->toSBasis());
- delete arc0;
- arc0 = NULL;
- } else {
- throw std::exception();
- }
-
- if (arc1) {
- path_builder.append (arc1->toSBasis());
- 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_curves(path_builder, outgoing, miter_limit, line_width);
- }
- } else {
- // Line segments exist
- miter_curves(path_builder, outgoing, miter_limit, line_width);
- }
-}
-
-/**
- * Extrapolate curves by reflecting them along the line that would be given by beveling the join.
- * @param path_builder Path to append curves to; back() is the incoming curve
- * @param outgoing Outgoing curve.
- * @param miter_limit When mitering, don't exceed this length
- * @param line_width The thickness of the line. Used for miter fallback.
- */
-void reflect_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width)
-{
- using namespace Geom;
- Curve const& incoming = path_builder.back();
- // On the outside, we'll take the incoming curve, the outgoing curve, and
- // reflect them over the line formed by taking the unit tangent vector at times
- // 0 and 1, respectively, rotated by 90 degrees.
- Crossings cross;
-
- // reflect curves along the line that would be given by beveling the join
- Point tang1 = unitTangentAt(reverse(incoming.toSBasis()), 0.);
- D2SB newcurve1 = incoming.toSBasis() * reflection(-rot90(tang1), incoming.finalPoint());
- CubicBezier bzr1 = sbasis_to_cubicbezier(reverse(newcurve1));
-
- Point tang2 = Geom::unitTangentAt(outgoing.toSBasis(), 0.);
- D2SB newcurve2 = outgoing.toSBasis() * reflection(-rot90(tang2), outgoing.initialPoint());
- CubicBezier bzr2 = sbasis_to_cubicbezier(reverse(newcurve2));
-
- cross = crossings(bzr1, bzr2);
- if (cross.empty()) {
- // paths don't cross, fall back to miter
- miter_curves(path_builder, outgoing, miter_limit, line_width);
- } else {
- // reflected join
- std::pair<CubicBezier, CubicBezier> sub1 = bzr1.subdivide(cross[0].ta);
- std::pair<CubicBezier, CubicBezier> sub2 = bzr2.subdivide(cross[0].tb);
-
- // TODO it seems as if a bug in 2geom sometimes doesn't catch the first
- // crossing of paths, but the second instead; but only sometimes.
- path_builder.appendNew <CubicBezier> (sub1.first[1], sub1.first[2], sub2.second[0]);
- path_builder.appendNew <CubicBezier> (sub2.second[1], sub2.second[2], outgoing.initialPoint());
- }
-}
-
-// Ideal function pointer we want to pass
-typedef void JoinFunc(Geom::Path& /*path_builder*/, Geom::Curve const& /*outgoing*/, double /*miter_limit*/, double /*line_width*/);
-
-/**
- * Helper function for repeated logic in outlineHalf.
- */
-static void outlineHelper(Geom::Path& path_builder, Geom::PathVector* path_vec, bool outside, double width, double miter, JoinFunc func)
-{
- Geom::Curve * cbc2 = path_vec->front()[0].duplicate();
-
- if (outside) {
- func(path_builder, *cbc2, miter, width);
- } else {
- joinInside(path_builder, *cbc2);
- }
-
- // store it
- Geom::Path temp_path = path_vec->front();
- if (!outside) {
- // erase the first segment since the inside join code already appended it
- temp_path.erase(temp_path.begin());
- }
-
- if (temp_path.initialPoint() != path_builder.finalPoint()) {
- temp_path.setInitial(path_builder.finalPoint());
- }
-
- path_builder.append(temp_path);
-
- delete cbc2;
-}
-
-/**
- * Offsets exactly one half of a bezier spline (path).
- * @param path_in The input path to use. (To create the other side use path_in.reverse() )
- * @param line_width the line width to use (usually you want to divide this by 2)
- * @param miter_limit the miter parameter
- * @param func Join function to apply at each join.
- */
-
-Geom::Path outlineHalf(const Geom::Path& path_in, double line_width, double miter_limit, JoinFunc func)
-{
- // NOTE: it is important to notice the distinction between a Geom::Path and a livarot ::Path here!
- // if you do not see "Geom::" there is a different function set!
-
- Geom::PathVector pv = split_at_cusps(path_in);
-
- ::Path to_outline;
- ::Path outlined_result;
-
- Geom::Path path_builder = Geom::Path(); // the path to store the result in
- Geom::PathVector* path_vec; // needed because livarot returns a pointer (TODO make this not a pointer)
-
- // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well
- const size_t k = pv.size();
- for (size_t u = 0; u < k; u += 2) {
- to_outline = Path();
- outlined_result = Path();
-
- to_outline.LoadPath(pv[u], Geom::identity(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
- // now a curve has been outside outlined and loaded into outlined_result
-
- // get the Geom::Path
- path_vec = outlined_result.MakePathVector();
-
- // on the first run through, there is no join
- if (u == 0) {
- path_builder.start(path_vec->front().initialPoint());
- path_builder.append(path_vec->front());
- } else {
- outlineHelper(path_builder, path_vec, outside_angle(pv[u-1][pv[u-1].size()-1], pv[u][0]), line_width, miter_limit, func);
- }
-
- // outline the next segment, but don't store it yet
- if (path_vec)
- delete path_vec;
- path_vec = NULL;
-
- // odd number of paths
- if (u < k - 1) {
- outlined_result = Path();
- to_outline = Path();
-
- to_outline.LoadPath(pv[u+1], Geom::Affine(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
-
- path_vec = outlined_result.MakePathVector();
- outlineHelper(path_builder, path_vec, outside_angle(pv[u][pv[u].size()-1], pv[u+1][0]), line_width, miter_limit, func);
-
- if (path_vec)
- delete path_vec;
- path_vec = NULL;
- }
- }
-
- if (path_in.closed()) {
- Geom::Curve * cbc1;
- Geom::Curve * cbc2;
-
- if ( path_in[path_in.size()].isDegenerate() ) {
- // handle case for last segment curved
- outlined_result = Path();
- to_outline = Path();
-
- Geom::Path oneCurve; oneCurve.append(path_in[0]);
-
- to_outline.LoadPath(oneCurve, Geom::Affine(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
-
- path_vec = outlined_result.MakePathVector();
-
- cbc1 = path_builder[path_builder.size() - 1].duplicate();
- cbc2 = path_vec->front()[0].duplicate();
-
- delete path_vec;
- } else {
- // handle case for last segment straight
- // since the path doesn't actually give us access to it, we'll do it ourselves
- outlined_result = Path();
- to_outline = Path();
-
- Geom::Path oneCurve; oneCurve.append(Geom::LineSegment(path_in.finalPoint(), path_in.initialPoint()));
-
- to_outline.LoadPath(oneCurve, Geom::Affine(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
-
- path_vec = outlined_result.MakePathVector();
-
- cbc1 = path_builder[path_builder.size() - 1].duplicate();
- cbc2 = (*path_vec)[0] [0].duplicate();
-
- outlineHelper(path_builder, path_vec, outside_angle(path_in[path_in.size()-1], oneCurve[0]), line_width, miter_limit, func);
-
- delete cbc1;
- cbc1 = cbc2->duplicate();
- delete path_vec;
-
- oneCurve = Geom::Path(); oneCurve.append(path_in[0]);
-
- to_outline.LoadPath(oneCurve, Geom::Affine(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
-
- path_vec = outlined_result.MakePathVector();
- delete cbc2; cbc2 = (*path_vec)[0] [0].duplicate();
- delete path_vec;
- }
-
- Geom::Path temporary;
- temporary.append(*cbc1);
-
- Geom::Curve const & prev_curve = path_in[path_in.size()].isDegenerate() ? path_in[path_in.size() - 1] : path_in[path_in.size()];
- Geom::Path isStraight;
- isStraight.append(prev_curve);
- isStraight.append(path_in[0]);
- // does closing path require a join?
- if (Geom::split_at_cusps(isStraight).size() > 1) {
- bool outside = outside_angle(prev_curve, path_in[0]);
- if (outside) {
- func(temporary, *cbc2, miter_limit, line_width);
- } else {
- joinInside(temporary, *cbc2);
- path_builder.erase(path_builder.begin());
- }
-
- // extract the appended curves
- path_builder.erase_last();
- if (Geom::are_near(path_builder.finalPoint(), temporary.initialPoint())) {
- path_builder.setFinal(temporary.initialPoint());
- } else {
- path_builder.appendNew<BezierLine>(temporary.initialPoint());
- }
- path_builder.append(temporary);
- } else {
- // closing path does not require a join
- path_builder.setFinal(path_builder.initialPoint());
- }
- path_builder.close();
-
- if (cbc1) delete cbc1;
- if (cbc2) delete cbc2;
- }
-
- return path_builder;
-}
-
-Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtTypeMod butt, double miter_lim, bool extrapolate, double start_lean, double end_lean)
-{
- Geom::PathVector path_out;
-
- unsigned pv_size = path_in.size();
- for (unsigned i = 0; i < pv_size; i++) {
-
- if (path_in[i].size() > 1) {
- Geom::Path with_direction;
- Geom::Path against_direction;
-
- with_direction = Outline::outlineHalf(path_in[i], -line_width, miter_lim, extrapolate ? extrapolate_curves : reflect_curves);
- against_direction = Outline::outlineHalf(path_in[i].reverse(), -line_width, miter_lim, extrapolate ? extrapolate_curves : reflect_curves);
-
- Geom::PathBuilder pb;
-
- pb.moveTo(with_direction.initialPoint());
- pb.append(with_direction);
-
- //add in our line caps
- if (!path_in[i].closed()) {
- switch (butt) {
- case BUTT_STRAIGHT:
- pb.lineTo(against_direction.initialPoint());
- break;
- case BUTT_ROUND:
- pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, against_direction.initialPoint() );
- break;
- case BUTT_POINTY: {
- Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.);
- double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint());
- Geom::Point midpoint = 0.5 * (with_direction.finalPoint() + against_direction.initialPoint()) + radius*end_deriv;
- pb.lineTo(midpoint);
- pb.lineTo(against_direction.initialPoint());
- break;
- }
- case BUTT_SQUARE: {
- Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.);
- double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint());
- pb.lineTo(with_direction.finalPoint() + radius*end_deriv);
- pb.lineTo(against_direction.initialPoint() + radius*end_deriv);
- pb.lineTo(against_direction.initialPoint());
- break;
- }
- case BUTT_LEANED: {
- Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.);
- double maxRadius = (end_lean+0.5) * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint());
- double minRadius = ((end_lean*-1)+0.5) * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint());
- pb.lineTo(with_direction.finalPoint() + maxRadius*end_deriv);
- pb.lineTo(against_direction.initialPoint() + minRadius*end_deriv);
- pb.lineTo(against_direction.initialPoint());
- break;
- }
- }
- } else {
- pb.moveTo(against_direction.initialPoint());
- }
-
- pb.append(against_direction);
-
- //cap (if necessary)
- if (!path_in[i].closed()) {
- switch (butt) {
- case BUTT_STRAIGHT:
- pb.lineTo(with_direction.initialPoint());
- break;
- case BUTT_ROUND:
- pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, with_direction.initialPoint() );
- break;
- case BUTT_POINTY: {
- Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.);
- double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint());
- Geom::Point midpoint = 0.5 * (against_direction.finalPoint() + with_direction.initialPoint()) + radius*end_deriv;
- pb.lineTo(midpoint);
- pb.lineTo(with_direction.initialPoint());
- break;
- }
- case BUTT_SQUARE: {
- Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.);
- double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint());
- pb.lineTo(against_direction.finalPoint() + radius*end_deriv);
- pb.lineTo(with_direction.initialPoint() + radius*end_deriv);
- pb.lineTo(with_direction.initialPoint());
- break;
- }
- case BUTT_LEANED: {
- Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.);
- double maxRadius = (start_lean+0.5) * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint());
- double minRadius = ((start_lean*-1)+0.5) * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint());
- pb.lineTo(against_direction.finalPoint() + minRadius*end_deriv);
- pb.lineTo(with_direction.initialPoint() + maxRadius*end_deriv);
- pb.lineTo(with_direction.initialPoint());
- break;
- }
- }
- }
- pb.flush();
- path_out.push_back(pb.peek()[0]);
- if (path_in[i].closed()) {
- path_out.push_back(pb.peek()[1]);
- }
- } else {
- Path p = Path();
- Path outlinepath = Path();
- ButtType original_butt;
- switch (butt) {
- case BUTT_STRAIGHT:
- original_butt = butt_straight;
- break;
- case BUTT_ROUND:
- original_butt = butt_round;
- break;
- case butt_pointy: {
- original_butt = butt_pointy;
- break;
- }
- case BUTT_SQUARE: {
- original_butt = butt_square;
- break;
- }
- case BUTT_LEANED: {
- original_butt = butt_straight;
- break;
- }
- }
- p.LoadPath(path_in[i], Geom::Affine(), false, false);
- p.Outline(&outlinepath, line_width / 2, static_cast<join_typ>(join), original_butt, miter_lim);
- Geom::PathVector *pv_p = outlinepath.MakePathVector();
- //somewhat hack-ish
- path_out.push_back( (*pv_p)[0].reverse() );
- if (pv_p) delete pv_p;
- }
- }
- return path_out;
-}
-
-#define miter_lim fabs(line_width * miter_limit)
-
-Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtTypeMod linecap_type, LineJoinType linejoin_type, double miter_limit, double start_lean, double end_lean)
-{
- std::vector<Geom::Path> path_out = std::vector<Geom::Path>();
- if (path_in.empty()) {
- return path_out;
- }
- Path p = Path();
- Path outlinepath = Path();
- for (unsigned i = 0; i < path_in.size(); i++) {
- p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true));
- }
-
- // magic!
- ButtType original_butt;
- switch (linecap_type) {
- case BUTT_STRAIGHT:
- original_butt = butt_straight;
- break;
- case BUTT_ROUND:
- original_butt = butt_round;
- break;
- case butt_pointy: {
- original_butt = butt_pointy;
- break;
- }
- case BUTT_SQUARE: {
- original_butt = butt_square;
- break;
- }
- case BUTT_LEANED: {
- original_butt = butt_straight;
- break;
- }
- }
- if (linejoin_type <= LINEJOIN_POINTY) {
- p.Outline(&outlinepath, line_width / 2, static_cast<join_typ>(linejoin_type),
- original_butt, miter_lim);
- // fix memory leak
- std::vector<Geom::Path> *pv_p = outlinepath.MakePathVector();
- path_out = *pv_p;
- delete pv_p;
-
- } else if (linejoin_type == LINEJOIN_REFLECTED) {
- // reflected arc join
- path_out = outlinePath(path_in, line_width, static_cast<LineJoinType>(linejoin_type),
- linecap_type , miter_lim, false, start_lean, end_lean);
-
- } else if (linejoin_type == LINEJOIN_EXTRAPOLATED) {
- // extrapolated arc join
- path_out = outlinePath(path_in, line_width, LINEJOIN_STRAIGHT, linecap_type, miter_lim, true, start_lean, end_lean);
- }
-
- return path_out;
-}
-
-Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit)
-{
-
- Geom::Path path_out;
-
- if (linejoin_type <= LINEJOIN_POINTY || path_in.size() <= 1) {
-
- Geom::PathVector * pathvec;
-
- Path path_tangent = Path();
- Path path_outline = Path();
- path_outline.LoadPath(path_in, Geom::Affine(), false, false);
- path_outline.OutsideOutline(&path_tangent, line_width / 2, static_cast<join_typ>(linejoin_type), butt_straight, miter_lim);
-
- pathvec = path_tangent.MakePathVector();
- path_out = pathvec->front();
- delete pathvec;
- return path_out;
- } else if (linejoin_type == LINEJOIN_REFLECTED) {
- path_out = outlineHalf(path_in, line_width, miter_lim, reflect_curves);
- return path_out;
- } else if (linejoin_type == LINEJOIN_EXTRAPOLATED) {
- path_out = outlineHalf(path_in, line_width, miter_lim, extrapolate_curves);
- return path_out;
- }
- return path_out;
-}
-
-} // namespace Outline
-
-/*
- 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/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h
deleted file mode 100644
index c17584be2..000000000
--- a/src/live_effects/pathoutlineprovider.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef SEEN_PATH_OUTLINE_H
-#define SEEN_PATH_OUTLINE_H
-
-/* Author:
- * Liam P. White <inkscapebrony@gmail.com>
- *
- * Copyright (C) 2014 Author
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include <livarot/Path.h>
-#include <livarot/LivarotDefs.h>
-
-enum LineJoinType {
- LINEJOIN_STRAIGHT,
- LINEJOIN_ROUND,
- LINEJOIN_POINTY,
- LINEJOIN_REFLECTED,
- LINEJOIN_EXTRAPOLATED
-};
-enum ButtTypeMod {
- BUTT_STRAIGHT,
- BUTT_ROUND,
- BUTT_SQUARE,
- BUTT_POINTY,
- BUTT_LEANED
-};
-
-namespace Geom
-{
- Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2<Geom::SBasis> const & sbasis_in);
- std::vector<Geom::Path> split_at_cusps(const Geom::Path& in);
-}
-
-namespace Outline
-{
- unsigned bezierOrder (const Geom::Curve* curve_in);
- std::vector<Geom::Path> PathVectorOutline(std::vector<Geom::Path> const & path_in, double line_width, ButtTypeMod linecap_type,
- LineJoinType linejoin_type, double miter_limit, double start_lean = 0, double end_lean = 0);
- Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit);
-}
-
-#endif // SEEN_PATH_OUTLINE_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/svg-profile.h b/src/svg-profile.h
index 9d221fc76..8945ee313 100644
--- a/src/svg-profile.h
+++ b/src/svg-profile.h
@@ -74,7 +74,7 @@ public:
SVG_PRINT_1_1, /**< */
- PROFILE_UNIQUE_CNT, /**< A marker to seperate between the entires
+ PROFILE_UNIQUE_CNT, /**< A marker to separate between the entires
that are unique, and those which are
aggregates of them. */
diff --git a/src/trace/potrace/auxiliary.h b/src/trace/potrace/auxiliary.h
index b7480bbb8..dbf124d7c 100644
--- a/src/trace/potrace/auxiliary.h
+++ b/src/trace/potrace/auxiliary.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
@@ -8,6 +8,8 @@
#ifndef AUXILIARY_H
#define AUXILIARY_H
+#include <stdlib.h>
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -75,31 +77,4 @@ static inline int floordiv(int a, int n) {
#define sq(a) ((a)*(a))
#define cu(a) ((a)*(a)*(a))
-/* ---------------------------------------------------------------------- */
-/* deterministically and efficiently hash (x,y) into a pseudo-random bit */
-static inline int detrand(int x, int y) {
- unsigned int z;
- static const unsigned char t[256] = {
- /* non-linear sequence: constant term of inverse in GF(8),
- mod x^8+x^4+x^3+x+1 */
- 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
- 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
- 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
- 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
- 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
- 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
- 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
- 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
- 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
- };
-
- /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible
- 5-bit sequence */
- z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93;
- z = t[z & 0xff] ^ t[(z>>8) & 0xff] ^ t[(z>>16) & 0xff] ^ t[(z>>24) & 0xff];
- return z;
-}
-
#endif /* AUXILIARY_H */
diff --git a/src/trace/potrace/bitmap.h b/src/trace/potrace/bitmap.h
index 2df04b46f..086bbb046 100644
--- a/src/trace/potrace/bitmap.h
+++ b/src/trace/potrace/bitmap.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
@@ -7,6 +7,7 @@
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
/* The bitmap type is defined in potracelib.h */
#include "potracelib.h"
@@ -27,7 +28,7 @@
/* macros for accessing pixel at index (x,y). U* macros omit the
bounds check. */
-#define bm_scanline(bm, y) ((bm)->map + (y)*(bm)->dy)
+#define bm_scanline(bm, y) ((bm)->map + (ssize_t)(y)*(ssize_t)(bm)->dy)
#define bm_index(bm, x, y) (&bm_scanline(bm, y)[(x)/BM_WORDBITS])
#define bm_mask(x) (BM_HIBIT >> ((x) & (BM_WORDBITS-1)))
#define bm_range(x, a) ((int)(x) >= 0 && (int)(x) < (a))
@@ -51,10 +52,18 @@ static inline void bm_free(potrace_bitmap_t *bm) {
free(bm);
}
-/* return new un-initialized bitmap. NULL with errno on error */
+/* return new un-initialized bitmap. NULL with errno on error.
+ Assumes w, h >= 0. */
static inline potrace_bitmap_t *bm_new(int w, int h) {
potrace_bitmap_t *bm;
- int dy = (w + BM_WORDBITS - 1) / BM_WORDBITS;
+ int dy = w == 0 ? 0 : (w - 1) / BM_WORDBITS + 1;
+ ssize_t size = (ssize_t)dy * (ssize_t)h * (ssize_t)BM_WORDSIZE;
+
+ /* check for overflow error */
+ if (size < 0 || size / h / dy != BM_WORDSIZE) {
+ errno = ENOMEM;
+ return NULL;
+ }
bm = (potrace_bitmap_t *) malloc(sizeof(potrace_bitmap_t));
if (!bm) {
@@ -63,7 +72,7 @@ static inline potrace_bitmap_t *bm_new(int w, int h) {
bm->w = w;
bm->h = h;
bm->dy = dy;
- bm->map = (potrace_word *) malloc(dy * h * BM_WORDSIZE);
+ bm->map = (potrace_word *) malloc(size);
if (!bm->map) {
free(bm);
return NULL;
@@ -73,23 +82,29 @@ static inline potrace_bitmap_t *bm_new(int w, int h) {
/* clear the given bitmap. Set all bits to c. */
static inline void bm_clear(potrace_bitmap_t *bm, int c) {
- memset(bm->map, c ? -1 : 0, bm->dy * bm->h * BM_WORDSIZE);
+ /* Note: if the bitmap was created with bm_new, then it is
+ guaranteed that size will fit into the ssize_t type. */
+ ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE;
+ memset(bm->map, c ? -1 : 0, size);
}
/* duplicate the given bitmap. Return NULL on error with errno set. */
static inline potrace_bitmap_t *bm_dup(const potrace_bitmap_t *bm) {
potrace_bitmap_t *bm1 = bm_new(bm->w, bm->h);
+ ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE;
if (!bm1) {
return NULL;
}
- memcpy(bm1->map, bm->map, bm->dy * bm->h * BM_WORDSIZE);
+ memcpy(bm1->map, bm->map, size);
return bm1;
}
/* invert the given bitmap. */
static inline void bm_invert(potrace_bitmap_t *bm) {
- int i;
- for (i = 0; i < bm->dy * bm->h; i++) {
+ ssize_t i;
+ ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h;
+
+ for (i = 0; i < size; i++) {
bm->map[i] ^= BM_ALLBITS;
}
}
diff --git a/src/trace/potrace/bitops.h b/src/trace/potrace/bitops.h
new file mode 100644
index 000000000..cff734a46
--- /dev/null
+++ b/src/trace/potrace/bitops.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 2001-2015 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+
+/* bits.h: this file defines some macros for bit manipulations. We
+ provide a generic implementation, as well as machine- and
+ compiler-specific fast implementations */
+
+/* lobit: return the position of the rightmost "1" bit of an int, or
+ 32 if none. hibit: return 1 + the position of the leftmost "1" bit
+ of an int, or 0 if none. Note: these functions work on 32-bit
+ integers. */
+
+#ifndef BITOPS_H
+#define BITOPS_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* machine specific macros */
+
+#if defined(HAVE_I386)
+
+static inline unsigned int lobit(unsigned int x) {
+ unsigned int res;
+ asm ("bsf %1,%0\n\t"
+ "jnz 0f\n\t"
+ "movl $32,%0\n"
+ "0:"
+ : "=r" (res)
+ : "r" (x)
+ : "cc");
+ return res;
+}
+
+static inline unsigned int hibit(unsigned int x) {
+ unsigned int res;
+
+ asm ("bsr %1,%0\n\t"
+ "jnz 0f\n\t"
+ "movl $-1,%0\n"
+ "0:"
+ : "=r" (res)
+ : "r" (x)
+ : "cc");
+ return res+1;
+}
+
+/* ---------------------------------------------------------------------- */
+#else /* generic macros */
+
+static inline unsigned int lobit(unsigned int x) {
+ unsigned int res = 32;
+ while (x & 0xffffff) {
+ x <<= 8;
+ res -= 8;
+ }
+ while (x) {
+ x <<= 1;
+ res -= 1;
+ }
+ return res;
+}
+
+static inline unsigned int hibit(unsigned int x) {
+ unsigned int res = 0;
+ while (x > 0xff) {
+ x >>= 8;
+ res += 8;
+ }
+ while (x) {
+ x >>= 1;
+ res += 1;
+ }
+ return res;
+}
+
+#endif
+
+#endif /* BITOPS_H */
diff --git a/src/trace/potrace/curve.cpp b/src/trace/potrace/curve.cpp
index d2e32aa7b..e6a9a4721 100644
--- a/src/trace/potrace/curve.cpp
+++ b/src/trace/potrace/curve.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
@@ -12,8 +12,8 @@
#include "lists.h"
#include "curve.h"
-#define SAFE_MALLOC(var, n, typ) \
- if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error
+#define SAFE_CALLOC(var, n, typ) \
+ if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error
/* ---------------------------------------------------------------------- */
/* allocate and free path objects */
@@ -22,14 +22,14 @@ path_t *path_new(void) {
path_t *p = NULL;
privpath_t *priv = NULL;
- SAFE_MALLOC(p, 1, path_t);
+ SAFE_CALLOC(p, 1, path_t);
memset(p, 0, sizeof(path_t));
- SAFE_MALLOC(priv, 1, privpath_t);
+ SAFE_CALLOC(priv, 1, privpath_t);
memset(priv, 0, sizeof(privpath_t));
p->priv = priv;
return p;
- malloc_error:
+ calloc_error:
free(p);
free(priv);
return NULL;
@@ -81,15 +81,15 @@ typedef dpoint_t dpoint3_t[3];
int privcurve_init(privcurve_t *curve, int n) {
memset(curve, 0, sizeof(privcurve_t));
curve->n = n;
- SAFE_MALLOC(curve->tag, n, int);
- SAFE_MALLOC(curve->c, n, dpoint3_t);
- SAFE_MALLOC(curve->vertex, n, dpoint_t);
- SAFE_MALLOC(curve->alpha, n, double);
- SAFE_MALLOC(curve->alpha0, n, double);
- SAFE_MALLOC(curve->beta, n, double);
+ SAFE_CALLOC(curve->tag, n, int);
+ SAFE_CALLOC(curve->c, n, dpoint3_t);
+ SAFE_CALLOC(curve->vertex, n, dpoint_t);
+ SAFE_CALLOC(curve->alpha, n, double);
+ SAFE_CALLOC(curve->alpha0, n, double);
+ SAFE_CALLOC(curve->beta, n, double);
return 0;
- malloc_error:
+ calloc_error:
free(curve->tag);
free(curve->c);
free(curve->vertex);
diff --git a/src/trace/potrace/curve.h b/src/trace/potrace/curve.h
index 6ceae0c3a..feb95b39b 100644
--- a/src/trace/potrace/curve.h
+++ b/src/trace/potrace/curve.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
diff --git a/src/trace/potrace/decompose.cpp b/src/trace/potrace/decompose.cpp
index 6c27a7ebf..7628b202d 100644
--- a/src/trace/potrace/decompose.cpp
+++ b/src/trace/potrace/decompose.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
@@ -15,6 +15,33 @@
#include "decompose.h"
#include "progress.h"
+/* ---------------------------------------------------------------------- */
+/* deterministically and efficiently hash (x,y) into a pseudo-random bit */
+
+static inline int detrand(int x, int y) {
+ unsigned int z;
+ static const unsigned char t[256] = {
+ /* non-linear sequence: constant term of inverse in GF(8),
+ mod x^8+x^4+x^3+x+1 */
+ 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
+ 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
+ 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ };
+
+ /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible
+ 5-bit sequence */
+ z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93;
+ z = t[z & 0xff] ^ t[(z>>8) & 0xff] ^ t[(z>>16) & 0xff] ^ t[(z>>24) & 0xff];
+ return z;
+}
/* ---------------------------------------------------------------------- */
/* auxiliary bitmap manipulations */
diff --git a/src/trace/potrace/decompose.h b/src/trace/potrace/decompose.h
index 89b01e504..8ae89b8ad 100644
--- a/src/trace/potrace/decompose.h
+++ b/src/trace/potrace/decompose.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
diff --git a/src/trace/potrace/greymap.cpp b/src/trace/potrace/greymap.cpp
index e116021c1..4ef2ec8df 100644
--- a/src/trace/potrace/greymap.cpp
+++ b/src/trace/potrace/greymap.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
@@ -9,8 +9,10 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <errno.h>
#include "greymap.h"
+#include "bitops.h"
#define INTBITS (8*sizeof(int))
@@ -22,10 +24,17 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp);
/* ---------------------------------------------------------------------- */
/* basic greymap routines */
-/* return new un-initialized greymap. NULL with errno on error */
-
+/* return new un-initialized greymap. NULL with errno on error.
+ Assumes w, h >= 0. */
greymap_t *gm_new(int w, int h) {
greymap_t *gm;
+ ssize_t size = (ssize_t)w * (ssize_t)h * (ssize_t)sizeof(signed short int);
+
+ /* check for overflow error */
+ if (size < 0 || size / w / h != sizeof(signed short int)) {
+ errno = ENOMEM;
+ return NULL;
+ }
gm = (greymap_t *) malloc(sizeof(greymap_t));
if (!gm) {
@@ -33,7 +42,7 @@ greymap_t *gm_new(int w, int h) {
}
gm->w = w;
gm->h = h;
- gm->map = (signed short int *) malloc(w*h*sizeof(signed short int));
+ gm->map = (signed short int *) malloc(size);
if (!gm->map) {
free(gm);
return NULL;
@@ -405,6 +414,10 @@ struct bmp_info_s {
unsigned int YpixelsPerM;
unsigned int ncolors; /* number of colors in palette */
unsigned int ColorsImportant;
+ unsigned int RedMask;
+ unsigned int GreenMask;
+ unsigned int BlueMask;
+ unsigned int AlphaMask;
unsigned int ctbits; /* sample size for color table */
int topdown; /* top-down mode? */
};
@@ -495,6 +508,7 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
int col[2];
unsigned int bitbuf;
unsigned int n;
+ unsigned int redshift, greenshift, blueshift;
gm_read_error = NULL;
gm = NULL;
@@ -523,12 +537,24 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
- if ((signed int)bmpinfo.h < 0) {
- bmpinfo.h = -bmpinfo.h;
+ if (bmpinfo.InfoSize >= 108) { /* V4 and V5 bitmaps */
+ TRY(bmp_readint(f, 4, &bmpinfo.RedMask));
+ TRY(bmp_readint(f, 4, &bmpinfo.GreenMask));
+ TRY(bmp_readint(f, 4, &bmpinfo.BlueMask));
+ TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask));
+ }
+ if (bmpinfo.w > 0x7fffffff) {
+ goto format_error;
+ }
+ if (bmpinfo.h > 0x7fffffff) {
+ bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
bmpinfo.topdown = 1;
} else {
bmpinfo.topdown = 0;
}
+ if (bmpinfo.h > 0x7fffffff) {
+ goto format_error;
+ }
} else if (bmpinfo.InfoSize == 12) {
/* old OS/2 format */
bmpinfo.ctbits = 24; /* sample size in color table */
@@ -543,6 +569,11 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
goto format_error;
}
+ if (bmpinfo.comp == 3 && bmpinfo.InfoSize < 108) {
+ /* bitfield feature is only understood with V4 and V5 format */
+ goto format_error;
+ }
+
/* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
@@ -557,7 +588,7 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
/* color table, present only if bmpinfo.bits <= 8. */
if (bmpinfo.bits <= 8) {
- coltable = (int *) malloc(bmpinfo.ncolors * sizeof(int));
+ coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int));
if (!coltable) {
goto std_error;
}
@@ -651,6 +682,22 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
}
break;
+ case 0x320: /* 32-bit encoding with bitfields */
+ redshift = lobit(bmpinfo.RedMask);
+ greenshift = lobit(bmpinfo.GreenMask);
+ blueshift = lobit(bmpinfo.BlueMask);
+
+ for (y=0; y<bmpinfo.h; y++) {
+ bmp_pad_reset();
+ for (x=0; x<bmpinfo.w; x++) {
+ TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
+ c = ((c & bmpinfo.RedMask) >> redshift) + ((c & bmpinfo.GreenMask) >> greenshift) + ((c & bmpinfo.BlueMask) >> blueshift);
+ GM_UPUT(gm, x, ycorr(y), c/3);
+ }
+ TRY(bmp_pad(f));
+ }
+ break;
+
case 0x204: /* 4-bit runlength compressed encoding (RLE4) */
x = 0;
y = 0;
diff --git a/src/trace/potrace/greymap.h b/src/trace/potrace/greymap.h
index 1fb5426c1..8c9db9bbf 100644
--- a/src/trace/potrace/greymap.h
+++ b/src/trace/potrace/greymap.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
@@ -7,6 +7,7 @@
#define GREYMAP_H
#include <stdio.h>
+#include <stdlib.h>
/* internal format for greymaps. Note: in this format, rows are
ordered from bottom to top. The pixels in each row are given from
@@ -22,7 +23,7 @@ typedef struct greymap_s greymap_t;
/* macros for accessing pixel at index (x,y). Note that the origin is
in the *lower* left corner. U* macros omit the bounds check. */
-#define gm_index(gm, x, y) (&(gm)->map[(x)+(y)*(gm)->w])
+#define gm_index(gm, x, y) (&(gm)->map[(x)+(y)*(ssize_t)(gm)->w])
#define gm_safe(gm, x, y) ((int)(x)>=0 && (int)(x)<(gm)->w && (int)(y)>=0 && (int)(y)<(gm)->h)
#define gm_bound(x, m) ((x)<0 ? 0 : (x)>=(m) ? (m)-1 : (x))
#define GM_UGET(gm, x, y) (*gm_index(gm, x, y))
diff --git a/src/trace/potrace/lists.h b/src/trace/potrace/lists.h
index 078129afc..394262c23 100644
--- a/src/trace/potrace/lists.h
+++ b/src/trace/potrace/lists.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
diff --git a/src/trace/potrace/potracelib.cpp b/src/trace/potrace/potracelib.cpp
index 0fb835593..b5463d676 100644
--- a/src/trace/potrace/potracelib.cpp
+++ b/src/trace/potrace/potracelib.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
diff --git a/src/trace/potrace/potracelib.h b/src/trace/potrace/potracelib.h
index cd142a6e1..0a6ddbf1f 100644
--- a/src/trace/potrace/potracelib.h
+++ b/src/trace/potrace/potracelib.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
diff --git a/src/trace/potrace/progress.h b/src/trace/potrace/progress.h
index 3e1dfb34e..ecc2ba217 100644
--- a/src/trace/potrace/progress.h
+++ b/src/trace/potrace/progress.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
diff --git a/src/trace/potrace/render.cpp b/src/trace/potrace/render.cpp
index 3c8f79c05..4f44ae6a6 100644
--- a/src/trace/potrace/render.cpp
+++ b/src/trace/potrace/render.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
@@ -52,7 +52,7 @@ render_t *render_new(greymap_t *gm) {
}
memset(rm, 0, sizeof(render_t));
rm->gm = gm;
- rm->incrow_buf = (int *) malloc(gm->h * sizeof(int));
+ rm->incrow_buf = (int *) calloc(gm->h, sizeof(int));
if (!rm->incrow_buf) {
free(rm);
return NULL;
diff --git a/src/trace/potrace/render.h b/src/trace/potrace/render.h
index ad600156a..0caaedff6 100644
--- a/src/trace/potrace/render.h
+++ b/src/trace/potrace/render.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
diff --git a/src/trace/potrace/trace.cpp b/src/trace/potrace/trace.cpp
index f1e88a908..469262b67 100644
--- a/src/trace/potrace/trace.cpp
+++ b/src/trace/potrace/trace.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
@@ -21,8 +21,8 @@
#define COS179 -0.999847695156 /* the cosine of 179 degrees */
/* ---------------------------------------------------------------------- */
-#define SAFE_MALLOC(var, n, typ) \
- if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error
+#define SAFE_CALLOC(var, n, typ) \
+ if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error
/* ---------------------------------------------------------------------- */
/* auxiliary functions */
@@ -265,7 +265,7 @@ static int calc_sums(privpath_t *pp) {
int i, x, y;
int n = pp->len;
- SAFE_MALLOC(pp->sums, pp->len+1, sums_t);
+ SAFE_CALLOC(pp->sums, pp->len+1, sums_t);
/* origin */
pp->x0 = pp->pt[0].x;
@@ -284,7 +284,7 @@ static int calc_sums(privpath_t *pp) {
}
return 0;
- malloc_error:
+ calloc_error:
return 1;
}
@@ -331,8 +331,8 @@ static int calc_lon(privpath_t *pp) {
point_t dk; /* direction of k-k1 */
int a, b, c, d;
- SAFE_MALLOC(pivk, n, int);
- SAFE_MALLOC(nc, n, int);
+ SAFE_CALLOC(pivk, n, int);
+ SAFE_CALLOC(nc, n, int);
/* initialize the nc data structure. Point from each point to the
furthest future point to which it is connected by a vertical or
@@ -349,7 +349,7 @@ static int calc_lon(privpath_t *pp) {
nc[i] = k;
}
- SAFE_MALLOC(pp->lon, n, int);
+ SAFE_CALLOC(pp->lon, n, int);
/* determine pivot points: for each i, let pivk[i] be the furthest k
such that all j with i<j<k lie on a line connecting i,k. */
@@ -458,7 +458,7 @@ static int calc_lon(privpath_t *pp) {
free(nc);
return 0;
- malloc_error:
+ calloc_error:
free(pivk);
free(nc);
return 1;
@@ -537,12 +537,12 @@ static int bestpolygon(privpath_t *pp)
double best;
int c;
- SAFE_MALLOC(pen, n+1, double);
- SAFE_MALLOC(prev, n+1, int);
- SAFE_MALLOC(clip0, n, int);
- SAFE_MALLOC(clip1, n+1, int);
- SAFE_MALLOC(seg0, n+1, int);
- SAFE_MALLOC(seg1, n+1, int);
+ SAFE_CALLOC(pen, n+1, double);
+ SAFE_CALLOC(prev, n+1, int);
+ SAFE_CALLOC(clip0, n, int);
+ SAFE_CALLOC(clip1, n+1, int);
+ SAFE_CALLOC(seg0, n+1, int);
+ SAFE_CALLOC(seg1, n+1, int);
/* calculate clipped paths */
for (i=0; i<n; i++) {
@@ -604,7 +604,7 @@ static int bestpolygon(privpath_t *pp)
}
pp->m = m;
- SAFE_MALLOC(pp->po, m, int);
+ SAFE_CALLOC(pp->po, m, int);
/* read off shortest path */
for (i=n, j=m-1; i>0; j--) {
@@ -620,7 +620,7 @@ static int bestpolygon(privpath_t *pp)
free(seg1);
return 0;
- malloc_error:
+ calloc_error:
free(pen);
free(prev);
free(clip0);
@@ -655,13 +655,13 @@ static int adjust_vertices(privpath_t *pp) {
dpoint_t s;
int r;
- SAFE_MALLOC(ctr, m, dpoint_t);
- SAFE_MALLOC(dir, m, dpoint_t);
- SAFE_MALLOC(q, m, quadform_t);
+ SAFE_CALLOC(ctr, m, dpoint_t);
+ SAFE_CALLOC(dir, m, dpoint_t);
+ SAFE_CALLOC(q, m, quadform_t);
r = privcurve_init(&pp->curve, m);
if (r) {
- goto malloc_error;
+ goto calloc_error;
}
/* calculate "optimal" point-slope representation for each line
@@ -827,7 +827,7 @@ static int adjust_vertices(privpath_t *pp) {
free(q);
return 0;
- malloc_error:
+ calloc_error:
free(ctr);
free(dir);
free(q);
@@ -875,7 +875,7 @@ static void smooth(privcurve_t *curve, double alphamax) {
}
curve->alpha0[j] = alpha; /* remember "original" value of alpha */
- if (alpha > alphamax) { /* pointed corner */
+ if (alpha >= alphamax) { /* pointed corner */
curve->tag[j] = POTRACE_CORNER;
curve->c[j][1] = curve->vertex[j];
curve->c[j][2] = p4;
@@ -1075,12 +1075,12 @@ static int opticurve(privpath_t *pp, double opttolerance) {
int *convc = NULL; /* conv[m]: pre-computed convexities */
double *areac = NULL; /* cumarea[m+1]: cache for fast area computation */
- SAFE_MALLOC(pt, m+1, int);
- SAFE_MALLOC(pen, m+1, double);
- SAFE_MALLOC(len, m+1, int);
- SAFE_MALLOC(opt, m+1, opti_t);
- SAFE_MALLOC(convc, m, int);
- SAFE_MALLOC(areac, m+1, double);
+ SAFE_CALLOC(pt, m+1, int);
+ SAFE_CALLOC(pen, m+1, double);
+ SAFE_CALLOC(len, m+1, int);
+ SAFE_CALLOC(opt, m+1, opti_t);
+ SAFE_CALLOC(convc, m, int);
+ SAFE_CALLOC(areac, m+1, double);
/* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */
for (i=0; i<m; i++) {
@@ -1134,10 +1134,10 @@ static int opticurve(privpath_t *pp, double opttolerance) {
om = len[m];
r = privcurve_init(&pp->ocurve, om);
if (r) {
- goto malloc_error;
+ goto calloc_error;
}
- SAFE_MALLOC(s, om, double);
- SAFE_MALLOC(t, om, double);
+ SAFE_CALLOC(s, om, double);
+ SAFE_CALLOC(t, om, double);
j = m;
for (i=om-1; i>=0; i--) {
@@ -1182,7 +1182,7 @@ static int opticurve(privpath_t *pp, double opttolerance) {
free(areac);
return 0;
- malloc_error:
+ calloc_error:
free(pt);
free(pen);
free(len);
diff --git a/src/trace/potrace/trace.h b/src/trace/potrace/trace.h
index dc2b9247a..c53cdd10f 100644
--- a/src/trace/potrace/trace.h
+++ b/src/trace/potrace/trace.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2011 Peter Selinger.
+/* Copyright (C) 2001-2015 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 674254686..991d11feb 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -1,11 +1,10 @@
-
set(ui_SRC
clipboard.cpp
control-manager.cpp
dialog-events.cpp
draw-anchor.cpp
- interface.cpp
- object-edit.cpp
+ interface.cpp
+ object-edit.cpp
previewholder.cpp
shape-editor.cpp
tool-factory.cpp
@@ -56,8 +55,8 @@ set(ui_SRC
dialog/aboutbox.cpp
dialog/align-and-distribute.cpp
dialog/calligraphic-profile-rename.cpp
- dialog/color-item.cpp
dialog/clonetiler.cpp
+ dialog/color-item.cpp
dialog/debug.cpp
dialog/desktop-tracker.cpp
dialog/dialog-manager.cpp
@@ -86,31 +85,36 @@ set(ui_SRC
dialog/livepatheffect-add.cpp
dialog/livepatheffect-editor.cpp
dialog/lpe-fillet-chamfer-properties.cpp
+ dialog/lpe-powerstroke-properties.cpp
dialog/memory.cpp
dialog/messages.cpp
dialog/new-from-template.cpp
dialog/object-attributes.cpp
dialog/object-properties.cpp
+ dialog/objects.cpp
dialog/ocaldialogs.cpp
+ dialog/pixelartdialog.cpp
dialog/polar-arrange-tab.cpp
dialog/print-colors-preview-dialog.cpp
dialog/print.cpp
- dialog/symbols.cpp
- dialog/xml-tree.cpp
dialog/spellcheck.cpp
dialog/svg-fonts-dialog.cpp
dialog/swatches.cpp
+ dialog/symbols.cpp
+ dialog/tags.cpp
dialog/template-load-tab.cpp
dialog/template-widget.cpp
dialog/text-edit.cpp
dialog/tile.cpp
dialog/tracedialog.cpp
- dialog/pixelartdialog.cpp
dialog/transformation.cpp
dialog/undo-history.cpp
+ dialog/xml-tree.cpp
+ widget/addtoicon.cpp
widget/anchor-selector.cpp
widget/button.cpp
+ widget/clipmaskicon.cpp
widget/color-picker.cpp
widget/color-preview.cpp
widget/dock-item.cpp
@@ -121,10 +125,13 @@ set(ui_SRC
widget/frame.cpp
widget/gimpcolorwheel.c
widget/gimpspinscale.c
+ widget/highlight-picker.cpp
widget/imageicon.cpp
widget/imagetoggler.cpp
+ widget/insertordericon.cpp
widget/labelled.cpp
widget/layer-selector.cpp
+ widget/layertypeicon.cpp
widget/licensor.cpp
widget/notebook-page.cpp
widget/object-composite-settings.cpp
@@ -179,8 +186,8 @@ set(ui_SRC
dialog/arrange-tab.h
dialog/behavior.h
dialog/calligraphic-profile-rename.h
- dialog/color-item.h
dialog/clonetiler.h
+ dialog/color-item.h
dialog/debug.h
dialog/desktop-tracker.h
dialog/dialog-manager.h
@@ -200,8 +207,8 @@ set(ui_SRC
dialog/floating-behavior.h
dialog/font-substitution.h
dialog/glyphs.h
- dialog/guides.h
dialog/grid-arrange-tab.h
+ dialog/guides.h
dialog/icon-preview.h
dialog/inkscape-preferences.h
dialog/input.h
@@ -215,13 +222,13 @@ set(ui_SRC
dialog/new-from-template.h
dialog/object-attributes.h
dialog/object-properties.h
+ dialog/objects.h
dialog/ocaldialogs.h
dialog/panel-dialog.h
- dialog/polar-arrange-tab.h
dialog/pixelartdialog.h
+ dialog/polar-arrange-tab.h
dialog/print-colors-preview-dialog.h
dialog/print.h
-
dialog/spellcheck.h
dialog/svg-fonts-dialog.h
dialog/swatches.h
diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp
index 3da0e0043..077c6f5ca 100644
--- a/src/ui/dialog/filter-effects-dialog.cpp
+++ b/src/ui/dialog/filter-effects-dialog.cpp
@@ -211,7 +211,7 @@ private:
ComboBoxEnum<T>* combo;
};
-// Contains an arbitrary number of spin buttons that use seperate attributes
+// Contains an arbitrary number of spin buttons that use separate attributes
class MultiSpinButton : public Gtk::HBox
{
public:
diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp
index 49c949107..a90dfb155 100644
--- a/src/ui/tool/curve-drag-point.cpp
+++ b/src/ui/tool/curve-drag-point.cpp
@@ -54,7 +54,7 @@ bool CurveDragPoint::grabbed(GdkEventMotion */*event*/)
// delta is a vector equal 1/3 of distance from first to second
Geom::Point delta = (second->position() - first->position()) / 3.0;
// only update the nodes if the mode is bspline
- if(!_pm.isBSpline(false)){
+ if(!_pm.isBSpline()){
first->front()->move(first->front()->position() + delta);
second->back()->move(second->back()->position() - delta);
}
@@ -91,7 +91,7 @@ void CurveDragPoint::dragged(Geom::Point &new_pos, GdkEventMotion *event)
Geom::Point offset1 = (weight/(3*t*t*(1-t))) * delta;
//modified so that, if the trace is bspline, it only acts if the SHIFT key is pressed
- if(!_pm.isBSpline(false)){
+ if(!_pm.isBSpline()){
first->front()->move(first->front()->position() + offset0);
second->back()->move(second->back()->position() + offset1);
}else if(weight>=0.8){
diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h
index cdbf34e9d..1bbcdd7ec 100644
--- a/src/ui/tool/multi-path-manipulator.h
+++ b/src/ui/tool/multi-path-manipulator.h
@@ -39,7 +39,7 @@ public:
virtual bool event(Inkscape::UI::Tools::ToolBase *, GdkEvent *event);
bool empty() { return _mmap.empty(); }
- unsigned size() { return _mmap.empty(); }
+ unsigned size() { return _mmap.size(); }
void setItems(std::set<ShapeRecord> const &);
void clear() { _mmap.clear(); }
void cleanup();
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index eeea47e4d..08cc6708d 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -192,7 +192,7 @@ void Handle::move(Geom::Point const &new_pos)
setRelativePos(new_delta);
//move the handler and its oposite the same proportion
- if(_pm().isBSpline()){
+ if(_pm().isBSpline()){
setPosition(_pm().BSplineHandleReposition(this,this));
this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),this));
}
@@ -222,7 +222,6 @@ void Handle::move(Geom::Point const &new_pos)
setPosition(_pm().BSplineHandleReposition(this,this));
this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),this));
}
-
}
void Handle::setPosition(Geom::Point const &p)
@@ -382,7 +381,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
std::vector<Inkscape::SnapCandidatePoint> unselected;
//if the snap adjustment is activated and it is not bspline
- if (snap && !_pm().isBSpline(false)) {
+ if (snap && !_pm().isBSpline()) {
ControlPointSelection::Set &nodes = _parent->_selection.allPoints();
for (ControlPointSelection::Set::iterator i = nodes.begin(); i != nodes.end(); ++i) {
Node *n = static_cast<Node*>(*i);
@@ -486,7 +485,7 @@ Glib::ustring Handle::_getTip(unsigned state) const
char const *more;
// a trick to mark as bspline if the node has no strength, we are going to use it later
// to show the appropiate messages. We cannot do it in any different way becasue the function is constant
-
+ Handle *h = const_cast<Handle *>(this);
bool isBSpline = _pm().isBSpline();
bool can_shift_rotate = _parent->type() == NODE_CUSP && !other()->isDegenerate();
if (can_shift_rotate && !isBSpline) {
@@ -550,7 +549,7 @@ Glib::ustring Handle::_getTip(unsigned state) const
"<b>Auto node handle</b>: drag to convert to smooth node (%s)"), more);
}else{
return format_tip(C_("Path handle tip",
- "<b>BSpline node handle</b>: Shift to drag, double click to reset (%s)"), more);
+ "<b>BSpline node handle</b>: Shift to drag, double click to reset (%s). %g power"),more,_pm().BSplineHandlePosition(h,NULL));
}
}
}
@@ -1435,6 +1434,8 @@ Node *Node::nodeAwayFrom(Handle *h)
Glib::ustring Node::_getTip(unsigned state) const
{
bool isBSpline = _pm().isBSpline();
+ Handle *h = const_cast<Handle *>(&_front);
+ Handle *h2 = const_cast<Handle *>(&_back);
if (state_held_shift(state)) {
bool can_drag_out = (_next() && _front.isDegenerate()) || (_prev() && _back.isDegenerate());
if (can_drag_out) {
@@ -1469,7 +1470,7 @@ Glib::ustring Node::_getTip(unsigned state) const
"<b>%s</b>: drag to shape the path (more: Shift, Ctrl, Alt)"), nodetype);
}else if(_selection.size() == 1){
return format_tip(C_("Path node tip",
- "<b>BSpline node</b>: %g weight, drag to shape the path (more: Shift, Ctrl, Alt)"),noPower/*this->bsplineWeight*/);
+ "<b>BSpline node</b>: drag to shape the path (more: Shift, Ctrl, Alt). %g power"),_pm().BSplineHandlePosition(h,h2));
}
return format_tip(C_("Path node tip",
"<b>%s</b>: drag to shape the path, click to toggle scale/rotation handles (more: Shift, Ctrl, Alt)"), nodetype);
@@ -1479,7 +1480,7 @@ Glib::ustring Node::_getTip(unsigned state) const
"<b>%s</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype);
}else{
return format_tip(C_("Path node tip",
- "<b>BSpline node</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"));
+ "<b>BSpline node</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt). %g power"),_pm().BSplineHandlePosition(h,h2));
}
}
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index c8b986824..dbae69f2c 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -11,6 +11,7 @@
*/
#include "live_effects/lpe-powerstroke.h"
+#include "live_effects/lpe-bspline.h"
#include "live_effects/lpe-fillet-chamfer.h"
#include <string>
#include <sstream>
@@ -43,7 +44,6 @@
#include "ui/tool/multi-path-manipulator.h"
#include "xml/node.h"
#include "xml/node-observer.h"
-#include "live_effects/lpe-bspline.h"
namespace Inkscape {
namespace UI {
@@ -124,6 +124,7 @@ PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path,
, _show_path_direction(false)
, _live_outline(true)
, _live_objects(true)
+ , _is_bspline(false)
, _lpe_key(lpe_key)
{
if (_lpe_key.empty()) {
@@ -151,7 +152,7 @@ PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path,
_createControlPointsFromGeometry();
//Define if the path is BSpline on construction
- isBSpline(true);
+ recalculateIsBSpline();
}
PathManipulator::~PathManipulator()
@@ -1221,10 +1222,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;
@@ -1235,19 +1239,24 @@ int PathManipulator::BSplineGetSteps() const {
}
// determines if the trace has bspline effect
-bool PathManipulator::isBSpline(bool recalculate){
- if(recalculate){
- _is_bspline = this->BSplineGetSteps() > 0;
+void PathManipulator::recalculateIsBSpline(){
+ if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()) {
+ Inkscape::LivePathEffect::Effect const *thisEffect = _path->getPathEffectOfType(Inkscape::LivePathEffect::BSPLINE);
+ if(thisEffect){
+ _is_bspline = true;
+ return;
+ }
}
- return _is_bspline;
+ _is_bspline = false;
}
bool PathManipulator::isBSpline() const {
- return BSplineGetSteps() > 0;
+ return _is_bspline;
}
// returns the corresponding strength to the position of the handlers
-double PathManipulator::BSplineHandlePosition(Handle *h, Handle *h2){
+double PathManipulator::BSplineHandlePosition(Handle *h, Handle *h2)
+{
using Geom::X;
using Geom::Y;
if(h2){
@@ -1272,7 +1281,8 @@ double PathManipulator::BSplineHandlePosition(Handle *h, Handle *h2){
}
// give the location for the handler in the corresponding position
-Geom::Point PathManipulator::BSplineHandleReposition(Handle *h, Handle *h2){
+Geom::Point PathManipulator::BSplineHandleReposition(Handle *h, Handle *h2)
+{
double pos = this->BSplineHandlePosition(h, h2);
return BSplineHandleReposition(h,pos);
}
@@ -1309,7 +1319,7 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE)
{
Geom::PathBuilder builder;
//Refresh if is bspline some times -think on path change selection, this value get lost
- isBSpline(true);
+ recalculateIsBSpline();
for (std::list<SubpathPtr>::iterator spi = _subpaths.begin(); spi != _subpaths.end(); ) {
SubpathPtr subpath = *spi;
if (subpath->empty()) {
@@ -1338,15 +1348,15 @@ 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 (SP_IS_LPE_ITEM(_path) && _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);
+ thisEffect = _path->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER);
if(thisEffect){
LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(thisEffect->getLPEObj()->get_lpe());
if (lpe_fll) {
diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h
index 4d2bf4300..6dc1c9d09 100644
--- a/src/ui/tool/path-manipulator.h
+++ b/src/ui/tool/path-manipulator.h
@@ -107,7 +107,7 @@ private:
void _createControlPointsFromGeometry();
- bool isBSpline(bool recalculate = false);
+ void recalculateIsBSpline();
bool isBSpline() const;
double BSplineHandlePosition(Handle *h, Handle *h2 = NULL);
Geom::Point BSplineHandleReposition(Handle *h, Handle *h2 = NULL);
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 8e647ebb4..0a5697661 100644
--- a/src/ui/widget/page-sizer.cpp
+++ b/src/ui/widget/page-sizer.cpp
@@ -242,7 +242,13 @@ PageSizer::PageSizer(Registry & _wr)
_marginBottom( _("Botto_m:"), _("Bottom margin"), "fit-margin-bottom", _wr),
_lockMarginUpdate(false),
_scaleX(_("Scale _x:"), _("Scale X"), "scale-x", _wr),
+ _scaleY(_("Scale _y:"), _("Scale Y"), "scale-y", _wr),
_lockScaleUpdate(false),
+ _viewboxX(_("X:"), _("X"), "viewbox-x", _wr),
+ _viewboxY(_("Y:"), _("Y"), "viewbox-y", _wr),
+ _viewboxW(_("Width:"), _("Width"), "viewbox-width", _wr),
+ _viewboxH(_("Height:"), _("Height"), "viewbox-height", _wr),
+ _lockViewboxUpdate(false),
_widgetRegistry(&_wr)
{
// set precision of scalar entry boxes
@@ -254,7 +260,21 @@ PageSizer::PageSizer(Registry & _wr)
_marginRight.setDigits(5);
_marginBottom.setDigits(5);
_scaleX.setDigits(5);
+ _scaleY.setDigits(5);
+ _viewboxX.setDigits(2);
+ _viewboxY.setDigits(2);
+ _viewboxW.setDigits(2);
+ _viewboxH.setDigits(2);
+
_scaleX.setRange( 0.00001, 100000 );
+ _scaleY.setRange( 0.00001, 100000 );
+ _viewboxX.setRange( -100000, 100000 );
+ _viewboxY.setRange( -100000, 100000 );
+ _viewboxW.setRange( 0, 200000 );
+ _viewboxH.setRange( 0, 200000 );
+
+ _scaleY.set_sensitive (false); // We only want to display Y scale.
+
_wr.setUpdating (false);
//# Set up the Paper Size combo box
@@ -435,21 +455,62 @@ PageSizer::PageSizer(Registry & _wr)
_scaleTable.set_row_spacing(4);
_scaleTable.set_column_spacing(4);
- _dimensionWidth.set_hexpand();
- _dimensionWidth.set_vexpand();
_scaleTable.attach(_scaleX, 0, 0, 1, 1);
+ _scaleTable.attach(_scaleY, 1, 0, 1, 1);
- _dimensionUnits.set_hexpand();
- _dimensionUnits.set_vexpand();
- _scaleTable.attach(_scaleLabel, 1, 0, 1, 1);
+ _scaleTable.attach(_scaleLabel, 2, 0, 1, 1);
+ _scaleTable.attach(_scaleWarning, 0, 1, 2, 1);
+ _viewboxExpander.set_hexpand();
+ _viewboxExpander.set_vexpand();
+ _scaleTable.attach(_viewboxExpander, 0, 2, 2, 1);
#else
- _scaleTable.resize(2, 1);
+ _scaleTable.resize(3, 2);
_scaleTable.set_row_spacings(4);
_scaleTable.set_col_spacings(4);
_scaleTable.attach(_scaleX, 0,1, 0,1);
- _scaleTable.attach(_scaleLabel, 1,2, 0,1);
+ _scaleTable.attach(_scaleY, 1,2, 0,1);
+ _scaleTable.attach(_scaleLabel, 2,3, 0,1);
+ _scaleTable.attach(_scaleWarning, 0,3, 1,2, Gtk::FILL);
+ _scaleTable.attach(_viewboxExpander, 0,3, 2,3);
#endif
+ _scaleWarning.set_label(_("While SVG allows non-uniform scaling it is recommended to use only uniform scaling in Inkscape. To set a non-uniform scaling, set the 'viewBox' directly."));
+ _scaleWarning.set_line_wrap( true );
+
+ _viewboxExpander.set_use_underline();
+ _viewboxExpander.set_label(_("_Viewbox..."));
+ _viewboxExpander.add(_viewboxTable);
+
+#if WITH_GTKMM_3_0
+ _viewboxTable.set_row_spacing(2);
+ _viewboxTable.set_column_spacing(2);
+
+ _viewboxX.set_hexpand();
+ _viewboxX.set_vexpand();
+ _viewboxTable.attach(_viewboxX, 0, 0, 1, 1);
+
+ _viewboxY.set_hexpand();
+ _viewboxY.set_vexpand();
+ _viewboxTable.attach(_viewboxY, 1, 0, 1, 1);
+
+ _viewboxW.set_hexpand();
+ _viewboxW.set_vexpand();
+ _viewboxTable.attach(_viewboxW, 0, 1, 1, 1);
+
+ _viewboxH.set_hexpand();
+ _viewboxH.set_vexpand();
+ _viewboxTable.attach(_viewboxH, 1, 1, 1, 1);
+
+#else
+ _viewboxTable.set_border_width(4);
+ _viewboxTable.set_row_spacings(2);
+ _viewboxTable.set_col_spacings(2);
+ _viewboxTable.attach(_viewboxX, 0,1, 0,1);
+ _viewboxTable.attach(_viewboxY, 1,2, 0,1);
+ _viewboxTable.attach(_viewboxW, 0,1, 1,2);
+ _viewboxTable.attach(_viewboxH, 1,2, 1,2);
+#endif
+
_wr.setUpdating (true);
updateScaleUI();
_wr.setUpdating (false);
@@ -478,7 +539,11 @@ PageSizer::init ()
_changedh_connection = _dimensionHeight.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_value_changed));
_changedu_connection = _dimensionUnits.getUnitMenu()->signal_changed().connect (sigc::mem_fun (*this, &PageSizer::on_units_changed));
_fitPageButton.signal_clicked().connect(sigc::mem_fun(*this, &PageSizer::fire_fit_canvas_to_selection_or_drawing));
- _changeds_connection = _scaleX.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_scale_changed));
+ _changeds_connection = _scaleX.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_scale_changed));
+ _changedvx_connection = _viewboxX.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_viewbox_changed));
+ _changedvy_connection = _viewboxY.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_viewbox_changed));
+ _changedvw_connection = _viewboxW.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_viewbox_changed));
+ _changedvh_connection = _viewboxH.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_viewbox_changed));
show_all_children();
}
@@ -744,10 +809,6 @@ void
PageSizer::updateScaleUI()
{
- if (_lockScaleUpdate) {
- return;
- }
-
static bool _called = false;
if (_called) {
return;
@@ -756,28 +817,56 @@ PageSizer::updateScaleUI()
_called = true;
_changeds_connection.block();
+ _changedvx_connection.block();
+ _changedvy_connection.block();
+ _changedvw_connection.block();
+ _changedvh_connection.block();
SPDesktop *dt = SP_ACTIVE_DESKTOP;
if (dt) {
SPDocument *doc = dt->getDocument();
+
+ // Update scale
Geom::Scale scale = doc->getDocumentScale();
-
SPNamedView *nv = dt->getNamedView();
std::stringstream ss;
ss << _("User units per ") << nv->display_units->abbr << "." ;
_scaleLabel.set_text( ss.str() );
- double scaleX_inv =
- Inkscape::Util::Quantity::convert( scale[Geom::X], "px", nv->display_units );
- if( scaleX_inv > 0 ) {
- _scaleX.setValue(1.0/scaleX_inv);
- } else {
- // Should never happen
- std::cerr << "PageSizer::updateScaleUI(): Invalid scale value: " << scaleX_inv << std::endl;
- _scaleX.setValue(1.0);
+ if( !_lockScaleUpdate ) {
+
+ double scaleX_inv =
+ Inkscape::Util::Quantity::convert( scale[Geom::X], "px", nv->display_units );
+ if( scaleX_inv > 0 ) {
+ _scaleX.setValue(1.0/scaleX_inv);
+ } else {
+ // Should never happen
+ std::cerr << "PageSizer::updateScaleUI(): Invalid scale value: " << scaleX_inv << std::endl;
+ _scaleX.setValue(1.0);
+ }
+ }
+
+ { // Don't need to lock as scaleY widget not linked to callback.
+ double scaleY_inv =
+ Inkscape::Util::Quantity::convert( scale[Geom::Y], "px", nv->display_units );
+ if( scaleY_inv > 0 ) {
+ _scaleY.setValue(1.0/scaleY_inv);
+ } else {
+ // Should never happen
+ std::cerr << "PageSizer::updateScaleUI(): Invalid scale value: " << scaleY_inv << std::endl;
+ _scaleY.setValue(1.0);
+ }
}
+ if( !_lockViewboxUpdate ) {
+ Geom::Rect viewBox = doc->getViewBox();
+ _viewboxX.setValue( viewBox.min()[Geom::X] );
+ _viewboxY.setValue( viewBox.min()[Geom::Y] );
+ _viewboxW.setValue( viewBox.width() );
+ _viewboxH.setValue( viewBox.height() );
+ }
+
} else {
// Should never happen
std::cerr << "PageSizer::updateScaleUI(): No active desktop." << std::endl;
@@ -785,6 +874,10 @@ PageSizer::updateScaleUI()
}
_changeds_connection.unblock();
+ _changedvx_connection.unblock();
+ _changedvy_connection.unblock();
+ _changedvw_connection.unblock();
+ _changedvh_connection.unblock();
_called = false;
}
@@ -801,6 +894,7 @@ PageSizer::on_value_changed()
setDim (Inkscape::Util::Quantity(_dimensionWidth.getValue(""), _dimensionUnits.getUnit()),
Inkscape::Util::Quantity(_dimensionHeight.getValue(""), _dimensionUnits.getUnit()));
}
+
void
PageSizer::on_units_changed()
{
@@ -830,13 +924,44 @@ PageSizer::on_scale_changed()
double scaleX_inv = Inkscape::Util::Quantity(1.0/value, nv->display_units ).value("px");
_lockScaleUpdate = true;
- doc->setDocumentScale( 1.0/scaleX_inv );
+ doc->setDocumentScale( 1.0/scaleX_inv );
+ updateScaleUI();
_lockScaleUpdate = false;
DocumentUndo::done(doc, SP_VERB_NONE, _("Set page scale"));
}
}
}
+/**
+ * Callback for viewbox widgets
+ */
+void
+PageSizer::on_viewbox_changed()
+{
+ if (_widgetRegistry->isUpdating()) return;
+
+ double viewboxX = _viewboxX.getValue();
+ double viewboxY = _viewboxY.getValue();
+ double viewboxW = _viewboxW.getValue();
+ double viewboxH = _viewboxH.getValue();
+
+ if( viewboxW > 0 && viewboxH > 0) {
+ SPDesktop *dt = SP_ACTIVE_DESKTOP;
+ if (dt) {
+ SPDocument *doc = dt->getDocument();
+ _lockViewboxUpdate = true;
+ doc->setViewBox( Geom::Rect::from_xywh( viewboxX, viewboxY, viewboxW, viewboxH ) );
+ updateScaleUI();
+ _lockViewboxUpdate = false;
+ DocumentUndo::done(doc, SP_VERB_NONE, _("Set 'viewBox'"));
+ }
+ } else {
+ std::cerr
+ << "PageSizer::on_viewbox_changed(): width and height must both be greater than zero."
+ << std::endl;
+ }
+}
+
} // namespace Widget
} // namespace UI
} // namespace Inkscape
diff --git a/src/ui/widget/page-sizer.h b/src/ui/widget/page-sizer.h
index f9a72d9f3..0eea28e61 100644
--- a/src/ui/widget/page-sizer.h
+++ b/src/ui/widget/page-sizer.h
@@ -264,17 +264,38 @@ protected:
#endif
Gtk::Label _scaleLabel;
+ Gtk::Label _scaleWarning;
RegisteredScalar _scaleX;
+ RegisteredScalar _scaleY;
bool _lockScaleUpdate;
+ // Viewbox
+ Gtk::Expander _viewboxExpander;
+#if WITH_GTKMM_3_0
+ Gtk::Grid _viewboxTable;
+#else
+ Gtk::Table _viewboxTable;
+#endif
+
+ RegisteredScalar _viewboxX;
+ RegisteredScalar _viewboxY;
+ RegisteredScalar _viewboxW;
+ RegisteredScalar _viewboxH;
+ bool _lockViewboxUpdate;
+
//callback
void on_value_changed();
void on_units_changed();
void on_scale_changed();
+ void on_viewbox_changed();
sigc::connection _changedw_connection;
sigc::connection _changedh_connection;
sigc::connection _changedu_connection;
sigc::connection _changeds_connection;
+ sigc::connection _changedvx_connection;
+ sigc::connection _changedvy_connection;
+ sigc::connection _changedvw_connection;
+ sigc::connection _changedvh_connection;
Registry *_widgetRegistry;
diff --git a/src/uri-references.cpp b/src/uri-references.cpp
index b23bed74a..2518c173e 100644
--- a/src/uri-references.cpp
+++ b/src/uri-references.cpp
@@ -65,7 +65,7 @@ void URIReference::attach(const URI &uri) throw(BadURIException)
skip = true;
}
- // The path contains references to seperate document files to load.
+ // The path contains references to separate document files to load.
if(document && uri.getPath() && !skip ) {
std::string base = document->getBase() ? document->getBase() : "";
std::string path = uri.getFullPath(base);