summaryrefslogtreecommitdiffstats
path: root/src/live_effects
diff options
context:
space:
mode:
authorMichael Soegtrop <MSoegtrop@yahoo.de>2017-06-05 13:56:11 +0000
committerMichael Soegtrop <MSoegtrop@yahoo.de>2017-06-05 13:56:11 +0000
commit7ee81350c73388881e60a59928d26764b7172c9b (patch)
treeb561a4dbbacd7eecbdbae3fa220a353375ccecf8 /src/live_effects
parentupdated to trunk (diff)
parent[Bug #1695016] Xaml export misses some radialGradients. (diff)
downloadinkscape-7ee81350c73388881e60a59928d26764b7172c9b.tar.gz
inkscape-7ee81350c73388881e60a59928d26764b7172c9b.zip
merged with latest version of lpe-bool and trunk
(bzr r14862.2.3)
Diffstat (limited to 'src/live_effects')
-rw-r--r--src/live_effects/CMakeLists.txt16
-rw-r--r--src/live_effects/Makefile_insert119
-rw-r--r--src/live_effects/effect-enum.h75
-rw-r--r--src/live_effects/effect.cpp360
-rw-r--r--src/live_effects/effect.h37
-rw-r--r--src/live_effects/lpe-angle_bisector.cpp9
-rw-r--r--src/live_effects/lpe-attach-path.cpp12
-rw-r--r--src/live_effects/lpe-bendpath.cpp25
-rw-r--r--src/live_effects/lpe-bool.cpp602
-rw-r--r--src/live_effects/lpe-bool.h41
-rw-r--r--src/live_effects/lpe-bounding-box.cpp15
-rw-r--r--src/live_effects/lpe-bspline.cpp7
-rw-r--r--src/live_effects/lpe-bspline.h2
-rw-r--r--src/live_effects/lpe-circle_3pts.cpp3
-rw-r--r--src/live_effects/lpe-circle_with_radius.cpp3
-rw-r--r--src/live_effects/lpe-clone-original.cpp347
-rw-r--r--src/live_effects/lpe-clone-original.h36
-rw-r--r--src/live_effects/lpe-constructgrid.cpp11
-rw-r--r--src/live_effects/lpe-copy_rotate.cpp617
-rw-r--r--src/live_effects/lpe-copy_rotate.h44
-rw-r--r--src/live_effects/lpe-curvestitch.cpp41
-rw-r--r--src/live_effects/lpe-curvestitch.h1
-rw-r--r--src/live_effects/lpe-dynastroke.cpp30
-rw-r--r--src/live_effects/lpe-ellipse_5pts.cpp8
-rw-r--r--src/live_effects/lpe-embrodery-stitch-ordering.cpp1775
-rw-r--r--src/live_effects/lpe-embrodery-stitch-ordering.h454
-rw-r--r--src/live_effects/lpe-embrodery-stitch.cpp639
-rw-r--r--src/live_effects/lpe-embrodery-stitch.h60
-rw-r--r--src/live_effects/lpe-envelope.cpp36
-rw-r--r--src/live_effects/lpe-extrude.cpp13
-rw-r--r--src/live_effects/lpe-fill-between-many.cpp55
-rw-r--r--src/live_effects/lpe-fill-between-many.h8
-rw-r--r--src/live_effects/lpe-fill-between-strokes.cpp85
-rw-r--r--src/live_effects/lpe-fill-between-strokes.h7
-rw-r--r--src/live_effects/lpe-fillet-chamfer.cpp968
-rw-r--r--src/live_effects/lpe-fillet-chamfer.h66
-rw-r--r--src/live_effects/lpe-gears.cpp30
-rw-r--r--src/live_effects/lpe-gears.h1
-rw-r--r--src/live_effects/lpe-interpolate.cpp15
-rw-r--r--src/live_effects/lpe-interpolate_points.cpp5
-rw-r--r--src/live_effects/lpe-jointype.cpp17
-rw-r--r--src/live_effects/lpe-knot.cpp38
-rw-r--r--src/live_effects/lpe-knot.h2
-rw-r--r--src/live_effects/lpe-lattice.cpp49
-rw-r--r--src/live_effects/lpe-lattice.h2
-rw-r--r--src/live_effects/lpe-lattice2.cpp23
-rw-r--r--src/live_effects/lpe-lattice2.h6
-rw-r--r--src/live_effects/lpe-line_segment.cpp8
-rw-r--r--src/live_effects/lpe-measure-line.cpp763
-rw-r--r--src/live_effects/lpe-measure-line.h107
-rw-r--r--src/live_effects/lpe-mirror_symmetry.cpp485
-rw-r--r--src/live_effects/lpe-mirror_symmetry.h25
-rw-r--r--src/live_effects/lpe-offset.cpp13
-rw-r--r--src/live_effects/lpe-parallel.cpp15
-rw-r--r--src/live_effects/lpe-path_length.cpp24
-rw-r--r--src/live_effects/lpe-path_length.h2
-rw-r--r--src/live_effects/lpe-patternalongpath.cpp84
-rw-r--r--src/live_effects/lpe-patternalongpath.h2
-rw-r--r--src/live_effects/lpe-perp_bisector.cpp13
-rw-r--r--src/live_effects/lpe-perspective-envelope.cpp151
-rw-r--r--src/live_effects/lpe-perspective-envelope.h3
-rw-r--r--src/live_effects/lpe-perspective_path.cpp50
-rw-r--r--src/live_effects/lpe-perspective_path.h2
-rw-r--r--src/live_effects/lpe-powerstroke.cpp58
-rw-r--r--src/live_effects/lpe-recursiveskeleton.cpp13
-rw-r--r--src/live_effects/lpe-rough-hatches.cpp51
-rw-r--r--src/live_effects/lpe-roughen.cpp19
-rw-r--r--src/live_effects/lpe-roughen.h2
-rw-r--r--src/live_effects/lpe-ruler.cpp25
-rw-r--r--src/live_effects/lpe-show_handles.cpp43
-rw-r--r--src/live_effects/lpe-show_handles.h6
-rw-r--r--src/live_effects/lpe-simplify.cpp20
-rw-r--r--src/live_effects/lpe-simplify.h1
-rw-r--r--src/live_effects/lpe-skeleton.cpp13
-rw-r--r--src/live_effects/lpe-skeleton.h2
-rw-r--r--src/live_effects/lpe-sketch.cpp47
-rw-r--r--src/live_effects/lpe-spiro.cpp5
-rw-r--r--src/live_effects/lpe-tangent_to_curve.cpp24
-rw-r--r--src/live_effects/lpe-tangent_to_curve.h2
-rw-r--r--src/live_effects/lpe-taperstroke.cpp26
-rw-r--r--src/live_effects/lpe-taperstroke.h2
-rw-r--r--src/live_effects/lpe-test-doEffect-stack.cpp16
-rw-r--r--src/live_effects/lpe-text_label.cpp7
-rw-r--r--src/live_effects/lpe-transform_2pts.cpp43
-rw-r--r--src/live_effects/lpe-transform_2pts.h2
-rw-r--r--src/live_effects/lpe-vonkoch.cpp22
-rw-r--r--src/live_effects/lpegroupbbox.cpp2
-rw-r--r--src/live_effects/lpeobject-reference.cpp5
-rw-r--r--src/live_effects/lpeobject.cpp4
-rw-r--r--src/live_effects/lpeobject.h8
-rw-r--r--src/live_effects/parameter/Makefile_insert36
-rw-r--r--src/live_effects/parameter/array.cpp44
-rw-r--r--src/live_effects/parameter/array.h41
-rw-r--r--src/live_effects/parameter/bool.cpp22
-rw-r--r--src/live_effects/parameter/bool.h8
-rw-r--r--src/live_effects/parameter/enum.h21
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.cpp877
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.h123
-rw-r--r--src/live_effects/parameter/fontbutton.cpp97
-rw-r--r--src/live_effects/parameter/fontbutton.h61
-rw-r--r--src/live_effects/parameter/hidden.cpp90
-rw-r--r--src/live_effects/parameter/hidden.h69
-rw-r--r--src/live_effects/parameter/item-reference.cpp44
-rw-r--r--src/live_effects/parameter/item-reference.h56
-rw-r--r--src/live_effects/parameter/item.cpp253
-rw-r--r--src/live_effects/parameter/item.h80
-rw-r--r--src/live_effects/parameter/originalitem.cpp129
-rw-r--r--src/live_effects/parameter/originalitem.h49
-rw-r--r--src/live_effects/parameter/originalpath.cpp4
-rw-r--r--src/live_effects/parameter/originalpatharray.cpp4
-rw-r--r--src/live_effects/parameter/originalpatharray.h3
-rw-r--r--src/live_effects/parameter/parameter.cpp43
-rw-r--r--src/live_effects/parameter/parameter.h22
-rw-r--r--src/live_effects/parameter/path.cpp146
-rw-r--r--src/live_effects/parameter/path.h7
-rw-r--r--src/live_effects/parameter/point.cpp45
-rw-r--r--src/live_effects/parameter/point.h9
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.cpp4
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.h4
-rw-r--r--src/live_effects/parameter/random.cpp15
-rw-r--r--src/live_effects/parameter/random.h4
-rw-r--r--src/live_effects/parameter/satellitesarray.cpp584
-rw-r--r--src/live_effects/parameter/satellitesarray.h114
-rw-r--r--src/live_effects/parameter/text.cpp61
-rw-r--r--src/live_effects/parameter/text.h8
-rw-r--r--src/live_effects/parameter/togglebutton.cpp96
-rw-r--r--src/live_effects/parameter/togglebutton.h10
-rw-r--r--src/live_effects/parameter/transformedpoint.cpp19
-rw-r--r--src/live_effects/parameter/transformedpoint.h4
-rw-r--r--src/live_effects/parameter/unit.cpp7
-rw-r--r--src/live_effects/parameter/unit.h4
-rw-r--r--src/live_effects/parameter/vector.cpp28
-rw-r--r--src/live_effects/parameter/vector.h5
-rw-r--r--src/live_effects/spiro.cpp1
134 files changed, 7431 insertions, 4950 deletions
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt
index 9448afa76..5b192f40e 100644
--- a/src/live_effects/CMakeLists.txt
+++ b/src/live_effects/CMakeLists.txt
@@ -27,6 +27,7 @@ set(live_effects_SRC
lpe-lattice.cpp
lpe-lattice2.cpp
lpe-line_segment.cpp
+ lpe-measure-line.cpp
lpe-mirror_symmetry.cpp
lpe-offset.cpp
lpe-parallel.cpp
@@ -61,7 +62,10 @@ set(live_effects_SRC
parameter/array.cpp
parameter/bool.cpp
- parameter/filletchamferpointarray.cpp
+ parameter/hidden.cpp
+ parameter/item-reference.cpp
+ parameter/item.cpp
+ parameter/originalitem.cpp
parameter/originalpath.cpp
parameter/originalpatharray.cpp
parameter/parameter.cpp
@@ -69,8 +73,10 @@ set(live_effects_SRC
parameter/path.cpp
parameter/point.cpp
parameter/powerstrokepointarray.cpp
+ parameter/satellitesarray.cpp
parameter/random.cpp
parameter/text.cpp
+ parameter/fontbutton.cpp
parameter/togglebutton.cpp
parameter/transformedpoint.cpp
parameter/unit.cpp
@@ -108,6 +114,7 @@ set(live_effects_SRC
lpe-lattice.h
lpe-lattice2.h
lpe-line_segment.h
+ lpe-measure-line.h
lpe-mirror_symmetry.h
lpe-offset.h
lpe-parallel.h
@@ -143,8 +150,11 @@ set(live_effects_SRC
parameter/array.h
parameter/bool.h
+ parameter/hidden.h
parameter/enum.h
- parameter/filletchamferpointarray.h
+ parameter/item.h
+ parameter/item-reference.h
+ parameter/originalitem.h
parameter/originalpath.h
parameter/originalpatharray.h
parameter/parameter.h
@@ -152,8 +162,10 @@ set(live_effects_SRC
parameter/path.h
parameter/point.h
parameter/powerstrokepointarray.h
+ parameter/satellitesarray.h
parameter/random.h
parameter/text.h
+ parameter/fontbutton.h
parameter/togglebutton.h
parameter/transformedpoint.h
parameter/unit.h
diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert
deleted file mode 100644
index 40835ee9c..000000000
--- a/src/live_effects/Makefile_insert
+++ /dev/null
@@ -1,119 +0,0 @@
-## Makefile.am fragment sourced by src/Makefile.am.
-
-ink_common_sources += \
- live_effects/effect.cpp \
- live_effects/effect.h \
- live_effects/effect-enum.h \
- live_effects/lpeobject.cpp \
- live_effects/lpeobject.h \
- live_effects/lpegroupbbox.cpp \
- live_effects/lpegroupbbox.h \
- live_effects/lpeobject-reference.cpp \
- live_effects/lpeobject-reference.h \
- live_effects/lpe-patternalongpath.cpp \
- live_effects/lpe-patternalongpath.h \
- live_effects/lpe-bendpath.cpp \
- live_effects/lpe-bendpath.h \
- live_effects/lpe-dynastroke.cpp \
- live_effects/lpe-dynastroke.h \
- live_effects/lpe-extrude.cpp \
- live_effects/lpe-extrude.h \
- live_effects/lpe-sketch.cpp \
- live_effects/lpe-sketch.h \
- live_effects/lpe-knot.cpp \
- live_effects/lpe-knot.h \
- live_effects/lpe-vonkoch.cpp \
- live_effects/lpe-vonkoch.h \
- live_effects/lpe-rough-hatches.cpp \
- live_effects/lpe-rough-hatches.h \
- live_effects/lpe-curvestitch.cpp \
- live_effects/lpe-curvestitch.h \
- live_effects/lpe-constructgrid.cpp \
- live_effects/lpe-constructgrid.h \
- live_effects/lpe-fillet-chamfer.cpp \
- live_effects/lpe-fillet-chamfer.h \
- live_effects/lpe-gears.cpp \
- live_effects/lpe-gears.h \
- live_effects/lpe-interpolate.cpp \
- live_effects/lpe-interpolate.h \
- live_effects/lpe-interpolate_points.cpp \
- live_effects/lpe-interpolate_points.h \
- live_effects/lpe-test-doEffect-stack.cpp \
- live_effects/lpe-test-doEffect-stack.h \
- live_effects/lpe-bspline.cpp \
- live_effects/lpe-bspline.h \
- live_effects/lpe-lattice.cpp \
- live_effects/lpe-lattice.h \
- live_effects/lpe-lattice2.cpp \
- live_effects/lpe-lattice2.h \
- live_effects/lpe-roughen.cpp \
- live_effects/lpe-roughen.h \
- live_effects/lpe-show_handles.cpp \
- live_effects/lpe-show_handles.h \
- live_effects/lpe-simplify.cpp \
- live_effects/lpe-simplify.h \
- live_effects/lpe-envelope.cpp \
- live_effects/lpe-envelope.h \
- live_effects/lpe-spiro.cpp \
- live_effects/lpe-spiro.h \
- live_effects/lpe-tangent_to_curve.cpp \
- live_effects/lpe-tangent_to_curve.h \
- live_effects/lpe-perp_bisector.cpp \
- live_effects/lpe-perp_bisector.h \
- live_effects/spiro.h \
- live_effects/spiro.cpp \
- live_effects/spiro-converters.h \
- live_effects/spiro-converters.cpp \
- live_effects/lpe-circle_with_radius.cpp \
- live_effects/lpe-circle_with_radius.h \
- live_effects/lpe-perspective_path.cpp \
- live_effects/lpe-perspective_path.h \
- live_effects/lpe-perspective-envelope.cpp \
- live_effects/lpe-perspective-envelope.h \
- live_effects/lpe-mirror_symmetry.cpp \
- live_effects/lpe-mirror_symmetry.h \
- live_effects/lpe-circle_3pts.cpp \
- live_effects/lpe-circle_3pts.h \
- live_effects/lpe-transform_2pts.cpp \
- live_effects/lpe-transform_2pts.h \
- live_effects/lpe-angle_bisector.cpp \
- live_effects/lpe-angle_bisector.h \
- live_effects/lpe-parallel.cpp \
- live_effects/lpe-parallel.h \
- live_effects/lpe-copy_rotate.cpp \
- live_effects/lpe-copy_rotate.h \
- live_effects/lpe-powerstroke.cpp \
- live_effects/lpe-powerstroke.h \
- live_effects/lpe-powerstroke-interpolators.h \
- live_effects/lpe-offset.cpp \
- live_effects/lpe-offset.h \
- live_effects/lpe-clone-original.cpp \
- live_effects/lpe-clone-original.h \
- live_effects/lpe-ruler.cpp \
- live_effects/lpe-ruler.h \
- live_effects/lpe-recursiveskeleton.cpp \
- live_effects/lpe-recursiveskeleton.h \
- live_effects/lpe-text_label.cpp \
- live_effects/lpe-text_label.h \
- live_effects/lpe-path_length.cpp \
- live_effects/lpe-path_length.h \
- live_effects/lpe-line_segment.cpp \
- live_effects/lpe-line_segment.h \
- live_effects/lpe-bounding-box.cpp \
- live_effects/lpe-bounding-box.h \
- live_effects/lpe-attach-path.cpp \
- live_effects/lpe-attach-path.h \
- live_effects/lpe-fill-between-strokes.cpp \
- live_effects/lpe-fill-between-strokes.h \
- live_effects/lpe-fill-between-many.cpp \
- live_effects/lpe-fill-between-many.h \
- live_effects/lpe-ellipse_5pts.cpp \
- live_effects/lpe-ellipse_5pts.h \
- live_effects/lpe-jointype.cpp \
- live_effects/lpe-jointype.h \
- live_effects/lpe-taperstroke.cpp \
- live_effects/lpe-taperstroke.h \
- live_effects/lpe-bool.cpp \
- live_effects/lpe-bool.h \
- live_effects/lpe-embrodery-stitch.cpp \
- live_effects/lpe-embrodery-stitch.h
diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h
index 8680b4f2a..0ad9c5230 100644
--- a/src/live_effects/effect-enum.h
+++ b/src/live_effects/effect-enum.h
@@ -16,58 +16,57 @@ namespace LivePathEffect {
enum EffectType {
BEND_PATH = 0,
+ GEARS,
PATTERN_ALONG_PATH,
- FREEHAND_SHAPE,
- SKETCH,
- ROUGH_HATCHES,
+ CURVE_STITCH,
VONKOCH,
KNOT,
- GEARS,
- CURVE_STITCH,
- CIRCLE_WITH_RADIUS,
- PERSPECTIVE_PATH,
+ CONSTRUCT_GRID,
SPIRO,
- LATTICE,
- LATTICE2,
- ROUGHEN,
- SHOW_HANDLES,
- SIMPLIFY,
ENVELOPE,
- CONSTRUCT_GRID,
- PERP_BISECTOR,
- TANGENT_TO_CURVE,
- MIRROR_SYMMETRY,
- CIRCLE_3PTS,
- TRANSFORM_2PTS,
- ANGLE_BISECTOR,
- PARALLEL,
- COPY_ROTATE,
- OFFSET,
- RULER,
- BOOLOPS,
INTERPOLATE,
- INTERPOLATE_POINTS,
- TEXT_LABEL,
- PATH_LENGTH,
- LINE_SEGMENT,
- DOEFFECTSTACK_TEST,
- BSPLINE,
- DYNASTROKE,
- RECURSIVE_SKELETON,
- EXTRUDE,
+ ROUGH_HATCHES,
+ SKETCH,
+ RULER,
POWERSTROKE,
CLONE_ORIGINAL,
+ SIMPLIFY,
+ LATTICE2,
+ PERSPECTIVE_ENVELOPE,
+ INTERPOLATE_POINTS,
+ TRANSFORM_2PTS,
+ SHOW_HANDLES,
+ ROUGHEN,
+ BSPLINE,
+ JOIN_TYPE,
+ TAPER_STROKE,
+ MIRROR_SYMMETRY,
+ COPY_ROTATE,
+ EMBRODERY_STITCH,
+ BOOL_OP,
ATTACH_PATH,
FILL_BETWEEN_STROKES,
FILL_BETWEEN_MANY,
ELLIPSE_5PTS,
BOUNDING_BOX,
- JOIN_TYPE,
- TAPER_STROKE,
- PERSPECTIVE_ENVELOPE,
+ MEASURE_LINE,
FILLET_CHAMFER,
- EMBRODERY_STITCH,
- BOOL_OP,
+ DOEFFECTSTACK_TEST,
+ ANGLE_BISECTOR,
+ CIRCLE_WITH_RADIUS,
+ CIRCLE_3PTS,
+ DYNASTROKE,
+ EXTRUDE,
+ LATTICE,
+ LINE_SEGMENT,
+ OFFSET,
+ PARALLEL,
+ PATH_LENGTH,
+ PERP_BISECTOR,
+ PERSPECTIVE_PATH,
+ RECURSIVE_SKELETON,
+ TANGENT_TO_CURVE,
+ TEXT_LABEL,
INVALID_LPE // This must be last (I made it such that it is not needed anymore I think..., Don't trust on it being last. - johan)
};
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index b503598b7..44580b9b2 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -8,12 +8,11 @@
//#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects
#ifdef HAVE_CONFIG_H
-# include "config.h"
+#include <config.h>
#endif
// include effects:
#include "live_effects/lpe-patternalongpath.h"
-#include "live_effects/effect.h"
#include "live_effects/lpe-angle_bisector.h"
#include "live_effects/lpe-attach-path.h"
#include "live_effects/lpe-bendpath.h"
@@ -40,6 +39,7 @@
#include "live_effects/lpe-lattice2.h"
#include "live_effects/lpe-lattice.h"
#include "live_effects/lpe-line_segment.h"
+#include "live_effects/lpe-measure-line.h"
#include "live_effects/lpe-mirror_symmetry.h"
#include "live_effects/lpe-offset.h"
#include "live_effects/lpe-parallel.h"
@@ -66,30 +66,19 @@
#include "live_effects/lpe-bool.h"
#include "xml/node-event-vector.h"
-#include "sp-object.h"
-#include "attributes.h"
#include "message-stack.h"
-#include "desktop.h"
-#include "inkscape.h"
-#include "document.h"
#include "document-private.h"
-#include "xml/document.h"
-#include <glibmm/i18n.h>
#include "ui/tools/pen-tool.h"
+#include "ui/tools/node-tool.h"
#include "ui/tools-switch.h"
#include "knotholder.h"
-#include "sp-lpe-item.h"
+#include "path-chemistry.h"
+#include "xml/sp-css-attr.h"
#include "live_effects/lpeobject.h"
-#include "live_effects/parameter/parameter.h"
-#include <glibmm/ustring.h>
+#include <pangomm/layout.h>
#include "display/curve.h"
-
-#include <exception>
-
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/affine.h>
-#include <2geom/pathvector.h>
-
+#include <stdio.h>
+#include <string.h>
namespace Inkscape {
@@ -97,65 +86,67 @@ namespace LivePathEffect {
const Util::EnumData<EffectType> LPETypeData[] = {
// {constant defined in effect-enum.h, N_("name of your effect"), "name of your effect in SVG"}
-#ifdef LPE_ENABLE_TEST_EFFECTS
- {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"},
- {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"},
- {CIRCLE_WITH_RADIUS, N_("Circle (by center and radius)"), "circle_with_radius"},
- {CIRCLE_3PTS, N_("Circle by 3 points"), "circle_3pts"},
- {DYNASTROKE, N_("Dynamic stroke"), "dynastroke"},
- {EXTRUDE, N_("Extrude"), "extrude"},
- {LATTICE, N_("Lattice Deformation"), "lattice"},
- {LINE_SEGMENT, N_("Line Segment"), "line_segment"},
- {OFFSET, N_("Offset"), "offset"},
- {PARALLEL, N_("Parallel"), "parallel"},
- {PATH_LENGTH, N_("Path length"), "path_length"},
- {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"},
- {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"},
- {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"},
- {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},
- {TEXT_LABEL, N_("Text label"), "text_label"},
- {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"},
-#endif
/* 0.46 */
- {BEND_PATH, N_("Bend"), "bend_path"},
- {GEARS, N_("Gears"), "gears"},
- {PATTERN_ALONG_PATH, N_("Pattern Along Path"), "skeletal"}, // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG
- {CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"},
+ {BEND_PATH, N_("Bend"), "bend_path"},
+ {GEARS, N_("Gears"), "gears"},
+ {PATTERN_ALONG_PATH, N_("Pattern Along Path"), "skeletal"}, // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG
+ {CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"},
/* 0.47 */
- {VONKOCH, N_("VonKoch"), "vonkoch"},
- {KNOT, N_("Knot"), "knot"},
- {CONSTRUCT_GRID, N_("Construct grid"), "construct_grid"},
- {SPIRO, N_("Spiro spline"), "spiro"},
- {ENVELOPE, N_("Envelope Deformation"), "envelope"},
- {INTERPOLATE, N_("Interpolate Sub-Paths"), "interpolate"},
- {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"},
- {SKETCH, N_("Sketch"), "sketch"},
- {RULER, N_("Ruler"), "ruler"},
+ {VONKOCH, N_("VonKoch"), "vonkoch"},
+ {KNOT, N_("Knot"), "knot"},
+ {CONSTRUCT_GRID, N_("Construct grid"), "construct_grid"},
+ {SPIRO, N_("Spiro spline"), "spiro"},
+ {ENVELOPE, N_("Envelope Deformation"), "envelope"},
+ {INTERPOLATE, N_("Interpolate Sub-Paths"), "interpolate"},
+ {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"},
+ {SKETCH, N_("Sketch"), "sketch"},
+ {RULER, N_("Ruler"), "ruler"},
/* 0.91 */
- {POWERSTROKE, N_("Power stroke"), "powerstroke"},
- {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"},
+ {POWERSTROKE, N_("Power stroke"), "powerstroke"},
+ {CLONE_ORIGINAL, N_("Clone original"), "clone_original"},
/* 0.92 */
- {SIMPLIFY, N_("Simplify"), "simplify"},
- {LATTICE2, N_("Lattice Deformation 2"), "lattice2"},
- {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"},
- {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"},
- {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"},
- {SHOW_HANDLES, N_("Show handles"), "show_handles"},
- {ROUGHEN, N_("Roughen"), "roughen"},
- {BSPLINE, N_("BSpline"), "bspline"},
- {JOIN_TYPE, N_("Join type"), "join_type"},
- {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"},
- {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"},
- {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"},
+ {SIMPLIFY, N_("Simplify"), "simplify"},
+ {LATTICE2, N_("Lattice Deformation 2"), "lattice2"},
+ {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"}, //TODO:Wrong name with "-"
+ {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"},
+ {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"},
+ {SHOW_HANDLES, N_("Show handles"), "show_handles"},
+ {ROUGHEN, N_("Roughen"), "roughen"},
+ {BSPLINE, N_("BSpline"), "bspline"},
+ {JOIN_TYPE, N_("Join type"), "join_type"},
+ {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"},
+ {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"},
+ {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"},
/* Ponyscape -> Inkscape 0.92*/
- {ATTACH_PATH, N_("Attach path"), "attach_path"},
- {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"},
- {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"},
- {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"},
- {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"},
-/* MSoegtrop */
- {EMBRODERY_STITCH, N_("Embrodery stitch"), "embrodery_stitch"},
- {BOOL_OP, N_("Boolean operation"), "bool_op"},
+ {EMBRODERY_STITCH, N_("Embrodery stitch"), "embrodery_stitch"},
+ {BOOL_OP, N_("Boolean operation"), "bool_op"},
+ {ATTACH_PATH, N_("Attach path"), "attach_path"},
+ {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"},
+ {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"},
+ {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"},
+ {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"},
+/* 9.93 */
+ {MEASURE_LINE, N_("Measure Line"), "measure_line"},
+ {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"},
+#ifdef LPE_ENABLE_TEST_EFFECTS
+ {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"},
+ {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"},
+ {CIRCLE_WITH_RADIUS, N_("Circle (by center and radius)"), "circle_with_radius"},
+ {CIRCLE_3PTS, N_("Circle by 3 points"), "circle_3pts"},
+ {DYNASTROKE, N_("Dynamic stroke"), "dynastroke"},
+ {EXTRUDE, N_("Extrude"), "extrude"},
+ {LATTICE, N_("Lattice Deformation"), "lattice"},
+ {LINE_SEGMENT, N_("Line Segment"), "line_segment"},
+ {OFFSET, N_("Offset"), "offset"},
+ {PARALLEL, N_("Parallel"), "parallel"},
+ {PATH_LENGTH, N_("Path length"), "path_length"},
+ {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"},
+ {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"},
+ {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"},
+ {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},
+ {TEXT_LABEL, N_("Text label"), "text_label"},
+#endif
+
};
const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
@@ -332,6 +323,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
case TRANSFORM_2PTS:
neweffect = static_cast<Effect*> ( new LPETransform2Pts(lpeobj) );
break;
+ case MEASURE_LINE:
+ neweffect = static_cast<Effect*> ( new LPEMeasureLine(lpeobj) );
+ break;
default:
g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr);
neweffect = NULL;
@@ -373,10 +367,14 @@ Effect::Effect(LivePathEffectObject *lpeobject)
oncanvasedit_it(0),
is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true),
show_orig_path(false),
+ keep_paths(false),
+ is_load(true),
lpeobj(lpeobject),
concatenate_before_pwd2(false),
sp_lpe_item(NULL),
current_zoom(1),
+ upd_params(true),
+ sp_shape(NULL),
sp_curve(NULL),
provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden
is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden
@@ -413,15 +411,15 @@ Effect::doOnApply (SPLPEItem const*/*lpeitem*/)
}
void
-Effect::setSelectedNodePoints(std::vector<Geom::Point> sNP)
+Effect::setCurrentZoom(double cZ)
{
- selectedNodesPoints = sNP;
+ current_zoom = cZ;
}
void
-Effect::setCurrentZoom(double cZ)
+Effect::setSelectedNodePoints(std::vector<Geom::Point> sNP)
{
- current_zoom = cZ;
+ selectedNodesPoints = sNP;
}
bool
@@ -444,6 +442,82 @@ Effect::isNodePointSelected(Geom::Point const &nodePoint) const
return false;
}
+void
+Effect::processObjects(LpeAction lpe_action)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ for (std::vector<const char *>::iterator el_it = items.begin();
+ el_it != items.end(); ++el_it) {
+ const char * id = *el_it;
+ if (!id) {
+ return;
+ }
+ SPObject *elemref = NULL;
+ if ((elemref = document->getObjectById(id))) {
+ Inkscape::XML::Node * elemnode = elemref->getRepr();
+ std::vector<SPItem*> item_list;
+ item_list.push_back(SP_ITEM(elemref));
+ std::vector<Inkscape::XML::Node*> item_to_select;
+ std::vector<SPItem*> item_selected;
+ SPCSSAttr *css;
+ Glib::ustring css_str;
+ SPItem *item = SP_ITEM(elemref);
+ switch (lpe_action){
+ case LPE_TO_OBJECTS:
+ if (item->isHidden()) {
+ sp_object_ref(item, 0 );
+ item->deleteObject(true);
+ sp_object_unref(item);
+ } else {
+ if (elemnode->attribute("inkscape:path-effect")) {
+ sp_item_list_to_curves(item_list, item_selected, item_to_select);
+ }
+ elemnode->setAttribute("sodipodi:insensitive", NULL);
+ }
+ break;
+
+ case LPE_ERASE:
+ sp_object_ref(item, 0 );
+ item->deleteObject(true);
+ sp_object_unref(item);
+ break;
+
+ case LPE_VISIBILITY:
+ css = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css, elemref->getRepr()->attribute("style"));
+ if (!this->isVisible()/* && std::strcmp(elemref->getId(),sp_lpe_item->getId()) != 0*/) {
+ css->setAttribute("display", "none");
+ } else {
+ css->setAttribute("display", NULL);
+ }
+ sp_repr_css_write_string(css,css_str);
+ elemnode->setAttribute("style", css_str.c_str());
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ if (lpe_action == LPE_ERASE || lpe_action == LPE_TO_OBJECTS) {
+ items.clear();
+ }
+}
+
+void Effect::setCurrentShape(SPShape * shape){
+ if(shape){
+ sp_shape = shape;
+ if (!(sp_curve = sp_shape->getCurveBeforeLPE())) {
+ // oops
+ return;
+ }
+ pathvector_before_effect = sp_curve->get_pathvector();
+ }
+}
+
/**
* Is performed each time before the effect is updated.
*/
@@ -455,35 +529,35 @@ Effect::doBeforeEffect (SPLPEItem const*/*lpeitem*/)
void Effect::doAfterEffect (SPLPEItem const* /*lpeitem*/)
{
+ is_load = false;
}
void Effect::doOnRemove (SPLPEItem const* /*lpeitem*/)
{
}
-
+void Effect::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
+{
+}
//secret impl methods (shhhh!)
void Effect::doOnApply_impl(SPLPEItem const* lpeitem)
{
sp_lpe_item = const_cast<SPLPEItem *>(lpeitem);
- /*sp_curve = SP_SHAPE(sp_lpe_item)->getCurve();
- pathvector_before_effect = sp_curve->get_pathvector();*/
+ SPShape * shape = dynamic_cast<SPShape *>(sp_lpe_item);
+ setCurrentShape(shape);
doOnApply(lpeitem);
}
void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem)
{
sp_lpe_item = const_cast<SPLPEItem *>(lpeitem);
- //printf("(SPLPEITEM*) %p\n", sp_lpe_item);
SPShape * shape = dynamic_cast<SPShape *>(sp_lpe_item);
- if(shape){
- sp_curve = shape->getCurve();
- pathvector_before_effect = sp_curve->get_pathvector();
- }
+ setCurrentShape(shape);
doBeforeEffect(lpeitem);
if (apply_to_clippath_and_mask && SP_IS_GROUP(sp_lpe_item)) {
sp_lpe_item->apply_to_clippath(sp_lpe_item);
sp_lpe_item->apply_to_mask(sp_lpe_item);
}
+ update_helperpath();
}
/**
@@ -583,6 +657,7 @@ void
Effect::readallParameters(Inkscape::XML::Node const* repr)
{
std::vector<Parameter *>::iterator it = param_vector.begin();
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
while (it != param_vector.end()) {
Parameter * param = *it;
const gchar * key = param->param_key.c_str();
@@ -593,10 +668,17 @@ Effect::readallParameters(Inkscape::XML::Node const* repr)
g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key);
}
} else {
- // set default value
- param->param_set_default();
+ Glib::ustring pref_path = (Glib::ustring)"/live_effects/" +
+ (Glib::ustring)LPETypeConverter.get_key(effectType()).c_str() +
+ (Glib::ustring)"/" +
+ (Glib::ustring)key;
+ bool valid = prefs->getEntry(pref_path).isValid();
+ if(valid){
+ param->param_update_default(prefs->getString(pref_path).c_str());
+ } else {
+ param->param_set_default();
+ }
}
-
++it;
}
}
@@ -630,15 +712,15 @@ Effect::registerParameter(Parameter * param)
* Add all registered LPE knotholder handles to the knotholder
*/
void
-Effect::addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
+Effect::addHandles(KnotHolder *knotholder, SPItem *item) {
using namespace Inkscape::LivePathEffect;
// add handles provided by the effect itself
- addKnotHolderEntities(knotholder, desktop, item);
+ addKnotHolderEntities(knotholder, item);
// add handles provided by the effect's parameters (if any)
for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
- (*p)->addKnotHolderEntities(knotholder, desktop, item);
+ (*p)->addKnotHolderEntities(knotholder, item);
}
}
@@ -673,6 +755,13 @@ Effect::addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathV
{
}
+/**
+ * Call to a method on nodetool to update the helper path from the effect
+ */
+void
+Effect::update_helperpath() {
+ Inkscape::UI::Tools::sp_update_helperpath();
+}
/**
* This *creates* a new widget, management of deletion should be done by the caller
@@ -704,10 +793,96 @@ Effect::newWidget()
++it;
}
-
return dynamic_cast<Gtk::Widget *>(vbox);
}
+/**
+ * This *creates* a new widget, with default values setter
+ */
+Gtk::Widget *
+Effect::defaultParamSet()
+{
+ // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox() );
+ Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox() );
+ Glib::ustring effectname = (Glib::ustring)Inkscape::LivePathEffect::LPETypeConverter.get_label(effectType());
+ Glib::ustring effectkey = (Glib::ustring)Inkscape::LivePathEffect::LPETypeConverter.get_key(effectType());
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ Inkscape::UI::Widget::Registry * wr;
+ bool has_params = false;
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ has_params = true;
+ Parameter * param = *it;
+ Glib::ustring * tip = param->param_getTooltip();
+ const gchar * key = param->param_key.c_str();
+ const gchar * value = param->param_label.c_str();
+ const gchar * tooltip_extra = _(". Change custom values for this parameter");
+ Glib::ustring tooltip = param->param_tooltip + (Glib::ustring)tooltip_extra;
+ Glib::ustring pref_path = (Glib::ustring)"/live_effects/" +
+ effectkey +
+ (Glib::ustring)"/" +
+ (Glib::ustring)key;
+ bool valid = prefs->getEntry(pref_path).isValid();
+ const gchar * set_or_upd;
+ if (valid) {
+ set_or_upd = _("Update");
+ } else {
+ set_or_upd = _("Set");
+ }
+ Gtk::HBox * vbox_param = Gtk::manage( new Gtk::HBox(true) );
+ Gtk::Label *parameter_label = Gtk::manage(new Gtk::Label(value, Gtk::ALIGN_START));
+ parameter_label->set_use_markup(true);
+ parameter_label->set_use_underline (true);
+ parameter_label->set_ellipsize(Pango::ELLIPSIZE_END);
+ vbox_param->pack_start(*parameter_label, true, true, 2);
+ Gtk::Button *set = Gtk::manage(new Gtk::Button((Glib::ustring)set_or_upd));
+ Gtk::Button *unset = Gtk::manage(new Gtk::Button(Glib::ustring(_("Unset"))));
+ unset->signal_clicked().connect(sigc::bind<Glib::ustring, Gtk::Button *, Gtk::Button *>(sigc::mem_fun(*this, &Effect::unsetDefaultParam), pref_path, set, unset));
+ set->signal_clicked().connect(sigc::bind<Glib::ustring, gchar *, Gtk::Button *, Gtk::Button *>(sigc::mem_fun(*this, &Effect::setDefaultParam), pref_path, param->param_getSVGValue(), set, unset));
+ if (!valid) {
+ unset->set_sensitive(false);
+ }
+ vbox_param->pack_start(*set, true, true, 2);
+ vbox_param->pack_start(*unset, true, true, 2);
+
+ vbox_expander->pack_start(*vbox_param, true, true, 2);
+ }
+ ++it;
+ }
+ Glib::ustring tip = "<b>" + effectname + (Glib::ustring)_("</b>: Set default parameters");
+ Gtk::Expander * expander = Gtk::manage(new Gtk::Expander(tip));
+ expander->set_use_markup(true);
+ expander->add(*vbox_expander);
+ expander->set_expanded(false);
+ vbox->pack_start(*dynamic_cast<Gtk::Widget *> (expander), true, true, 2);
+ if (has_params) {
+ return dynamic_cast<Gtk::Widget *>(vbox);
+ } else {
+ return NULL;
+ }
+}
+
+void
+Effect::setDefaultParam(Glib::ustring pref_path, gchar * value, Gtk::Button *set , Gtk::Button *unset)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setString(pref_path, (Glib::ustring)value);
+ gchar * label = _("Update");
+ set->set_label((Glib::ustring)label);
+ unset->set_sensitive(true);
+}
+
+void
+Effect::unsetDefaultParam(Glib::ustring pref_path, Gtk::Button *set, Gtk::Button *unset)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->remove(pref_path);
+ gchar * label = _("Set");
+ set->set_label((Glib::ustring)label);
+ unset->set_sensitive(false);
+}
Inkscape::XML::Node *Effect::getRepr()
{
@@ -727,6 +902,7 @@ Effect::getParameter(const char * key)
{
Glib::ustring stringkey(key);
+ if (param_vector.empty()) return NULL;
std::vector<Parameter *>::iterator it = param_vector.begin();
while (it != param_vector.end()) {
Parameter * param = *it;
diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h
index 898e089b7..e353eba23 100644
--- a/src/live_effects/effect.h
+++ b/src/live_effects/effect.h
@@ -19,7 +19,7 @@
class SPDocument;
class SPDesktop;
class SPItem;
-class LivePathEffectObject;
+class LivePathEffectObject;
class SPLPEItem;
class KnotHolder;
class KnotHolderEntity;
@@ -44,6 +44,12 @@ enum LPEPathFlashType {
DEFAULT
};
+enum LpeAction {
+ LPE_ERASE = 0,
+ LPE_TO_OBJECTS,
+ LPE_VISIBILITY
+};
+
class Effect {
public:
static Effect* New(EffectType lpenr, LivePathEffectObject *lpeobj);
@@ -66,13 +72,16 @@ public:
virtual void doAfterEffect (SPLPEItem const* lpeitem);
virtual void doOnRemove (SPLPEItem const* lpeitem);
-
+ virtual void doOnVisibilityToggled(SPLPEItem const* lpeitem);
void writeParamsToSVG();
virtual void acceptParamPath (SPPath const* param_path);
static int acceptsNumClicks(EffectType type);
int acceptsNumClicks() const { return acceptsNumClicks(effectType()); }
void doAcceptPathPreparations(SPLPEItem *lpeitem);
+ SPShape * getCurrentShape(){ return sp_shape; };
+ void setCurrentShape(SPShape * shape);
+ void processObjects(LpeAction lpe_action);
/*
* isReady() indicates whether all preparations which are necessary to apply the LPE are done,
@@ -85,7 +94,7 @@ public:
virtual void doEffect (SPCurve * curve);
virtual Gtk::Widget * newWidget();
-
+ virtual Gtk::Widget * defaultParamSet();
/**
* Sets all parameters to their default values and writes them to SVG.
*/
@@ -100,8 +109,9 @@ public:
// /TODO: in view of providesOwnFlashPaths() below, this is somewhat redundant
// (but spiro lpe still needs it!)
virtual LPEPathFlashType pathFlashType() const { return DEFAULT; }
- void addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ void addHandles(KnotHolder *knotholder, SPItem *item);
std::vector<Geom::PathVector> getCanvasIndicators(SPLPEItem const* lpeitem);
+ void update_helperpath();
inline bool providesOwnFlashPaths() const {
return provides_own_flash_paths || show_orig_path;
@@ -122,7 +132,13 @@ public:
void editNextParamOncanvas(SPItem * item, SPDesktop * desktop);
bool apply_to_clippath_and_mask;
-
+ bool keep_paths; // set this to false allow retain extra generated objects, see measure line LPE
+ bool is_load;
+ bool upd_params;
+ BoolParam is_visible;
+ SPCurve * sp_curve;
+ Geom::PathVector pathvector_before_effect;
+ Geom::PathVector pathvector_after_effect;
protected:
Effect(LivePathEffectObject *lpeobject);
@@ -139,7 +155,7 @@ protected:
void registerParameter(Parameter * param);
Parameter * getNextOncanvasEditableParam();
- virtual void addKnotHolderEntities(KnotHolder * /*knotholder*/, SPDesktop * /*desktop*/, SPItem * /*item*/) {};
+ virtual void addKnotHolderEntities(KnotHolder * /*knotholder*/, SPItem * /*item*/) {};
virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector<Geom::PathVector> &hp_vec);
@@ -147,7 +163,6 @@ protected:
bool _provides_knotholder_entities;
int oncanvasedit_it;
- BoolParam is_visible;
bool show_orig_path; // set this to true in derived effects to automatically have the original
// path displayed as helperpath
@@ -159,13 +174,15 @@ protected:
// this boolean defaults to false, it concatenates the input path to one pwd2,
// instead of normally 'splitting' the path into continuous pwd2 paths and calling doEffect_pwd2 for each.
bool concatenate_before_pwd2;
-
SPLPEItem * sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them.
+ SPShape * sp_shape; // these get stored in doBeforeEffect_impl before doEffect chain, or in performPathEffects on groups, and derived classes may do as they please with them.
+ std::vector<const char *> items;
double current_zoom;
std::vector<Geom::Point> selectedNodesPoints;
- SPCurve * sp_curve;
- Geom::PathVector pathvector_before_effect;
+
private:
+ void setDefaultParam(Glib::ustring pref_path, gchar * value, Gtk::Button *set , Gtk::Button *unset);
+ void unsetDefaultParam(Glib::ustring pref_path, Gtk::Button *set , Gtk::Button *unset);
bool provides_own_flash_paths; // if true, the standard flash path is suppressed
bool is_ready;
diff --git a/src/live_effects/lpe-angle_bisector.cpp b/src/live_effects/lpe-angle_bisector.cpp
index 900d29e3a..56d33eb4b 100644
--- a/src/live_effects/lpe-angle_bisector.cpp
+++ b/src/live_effects/lpe-angle_bisector.cpp
@@ -8,16 +8,13 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-angle_bisector.h"
-
-#include <2geom/path.h>
-#include <2geom/sbasis-to-bezier.h>
-
+#include "2geom/sbasis-to-bezier.h"
#include "sp-lpe-item.h"
#include "knot-holder-entity.h"
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp
index 21459f322..302165719 100644
--- a/src/live_effects/lpe-attach-path.cpp
+++ b/src/live_effects/lpe-attach-path.cpp
@@ -4,22 +4,14 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
#include <math.h>
-
#include "live_effects/lpe-attach-path.h"
-
#include "display/curve.h"
-#include "sp-item.h"
-#include "2geom/path.h"
#include "sp-shape.h"
#include "sp-text.h"
-#include "2geom/bezier-curve.h"
#include "2geom/path-sink.h"
-#include "parameter/parameter.h"
-#include "live_effects/parameter/point.h"
-#include "parameter/originalpath.h"
-#include "2geom/affine.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-bendpath.cpp b/src/live_effects/lpe-bendpath.cpp
index bc112285f..363356cac 100644
--- a/src/live_effects/lpe-bendpath.cpp
+++ b/src/live_effects/lpe-bendpath.cpp
@@ -6,27 +6,12 @@
*/
#include "live_effects/lpe-bendpath.h"
-#include "sp-shape.h"
-#include "sp-item.h"
-#include "sp-path.h"
#include "sp-item-group.h"
-#include "svg/svg.h"
-#include "ui/widget/scalar.h"
-
-#include <2geom/sbasis.h>
-#include <2geom/sbasis-geometric.h>
-#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/piecewise.h>
-
#include "knot-holder-entity.h"
#include "knotholder.h"
-
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
-#include <algorithm>
-
using std::vector;
@@ -72,10 +57,10 @@ LPEBendPath::LPEBendPath(LivePathEffectObject *lpeobject) :
scale_y_rel(_("W_idth in units of length"), _("Scale the width of the path in units of its length"), "scale_y_rel", &wr, this, false),
vertical_pattern(_("_Original path is vertical"), _("Rotates the original 90 degrees, before bending it along the bend path"), "vertical", &wr, this, false)
{
- registerParameter( dynamic_cast<Parameter *>(&bend_path) );
- registerParameter( dynamic_cast<Parameter *>(&prop_scale) );
- registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) );
- registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) );
+ registerParameter( &bend_path );
+ registerParameter( &prop_scale);
+ registerParameter( &scale_y_rel);
+ registerParameter( &vertical_pattern);
prop_scale.param_set_digits(3);
prop_scale.param_set_increments(0.01, 0.10);
diff --git a/src/live_effects/lpe-bool.cpp b/src/live_effects/lpe-bool.cpp
index afc6abfc1..2930414b3 100644
--- a/src/live_effects/lpe-bool.cpp
+++ b/src/live_effects/lpe-bool.cpp
@@ -1,7 +1,7 @@
/*
* Boolean operation live path effect
*
- * Copyright (C) 2016 Michael Soegtrop
+ * Copyright (C) 2016-2017 Michael Soegtrop
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -34,53 +34,55 @@ namespace LivePathEffect {
// Define an extended boolean operation type
static const Util::EnumData<LPEBool::bool_op_ex> BoolOpData[LPEBool::bool_op_ex_count] = {
- { LPEBool::bool_op_ex_union, N_("union"), "union" },
- { LPEBool::bool_op_ex_inters, N_("intersection"), "inters" },
- { LPEBool::bool_op_ex_diff, N_("difference"), "diff" },
- { LPEBool::bool_op_ex_symdiff, N_("symmetric difference"), "symdiff" },
- { LPEBool::bool_op_ex_cut, N_("cut"), "cut" },
- { LPEBool::bool_op_ex_slice, N_("slice, keep inner contours"), "slice" },
- { LPEBool::bool_op_ex_slice_inside, N_("slice inside, keep inner contours"), "slice-inside" },
- { LPEBool::bool_op_ex_slice_outside, N_("slice outside, keep inner contours"), "slice-outside" },
- { LPEBool::bool_op_ex_slice_rmv_inner, N_("slice, remove inner contours"), "slice-rmv-inner" },
- { LPEBool::bool_op_ex_slice_inside_rmv_inner, N_("slice inside, remove inner contours"), "slice-inside-rmv-inner" },
- { LPEBool::bool_op_ex_slice_outside_rmv_inner, N_("slice outside, remove inner contours"), "slice-outside-rmv-inner" }
+ { LPEBool::bool_op_ex_union, N_("union"), "union" },
+ { LPEBool::bool_op_ex_inters, N_("intersection"), "inters" },
+ { LPEBool::bool_op_ex_diff, N_("difference"), "diff" },
+ { LPEBool::bool_op_ex_symdiff, N_("symmetric difference"), "symdiff" },
+ { LPEBool::bool_op_ex_cut, N_("division"), "cut" },
+ // Note on naming of operations:
+ // bool_op_cut is called "Division" in the manu, see sp_selected_path_cut
+ // bool_op_slice is called "Cut path" in the menu, see sp_selected_path_slice
+ { LPEBool::bool_op_ex_slice, N_("cut"), "slice" },
+ { LPEBool::bool_op_ex_slice_inside, N_("cut inside"), "slice-inside" },
+ { LPEBool::bool_op_ex_slice_outside, N_("cut outside"), "slice-outside" },
};
-static const Util::EnumDataConverter<LPEBool::bool_op_ex> BoolOpConverter(BoolOpData, sizeof(BoolOpData)/sizeof(*BoolOpData));
+static const Util::EnumDataConverter<LPEBool::bool_op_ex> BoolOpConverter(BoolOpData, sizeof(BoolOpData) / sizeof(*BoolOpData));
-static const Util::EnumData<fill_typ> FillTypeData[fill_justDont+1] = {
- { fill_oddEven, N_("odd-even"), "oddeven" },
- { fill_nonZero, N_("non-zero"), "nonzero" },
- { fill_positive, N_("positive"), "positive" },
- { fill_justDont, N_("from curve"), "from-curve" }
+static const Util::EnumData<fill_typ> FillTypeData[] = {
+ { fill_oddEven, N_("odd-even"), "oddeven" },
+ { fill_nonZero, N_("non-zero"), "nonzero" },
+ { fill_positive, N_("positive"), "positive" },
+ { fill_justDont, N_("from curve"), "from-curve" }
};
-static const Util::EnumDataConverter<fill_typ> FillTypeConverter(FillTypeData, sizeof(FillTypeData)/sizeof(*FillTypeData));
+static const Util::EnumDataConverter<fill_typ> FillTypeConverter(FillTypeData, sizeof(FillTypeData) / sizeof(*FillTypeData));
-static const Util::EnumData<fill_typ> FillTypeDataThis[fill_justDont+1] = {
- { fill_oddEven, N_("odd-even"), "oddeven" },
- { fill_nonZero, N_("non-zero"), "nonzero" },
- { fill_positive, N_("positive"), "positive" }
+static const Util::EnumData<fill_typ> FillTypeDataThis[] = {
+ { fill_oddEven, N_("odd-even"), "oddeven" },
+ { fill_nonZero, N_("non-zero"), "nonzero" },
+ { fill_positive, N_("positive"), "positive" }
};
-static const Util::EnumDataConverter<fill_typ> FillTypeConverterThis(FillTypeDataThis, sizeof(FillTypeDataThis)/sizeof(*FillTypeDataThis));
+static const Util::EnumDataConverter<fill_typ> FillTypeConverterThis(FillTypeDataThis, sizeof(FillTypeDataThis) / sizeof(*FillTypeDataThis));
LPEBool::LPEBool(LivePathEffectObject *lpeobject) :
- Effect(lpeobject),
- operand_path(_("Operand path:"), _("Operand for the boolean operation"), "operand-path", &wr, this),
- bool_operation(_("Operation:"), _("Boolean Operation"), "operation", BoolOpConverter, &wr, this, bool_op_ex_union),
- swap_operands(_("Swap operands:"), _("Swap operands (useful e.g. for difference)"), "swap-operands", &wr, this),
- fill_type_this(_("Fill type this:"), _("Fill type (winding mode) for this path"), "filltype-this", FillTypeConverterThis, &wr, this, fill_oddEven),
- fill_type_operand(_("Fill type operand:"), _("Fill type (winding mode) for operand path"), "filltype-operand", FillTypeConverter, &wr, this, fill_justDont)
+ Effect(lpeobject),
+ operand_path(_("Operand path:"), _("Operand for the boolean operation"), "operand-path", &wr, this),
+ bool_operation(_("Operation:"), _("Boolean Operation"), "operation", BoolOpConverter, &wr, this, bool_op_ex_union),
+ swap_operands(_("Swap operands:"), _("Swap operands (useful e.g. for difference)"), "swap-operands", &wr, this),
+ rmv_inner(_("Remove inner:"), _("For cut operations: remove inner (non-contour) lines of cutting path to avoid invisible extra points"), "rmv-inner", &wr, this),
+ fill_type_this(_("Fill type this:"), _("Fill type (winding mode) for this path"), "filltype-this", FillTypeConverterThis, &wr, this, fill_oddEven),
+ fill_type_operand(_("Fill type operand:"), _("Fill type (winding mode) for operand path"), "filltype-operand", FillTypeConverter, &wr, this, fill_justDont)
{
- registerParameter(&operand_path);
- registerParameter(&bool_operation);
- registerParameter(&swap_operands);
- registerParameter(&fill_type_this);
- registerParameter(&fill_type_operand);
-
- show_orig_path = true;
+ registerParameter(&operand_path);
+ registerParameter(&bool_operation);
+ registerParameter(&swap_operands);
+ registerParameter(&rmv_inner);
+ registerParameter(&fill_type_this);
+ registerParameter(&fill_type_operand);
+
+ show_orig_path = true;
}
LPEBool::~LPEBool()
@@ -92,231 +94,222 @@ void LPEBool::resetDefaults(SPItem const * /*item*/)
{
}
-bool cmp_cut_position( const Path::cut_position &a, const Path::cut_position &b )
+bool cmp_cut_position(const Path::cut_position &a, const Path::cut_position &b)
{
- return a.piece==b.piece ? a.t<b.t : a.piece<b.piece;
+ return a.piece == b.piece ? a.t < b.t : a.piece < b.piece;
}
Geom::PathVector
sp_pathvector_boolop_slice_intersect(Geom::PathVector const &pathva, Geom::PathVector const &pathvb, bool inside, fill_typ fra, fill_typ frb)
{
- // This is similar to sp_pathvector_boolop/bool_op_slice, but keeps only edges inside the cutter area.
- // The code is also based on sp_pathvector_boolop_slice.
- //
- // We have two paths on input
- // - a closed area which is used to cut out pieces from a contour (called area below)
- // - a contour which is cut into pieces by the border of thr area (called contour below)
- //
- // The code below works in the following steps
- // (a) Convert the area to a shape, so that we can ask the winding number for any point
- // (b) Add both, the contour and the area to a single shape and intersect them
- // (c) Find the intersection points between area border and contour (vector toCut)
- // (d) Split the original contour at the intersection points
- // (e) check for each contour edge in combined shape if its center is inside the area - if not discard it
- // (f) create a vector of all inside edges
- // (g) convert the piece numbers to the piece numbers after applying the cuts
- // (h) fill a bool vector with information which pieces are in
- // (i) filter the descr_cmd of the result path with this bool vector
- //
- // The main inefficieny here is step (e) because I use a winding function of the area-shape which goes
- // through teh complete edge list for each point I ask for, so effort is n-edges-contour * n-edges-area.
- // It is tricky to improve this without building into the livarot code.
- // One way might be to decide at the intersection points which edges touching the intersection points are
- // in by making a loop through all edges on the intersection vertex. Since this is a directed non intersecting
- // graph, this should provide sufficient information.
- // But since I anyway will change this to the new mechanism some time speed is fairly ok, I didn't look into this.
-
-
- // extract the livarot Paths from the source objects
- // also get the winding rule specified in the style
- // Livarot's outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly.
- Path *contour_path = Path_for_pathvector(pathv_to_linear_and_cubic_beziers( pathva) );
- Path *area_path = Path_for_pathvector(pathv_to_linear_and_cubic_beziers( pathvb) );
-
- // Shapes from above paths
- Shape *area_shape = new Shape;
- Shape *combined_shape = new Shape;
- Shape *combined_inters = new Shape;
-
- // Add the area (process to intersection free shape)
- area_path->ConvertWithBackData(1.0);
- area_path->Fill(combined_shape, 1);
-
- // Convert this to a shape with full winding information
- area_shape->ConvertToShape(combined_shape, frb);
-
- // Add the contour to the combined path (just add, no winding processing)
- contour_path->ConvertWithBackData(1.0);
- contour_path->Fill(combined_shape, 0,true,false,false);
-
- // Intersect the area and the contour - no fill processing
- combined_inters->ConvertToShape(combined_shape, fill_justDont);
-
- // Result path
- Path *result_path = new Path;
- result_path->SetBackData(false);
-
- // Cutting positions for contour
- std::vector<Path::cut_position> toCut;
-
- if ( combined_inters->hasBackData() ) {
- // should always be the case, but ya never know
- {
- for (int i = 0; i < combined_inters->numberOfPoints(); i++) {
- if ( combined_inters->getPoint(i).totalDegree() > 2 ) {
- // possibly an intersection
- // we need to check that at least one edge from the source path is incident to it
- // before we declare it's an intersection
- int cb = combined_inters->getPoint(i).incidentEdge[FIRST];
- int nbOrig=0;
- int nbOther=0;
- int piece=-1;
- float t=0.0;
- while ( cb >= 0 && cb < combined_inters->numberOfEdges() ) {
- if ( combined_inters->ebData[cb].pathID == 0 ) {
- // the source has an edge incident to the point, get its position on the path
- piece=combined_inters->ebData[cb].pieceID;
- if ( combined_inters->getEdge(cb).st == i ) {
- t=combined_inters->ebData[cb].tSt;
- } else {
- t=combined_inters->ebData[cb].tEn;
- }
- nbOrig++;
- }
- if ( combined_inters->ebData[cb].pathID == 1 ) nbOther++; // the cut is incident to this point
- cb=combined_inters->NextAt(i, cb);
- }
- if ( nbOrig > 0 && nbOther > 0 ) {
- // point incident to both path and cut: an intersection
- // note that you only keep one position on the source; you could have degenerate
- // cases where the source crosses itself at this point, and you wouyld miss an intersection
- Path::cut_position cutpos;
- cutpos.piece=piece;
- cutpos.t=t;
- toCut.push_back( cutpos );
- }
- }
- }
- }
- {
- // remove the edges from the intersection polygon
- int i = combined_inters->numberOfEdges() - 1;
- for (;i>=0;i--) {
- if ( combined_inters->ebData[i].pathID == 1 ) {
- combined_inters->SubEdge(i);
- } else {
- const Shape::dg_arete &edge = combined_inters->getEdge(i);
- const Shape::dg_point &start = combined_inters->getPoint(edge.st);
- const Shape::dg_point &end = combined_inters->getPoint(edge.en);
- Geom::Point mid = 0.5*(start.x+end.x);
- int wind = area_shape->PtWinding( mid );
- if ( wind==0 ) {
- combined_inters->SubEdge(i);
- }
- }
- }
- }
- }
-
- // create a vector of pieces, which are in the intersection
- std::vector<Path::cut_position> inside_pieces( combined_inters->numberOfEdges() );
- for( int i=0; i<combined_inters->numberOfEdges(); i++ ) {
- inside_pieces[i].piece = combined_inters->ebData[i].pieceID;
- // Use the t middle point, this is safe to compare with values from toCut in the presence of roundoff errors
- inside_pieces[i].t = 0.5 * (combined_inters->ebData[i].tSt + combined_inters->ebData[i].tEn);
- }
- std::sort( inside_pieces.begin(), inside_pieces.end(), cmp_cut_position );
-
- // sort cut positions
- std::sort( toCut.begin(), toCut.end(), cmp_cut_position );
-
- // Compute piece ids after ConvertPositionsToMoveTo
- {
- int idIncr=0;
- std::vector<Path::cut_position>::iterator itPiece=inside_pieces.begin();
- std::vector<Path::cut_position>::iterator itCut=toCut.begin();
- while( itPiece!=inside_pieces.end() )
- {
- while( itCut!=toCut.end() && cmp_cut_position( *itCut, *itPiece ) )
- {
- ++itCut;
- idIncr+=2;
- }
- itPiece->piece += idIncr;
- ++itPiece;
- }
- }
-
- // Copy the original path to result and cut at the intersection points
- result_path->Copy( contour_path );
- result_path->ConvertPositionsToMoveTo( toCut.size(), toCut.data() ); // cut where you found intersections
-
- // Create an array of bools which states which pieces are in
- std::vector<bool> inside_flags(result_path->descr_cmd.size(), false );
- for( std::vector<Path::cut_position>::iterator itPiece=inside_pieces.begin(); itPiece!=inside_pieces.end(); ++itPiece )
- {
- inside_flags[ itPiece->piece ] = true;
- // also enable the element -1 to get the MoveTo
- if( itPiece->piece>=1 )
- {
- inside_flags[ itPiece->piece-1 ] = true;
- }
- }
+ // This is similar to sp_pathvector_boolop/bool_op_slice, but keeps only edges inside the cutter area.
+ // The code is also based on sp_pathvector_boolop_slice.
+ //
+ // We have two paths on input
+ // - a closed area which is used to cut out pieces from a contour (called area below)
+ // - a contour which is cut into pieces by the border of thr area (called contour below)
+ //
+ // The code below works in the following steps
+ // (a) Convert the area to a shape, so that we can ask the winding number for any point
+ // (b) Add both, the contour and the area to a single shape and intersect them
+ // (c) Find the intersection points between area border and contour (vector toCut)
+ // (d) Split the original contour at the intersection points
+ // (e) check for each contour edge in combined shape if its center is inside the area - if not discard it
+ // (f) create a vector of all inside edges
+ // (g) convert the piece numbers to the piece numbers after applying the cuts
+ // (h) fill a bool vector with information which pieces are in
+ // (i) filter the descr_cmd of the result path with this bool vector
+ //
+ // The main inefficieny here is step (e) because I use a winding function of the area-shape which goes
+ // through teh complete edge list for each point I ask for, so effort is n-edges-contour * n-edges-area.
+ // It is tricky to improve this without building into the livarot code.
+ // One way might be to decide at the intersection points which edges touching the intersection points are
+ // in by making a loop through all edges on the intersection vertex. Since this is a directed non intersecting
+ // graph, this should provide sufficient information.
+ // But since I anyway will change this to the new mechanism some time speed is fairly ok, I didn't look into this.
+
+
+ // extract the livarot Paths from the source objects
+ // also get the winding rule specified in the style
+ // Livarot's outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly.
+ Path *contour_path = Path_for_pathvector(pathv_to_linear_and_cubic_beziers(pathva));
+ Path *area_path = Path_for_pathvector(pathv_to_linear_and_cubic_beziers(pathvb));
+
+ // Shapes from above paths
+ Shape *area_shape = new Shape;
+ Shape *combined_shape = new Shape;
+ Shape *combined_inters = new Shape;
+
+ // Add the area (process to intersection free shape)
+ area_path->ConvertWithBackData(1.0);
+ area_path->Fill(combined_shape, 1);
+
+ // Convert this to a shape with full winding information
+ area_shape->ConvertToShape(combined_shape, frb);
+
+ // Add the contour to the combined path (just add, no winding processing)
+ contour_path->ConvertWithBackData(1.0);
+ contour_path->Fill(combined_shape, 0, true, false, false);
+
+ // Intersect the area and the contour - no fill processing
+ combined_inters->ConvertToShape(combined_shape, fill_justDont);
+
+ // Result path
+ Path *result_path = new Path;
+ result_path->SetBackData(false);
+
+ // Cutting positions for contour
+ std::vector<Path::cut_position> toCut;
+
+ if (combined_inters->hasBackData()) {
+ // should always be the case, but ya never know
+ {
+ for (int i = 0; i < combined_inters->numberOfPoints(); i++) {
+ if (combined_inters->getPoint(i).totalDegree() > 2) {
+ // possibly an intersection
+ // we need to check that at least one edge from the source path is incident to it
+ // before we declare it's an intersection
+ int cb = combined_inters->getPoint(i).incidentEdge[FIRST];
+ int nbOrig = 0;
+ int nbOther = 0;
+ int piece = -1;
+ float t = 0.0;
+ while (cb >= 0 && cb < combined_inters->numberOfEdges()) {
+ if (combined_inters->ebData[cb].pathID == 0) {
+ // the source has an edge incident to the point, get its position on the path
+ piece = combined_inters->ebData[cb].pieceID;
+ if (combined_inters->getEdge(cb).st == i) {
+ t = combined_inters->ebData[cb].tSt;
+ } else {
+ t = combined_inters->ebData[cb].tEn;
+ }
+ nbOrig++;
+ }
+ if (combined_inters->ebData[cb].pathID == 1) {
+ nbOther++; // the cut is incident to this point
+ }
+ cb = combined_inters->NextAt(i, cb);
+ }
+ if (nbOrig > 0 && nbOther > 0) {
+ // point incident to both path and cut: an intersection
+ // note that you only keep one position on the source; you could have degenerate
+ // cases where the source crosses itself at this point, and you wouyld miss an intersection
+ Path::cut_position cutpos;
+ cutpos.piece = piece;
+ cutpos.t = t;
+ toCut.push_back(cutpos);
+ }
+ }
+ }
+ }
+ {
+ // remove the edges from the intersection polygon
+ int i = combined_inters->numberOfEdges() - 1;
+ for (; i >= 0; i--) {
+ if (combined_inters->ebData[i].pathID == 1) {
+ combined_inters->SubEdge(i);
+ } else {
+ const Shape::dg_arete &edge = combined_inters->getEdge(i);
+ const Shape::dg_point &start = combined_inters->getPoint(edge.st);
+ const Shape::dg_point &end = combined_inters->getPoint(edge.en);
+ Geom::Point mid = 0.5 * (start.x + end.x);
+ int wind = area_shape->PtWinding(mid);
+ if (wind == 0) {
+ combined_inters->SubEdge(i);
+ }
+ }
+ }
+ }
+ }
+
+ // create a vector of pieces, which are in the intersection
+ std::vector<Path::cut_position> inside_pieces(combined_inters->numberOfEdges());
+ for (int i = 0; i < combined_inters->numberOfEdges(); i++) {
+ inside_pieces[i].piece = combined_inters->ebData[i].pieceID;
+ // Use the t middle point, this is safe to compare with values from toCut in the presence of roundoff errors
+ inside_pieces[i].t = 0.5 * (combined_inters->ebData[i].tSt + combined_inters->ebData[i].tEn);
+ }
+ std::sort(inside_pieces.begin(), inside_pieces.end(), cmp_cut_position);
+
+ // sort cut positions
+ std::sort(toCut.begin(), toCut.end(), cmp_cut_position);
+
+ // Compute piece ids after ConvertPositionsToMoveTo
+ {
+ int idIncr = 0;
+ std::vector<Path::cut_position>::iterator itPiece = inside_pieces.begin();
+ std::vector<Path::cut_position>::iterator itCut = toCut.begin();
+ while (itPiece != inside_pieces.end()) {
+ while (itCut != toCut.end() && cmp_cut_position(*itCut, *itPiece)) {
+ ++itCut;
+ idIncr += 2;
+ }
+ itPiece->piece += idIncr;
+ ++itPiece;
+ }
+ }
+
+ // Copy the original path to result and cut at the intersection points
+ result_path->Copy(contour_path);
+ result_path->ConvertPositionsToMoveTo(toCut.size(), toCut.data()); // cut where you found intersections
+
+ // Create an array of bools which states which pieces are in
+ std::vector<bool> inside_flags(result_path->descr_cmd.size(), false);
+ for (std::vector<Path::cut_position>::iterator itPiece = inside_pieces.begin(); itPiece != inside_pieces.end(); ++itPiece) {
+ inside_flags[ itPiece->piece ] = true;
+ // also enable the element -1 to get the MoveTo
+ if (itPiece->piece >= 1) {
+ inside_flags[ itPiece->piece - 1 ] = true;
+ }
+ }
#if 0 // CONCEPT TESTING
- //Check if the inside/outside verdict is consistent - just for testing the concept
- // Retrieve the pieces
- int nParts=0;
- Path** parts=result_path->SubPaths(nParts,false);
+ //Check if the inside/outside verdict is consistent - just for testing the concept
+ // Retrieve the pieces
+ int nParts = 0;
+ Path **parts = result_path->SubPaths(nParts, false);
// Each piece should be either fully in or fully out
- int iPiece=0;
- for( int iPart=0; iPart<nParts; iPart++ )
- {
- bool andsum=true;
- bool orsum=false;
- for( int iCmd=0; iCmd<parts[iPart]->descr_cmd.size(); iCmd++, iPiece++ )
- {
- andsum = andsum && inside_flags[ iPiece ];
- orsum = andsum || inside_flags[ iPiece ];
- }
-
- if( andsum!=orsum )
- {
- g_warning( "Inconsistent inside/outside verdict for part=%d", iPart );
- }
+ int iPiece = 0;
+ for (int iPart = 0; iPart < nParts; iPart++) {
+ bool andsum = true;
+ bool orsum = false;
+ for (int iCmd = 0; iCmd < parts[iPart]->descr_cmd.size(); iCmd++, iPiece++) {
+ andsum = andsum && inside_flags[ iPiece ];
+ orsum = andsum || inside_flags[ iPiece ];
+ }
+
+ if (andsum != orsum) {
+ g_warning("Inconsistent inside/outside verdict for part=%d", iPart);
+ }
}
- g_free(parts);
+ g_free(parts);
#endif
- // iterate over the commands of a path and keep those which are inside
- int iDest=0;
- for( int iSrc=0; iSrc<result_path->descr_cmd.size(); iSrc++ )
- {
- if( inside_flags[iSrc]==inside )
- {
- result_path->descr_cmd[iDest++] = result_path->descr_cmd[iSrc];
- }
- else
- {
- delete result_path->descr_cmd[iSrc];
- }
- }
- result_path->descr_cmd.resize( iDest );
-
- delete combined_inters;
- delete combined_shape;
- delete area_shape;
- delete contour_path;
- delete area_path;
-
- gchar *result_str = result_path->svg_dump_path();
- Geom::PathVector outres = Geom::parse_svg_path(result_str);
- // CONCEPT TESTING g_warning( "%s", result_str );
- g_free(result_str);
- delete result_path;
-
- return outres;
+ // iterate over the commands of a path and keep those which are inside
+ int iDest = 0;
+ for (int iSrc = 0; iSrc < result_path->descr_cmd.size(); iSrc++) {
+ if (inside_flags[iSrc] == inside) {
+ result_path->descr_cmd[iDest++] = result_path->descr_cmd[iSrc];
+ } else {
+ delete result_path->descr_cmd[iSrc];
+ }
+ }
+ result_path->descr_cmd.resize(iDest);
+
+ delete combined_inters;
+ delete combined_shape;
+ delete area_shape;
+ delete contour_path;
+ delete area_path;
+
+ gchar *result_str = result_path->svg_dump_path();
+ Geom::PathVector outres = Geom::parse_svg_path(result_str);
+ // CONCEPT TESTING g_warning( "%s", result_str );
+ g_free(result_str);
+ delete result_path;
+
+ return outres;
}
// remove inner contours
@@ -324,17 +317,17 @@ Geom::PathVector
sp_pathvector_boolop_remove_inner(Geom::PathVector const &pathva, fill_typ fra)
{
Geom::PathVector patht;
- Path *patha = Path_for_pathvector(pathv_to_linear_and_cubic_beziers( pathva ) );
+ Path *patha = Path_for_pathvector(pathv_to_linear_and_cubic_beziers(pathva));
Shape *shape = new Shape;
Shape *shapeshape = new Shape;
Path *resultp = new Path;
resultp->SetBackData(false);
- patha->ConvertWithBackData(0.1);
- patha->Fill(shape, 0);
- shapeshape->ConvertToShape(shape, fra);
- shapeshape->ConvertToForme(resultp, 1, &patha);
+ patha->ConvertWithBackData(0.1);
+ patha->Fill(shape, 0);
+ shapeshape->ConvertToShape(shape, fra);
+ shapeshape->ConvertToForme(resultp, 1, &patha);
delete shape;
delete shapeshape;
@@ -361,73 +354,46 @@ static fill_typ GetFillTyp(SPItem *item)
}
}
-void LPEBool::doEffect (SPCurve * curve)
+void LPEBool::doEffect(SPCurve *curve)
{
Geom::PathVector path_in = curve->get_pathvector();
- if ( operand_path.linksToPath() && operand_path.getObject() )
- {
- bool_op_ex op = bool_operation.get_value();
- bool swap = swap_operands.get_value();
-
- Geom::PathVector path_a = swap ? operand_path.get_pathvector() : path_in;
- Geom::PathVector path_b = swap ? path_in : operand_path.get_pathvector();
-
- // TODO: I would like to use the original objects fill rule if the UI selected rule is fill_justDont.
- // But it doesn't seem possible to access them from here, because SPCurve is not derived from SPItem.
- // The nearest function in the call stack, where this is available is SPLPEItem::performPathEffect (this is then an SPItem)
- // For the parameter curve, this is possible.
- // fill_typ fill_this = fill_type_this. get_value()!=fill_justDont ? fill_type_this.get_value() : GetFillTyp( curve ) ;
- fill_typ fill_this = fill_type_this.get_value();
- fill_typ fill_operand = fill_type_operand.get_value()!=fill_justDont ? fill_type_operand.get_value() : GetFillTyp( operand_path.getObject() );
-
- fill_typ fill_a = swap ? fill_operand : fill_this;
- fill_typ fill_b = swap ? fill_this : fill_operand;
-
- switch( op )
- {
- case bool_op_ex_slice_rmv_inner:
- op = bool_op_ex_slice;
- path_b = sp_pathvector_boolop_remove_inner( path_b, fill_b );
- break;
-
- case bool_op_ex_slice_inside_rmv_inner:
- op = bool_op_ex_slice_inside;
- path_b = sp_pathvector_boolop_remove_inner( path_b, fill_b );
- break;
-
- case bool_op_ex_slice_outside_rmv_inner:
- op = bool_op_ex_slice_outside;
- path_b = sp_pathvector_boolop_remove_inner( path_b, fill_b );
- break;
- }
-
- Geom::PathVector path_out;
-
- if( op==bool_op_ex_slice || op == bool_op_ex_slice_rmv_inner) {
- if( op==bool_op_ex_slice_rmv_inner )
- {
- path_b = sp_pathvector_boolop_remove_inner( path_b, fill_b );
- }
- path_out = sp_pathvector_boolop( path_b, path_a, to_bool_op(op), fill_b, fill_a);
- }
- else if( op==bool_op_ex_slice_inside || op==bool_op_ex_slice_inside_rmv_inner ) {
- if( op==bool_op_ex_slice_inside_rmv_inner )
- {
- path_b = sp_pathvector_boolop_remove_inner( path_b, fill_b );
- }
- path_out = sp_pathvector_boolop_slice_intersect( path_a, path_b, true, fill_a, fill_b);
- } else if( op==bool_op_ex_slice_outside || op == bool_op_ex_slice_outside_rmv_inner ) {
- if( op==bool_op_ex_slice_outside_rmv_inner )
- {
- path_b = sp_pathvector_boolop_remove_inner( path_b, fill_b );
- }
- path_out = sp_pathvector_boolop_slice_intersect( path_a, path_b, false, fill_a, fill_b);
- } else {
- path_out = sp_pathvector_boolop( path_a, path_b, to_bool_op(op), fill_a, fill_b);
- }
- curve->set_pathvector( path_out );
- }
+ if (operand_path.linksToPath() && operand_path.getObject()) {
+ bool_op_ex op = bool_operation.get_value();
+ bool swap = swap_operands.get_value();
+
+ Geom::PathVector path_a = swap ? operand_path.get_pathvector() : path_in;
+ Geom::PathVector path_b = swap ? path_in : operand_path.get_pathvector();
+
+ // TODO: I would like to use the original objects fill rule if the UI selected rule is fill_justDont.
+ // But it doesn't seem possible to access them from here, because SPCurve is not derived from SPItem.
+ // The nearest function in the call stack, where this is available is SPLPEItem::performPathEffect (this is then an SPItem)
+ // For the parameter curve, this is possible.
+ // fill_typ fill_this = fill_type_this. get_value()!=fill_justDont ? fill_type_this.get_value() : GetFillTyp( curve ) ;
+ fill_typ fill_this = fill_type_this.get_value();
+ fill_typ fill_operand = fill_type_operand.get_value() != fill_justDont ? fill_type_operand.get_value() : GetFillTyp(operand_path.getObject());
+
+ fill_typ fill_a = swap ? fill_operand : fill_this;
+ fill_typ fill_b = swap ? fill_this : fill_operand;
+
+ if (rmv_inner.get_value()) {
+ path_b = sp_pathvector_boolop_remove_inner(path_b, fill_b);
+ }
+
+ Geom::PathVector path_out;
+
+ if (op == bool_op_ex_slice) {
+ // For slicing, the bool op is added to the line group which is sliced, not the cut path. This swapped order is correct.
+ path_out = sp_pathvector_boolop(path_b, path_a, to_bool_op(op), fill_b, fill_a);
+ } else if (op == bool_op_ex_slice_inside) {
+ path_out = sp_pathvector_boolop_slice_intersect(path_a, path_b, true, fill_a, fill_b);
+ } else if (op == bool_op_ex_slice_outside) {
+ path_out = sp_pathvector_boolop_slice_intersect(path_a, path_b, false, fill_a, fill_b);
+ } else {
+ path_out = sp_pathvector_boolop(path_a, path_b, to_bool_op(op), fill_a, fill_b);
+ }
+ curve->set_pathvector(path_out);
+ }
}
} // namespace LivePathEffect
diff --git a/src/live_effects/lpe-bool.h b/src/live_effects/lpe-bool.h
index 12c51b4ec..1c0aa0243 100644
--- a/src/live_effects/lpe-bool.h
+++ b/src/live_effects/lpe-bool.h
@@ -24,40 +24,37 @@ public:
LPEBool(LivePathEffectObject *lpeobject);
virtual ~LPEBool();
- void doEffect (SPCurve * curve);
- virtual void resetDefaults(SPItem const * item);
-
- enum bool_op_ex
- {
- bool_op_ex_union = bool_op_union,
- bool_op_ex_inters = bool_op_inters,
- bool_op_ex_diff = bool_op_diff,
- bool_op_ex_symdiff = bool_op_symdiff,
- bool_op_ex_cut = bool_op_cut,
- bool_op_ex_slice = bool_op_slice,
- bool_op_ex_slice_inside, // like bool_op_slice, but leaves only the contour pieces inside of the cut path
- bool_op_ex_slice_outside, // like bool_op_slice, but leaves only the contour pieces outside of the cut path
- bool_op_ex_slice_rmv_inner, // like bool_op_ex_slice, but remove inner contours
- bool_op_ex_slice_inside_rmv_inner, // like bool_op_ex_slice_inside, but remove inner contours
- bool_op_ex_slice_outside_rmv_inner, // like bool_op_ex_slice_outside, but remove inner contours
- bool_op_ex_count
+ void doEffect(SPCurve *curve);
+ virtual void resetDefaults(SPItem const *item);
+
+ enum bool_op_ex {
+ bool_op_ex_union = bool_op_union,
+ bool_op_ex_inters = bool_op_inters,
+ bool_op_ex_diff = bool_op_diff,
+ bool_op_ex_symdiff = bool_op_symdiff,
+ bool_op_ex_cut = bool_op_cut,
+ bool_op_ex_slice = bool_op_slice,
+ bool_op_ex_slice_inside, // like bool_op_slice, but leaves only the contour pieces inside of the cut path
+ bool_op_ex_slice_outside, // like bool_op_slice, but leaves only the contour pieces outside of the cut path
+ bool_op_ex_count
};
- inline friend bool_op to_bool_op( bool_op_ex val )
+ inline friend bool_op to_bool_op(bool_op_ex val)
{
- assert( val<=bool_op_ex_slice );
- (bool_op) val;
+ assert(val <= bool_op_ex_slice);
+ (bool_op) val;
}
private:
- LPEBool(const LPEBool&);
- LPEBool& operator=(const LPEBool&);
+ LPEBool(const LPEBool &);
+ LPEBool &operator=(const LPEBool &);
OriginalPathParam operand_path;
EnumParam<bool_op_ex> bool_operation;
EnumParam<fill_typ> fill_type_this;
EnumParam<fill_typ> fill_type_operand;
BoolParam swap_operands;
+ BoolParam rmv_inner;
};
}; //namespace LivePathEffect
diff --git a/src/live_effects/lpe-bounding-box.cpp b/src/live_effects/lpe-bounding-box.cpp
index 43a60d482..c83d7e3bc 100644
--- a/src/live_effects/lpe-bounding-box.cpp
+++ b/src/live_effects/lpe-bounding-box.cpp
@@ -3,18 +3,14 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-bounding-box.h"
#include "display/curve.h"
-#include "sp-item.h"
-#include "2geom/path.h"
#include "sp-shape.h"
#include "sp-text.h"
-#include "2geom/bezier-curve.h"
-#include "lpe-bounding-box.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -24,8 +20,8 @@ LPEBoundingBox::LPEBoundingBox(LivePathEffectObject *lpeobject) :
linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this),
visual_bounds(_("Visual Bounds"), _("Uses the visual bounding box"), "visualbounds", &wr, this)
{
- registerParameter( dynamic_cast<Parameter *>(&linked_path) );
- registerParameter( dynamic_cast<Parameter *>(&visual_bounds) );
+ registerParameter(&linked_path);
+ registerParameter(&visual_bounds);
//perceived_path = true;
}
@@ -45,6 +41,7 @@ void LPEBoundingBox::doEffect (SPCurve * curve)
p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->bottom()));
p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->bottom()));
p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->top()));
+ p.close();
Geom::PathVector out;
out.push_back(p);
curve->set_pathvector(out);
diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp
index 1423e670a..721a4ecab 100644
--- a/src/live_effects/lpe-bspline.cpp
+++ b/src/live_effects/lpe-bspline.cpp
@@ -44,12 +44,12 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject)
weight.param_set_range(NO_POWER, 100.0);
weight.param_set_increments(0.1, 0.1);
weight.param_set_digits(4);
- weight.param_overwrite_widget(true);
+ weight.param_set_undo(false);
steps.param_set_range(1, 10);
steps.param_set_increments(1, 1);
steps.param_set_digits(0);
- steps.param_overwrite_widget(true);
+ steps.param_set_undo(false);
helper_size.param_set_range(0.0, 999.0);
helper_size.param_set_increments(1, 1);
@@ -86,7 +86,7 @@ Gtk::Widget *LPEBSpline::newWidget()
// use manage here, because after deletion of Effect object, others might
// still be pointing to this widget.
Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
-
+ vbox->set_homogeneous(false);
vbox->set_border_width(5);
std::vector<Parameter *>::iterator it = param_vector.begin();
while (it != param_vector.end()) {
@@ -168,6 +168,7 @@ void LPEBSpline::changeWeight(double weight_ammount)
doBSplineFromWidget(curve, weight_ammount/100.0);
gchar *str = sp_svg_write_path(curve->get_pathvector());
path->getRepr()->setAttribute("inkscape:original-d", str);
+ g_free(str);
}
}
diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h
index 7823f00f0..90cf82c19 100644
--- a/src/live_effects/lpe-bspline.h
+++ b/src/live_effects/lpe-bspline.h
@@ -6,8 +6,8 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "live_effects/effect.h"
+#include "live_effects/effect.h"
#include <vector>
namespace Inkscape {
diff --git a/src/live_effects/lpe-circle_3pts.cpp b/src/live_effects/lpe-circle_3pts.cpp
index dbb1f4b6b..3410b13f2 100644
--- a/src/live_effects/lpe-circle_3pts.cpp
+++ b/src/live_effects/lpe-circle_3pts.cpp
@@ -15,9 +15,10 @@
#include "live_effects/lpe-circle_3pts.h"
// You might need to include other 2geom files. You can add them here:
-#include <2geom/path.h>
#include <2geom/circle.h>
#include <2geom/path-sink.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-circle_with_radius.cpp b/src/live_effects/lpe-circle_with_radius.cpp
index 8f2156044..fcefc4ec6 100644
--- a/src/live_effects/lpe-circle_with_radius.cpp
+++ b/src/live_effects/lpe-circle_with_radius.cpp
@@ -15,9 +15,10 @@
#include "display/curve.h"
// You might need to include other 2geom files. You can add them here:
-#include <2geom/pathvector.h>
#include <2geom/circle.h>
#include <2geom/path-sink.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using namespace Geom;
diff --git a/src/live_effects/lpe-clone-original.cpp b/src/live_effects/lpe-clone-original.cpp
index 7541c0be2..31bf0e270 100644
--- a/src/live_effects/lpe-clone-original.cpp
+++ b/src/live_effects/lpe-clone-original.cpp
@@ -4,20 +4,338 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-clone-original.h"
-
#include "display/curve.h"
+#include "svg/path-string.h"
+#include "svg/svg.h"
+#include "sp-clippath.h"
+#include "sp-mask.h"
+#include "xml/sp-css-attr.h"
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
LPECloneOriginal::LPECloneOriginal(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
- linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this)
+ linkeditem(_("Linked Item:"), _("Item from which to take the original data"), "linkeditem", &wr, this),
+ scale(_("Scale %"), _("Scale item %"), "scale", &wr, this, 100.0),
+ preserve_position(_("Preserve position"), _("Preserve position"), "preserve_position", &wr, this, false),
+ inverse(_("Inverse clone"), _("Use LPE item as origin"), "inverse", &wr, this, false),
+ d(_("Clone shape -d-"), _("Clone shape -d-"), "d", &wr, this, true),
+ transform(_("Clone transforms"), _("Clone transforms"), "transform", &wr, this, true),
+ fill(_("Clone fill"), _("Clone fill"), "fill", &wr, this, false),
+ stroke(_("Clone stroke"), _("Clone stroke"), "stroke", &wr, this, false),
+ paintorder(_("Clone paint order"), _("Clone paint order"), "paintorder", &wr, this, false),
+ opacity(_("Clone opacity"), _("Clone opacity"), "opacity", &wr, this, false),
+ filter(_("Clone filter"), _("Clone filter"), "filter", &wr, this, false),
+ attributes("Attributes linked", "Attributes linked, comma separated atributes", "attributes", &wr, this,""),
+ style_attributes("Style attributes linked", "Style attributes linked, comma separated atributes", "style_attributes", &wr, this,""),
+ expanded(false),
+ origin(Geom::Point(0,0))
{
- registerParameter( dynamic_cast<Parameter *>(&linked_path) );
+ //0.92 compatibility
+ const gchar * linkedpath = this->getRepr()->attribute("linkedpath");
+ if (linkedpath && strcmp(linkedpath, "") != 0){
+ this->getRepr()->setAttribute("linkeditem", linkedpath);
+ this->getRepr()->setAttribute("linkedpath", NULL);
+ this->getRepr()->setAttribute("transform", "false");
+ };
+
+ registerParameter(&linkeditem);
+ registerParameter(&scale);
+ registerParameter(&attributes);
+ registerParameter(&style_attributes);
+ registerParameter(&preserve_position);
+ registerParameter(&inverse);
+ registerParameter(&d);
+ registerParameter(&transform);
+ registerParameter(&fill);
+ registerParameter(&stroke);
+ registerParameter(&paintorder);
+ registerParameter(&opacity);
+ registerParameter(&filter);
+ scale.param_set_range(0.01, 999999.0);
+ scale.param_set_increments(1, 1);
+ scale.param_set_digits(2);
+ attributes.param_hide_canvas_text();
+ style_attributes.param_hide_canvas_text();
+ preserve_position_changed = preserve_position;
+ preserve_affine = Geom::identity();
+}
+
+void
+LPECloneOriginal::cloneAttrbutes(SPObject *origin, SPObject *dest, bool live, const char * attributes, const char * style_attributes, bool root)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ if ( SP_IS_GROUP(origin) && SP_IS_GROUP(dest) && SP_GROUP(origin)->getItemCount() == SP_GROUP(dest)->getItemCount() ) {
+ std::vector< SPObject * > childs = origin->childList(true);
+ size_t index = 0;
+ for (std::vector<SPObject * >::iterator obj_it = childs.begin();
+ obj_it != childs.end(); ++obj_it) {
+ SPObject *dest_child = dest->nthChild(index);
+ cloneAttrbutes((*obj_it), dest_child, live, attributes, style_attributes, false);
+ index++;
+ }
+ }
+ //Attributes
+ SPShape * shape_origin = SP_SHAPE(origin);
+ SPPath * path_origin = SP_PATH(origin);
+ SPShape * shape_dest = SP_SHAPE(dest);
+ SPMask *mask_origin = SP_ITEM(origin)->mask_ref->getObject();
+ SPMask *mask_dest = SP_ITEM(dest)->mask_ref->getObject();
+ if(mask_origin && mask_dest) {
+ std::vector<SPObject*> mask_list = mask_origin->childList(true);
+ std::vector<SPObject*> mask_list_dest = mask_dest->childList(true);
+ if (mask_list.size() == mask_list_dest.size()) {
+ size_t i = 0;
+ for ( std::vector<SPObject*>::const_iterator iter=mask_list.begin();iter!=mask_list.end();++iter) {
+ SPObject * mask_data = *iter;
+ SPObject * mask_dest_data = mask_list_dest[i];
+ cloneAttrbutes(mask_data, mask_dest_data, live, attributes, style_attributes, false);
+ i++;
+ }
+ }
+ }
+ SPClipPath *clippath_origin = SP_ITEM(origin)->clip_ref->getObject();
+ SPClipPath *clippath_dest = SP_ITEM(dest)->clip_ref->getObject();
+ if(clippath_origin && clippath_dest) {
+ std::vector<SPObject*> clippath_list = clippath_origin->childList(true);
+ std::vector<SPObject*> clippath_list_dest = clippath_dest->childList(true);
+ if (clippath_list.size() == clippath_list_dest.size()) {
+ size_t i = 0;
+ for ( std::vector<SPObject*>::const_iterator iter=clippath_list.begin();iter!=clippath_list.end();++iter) {
+ SPObject * clippath_data = *iter;
+ SPObject * clippath_dest_data = clippath_list_dest[i];
+ cloneAttrbutes(clippath_data, clippath_dest_data, live, attributes, style_attributes, false);
+ i++;
+ }
+ }
+ }
+ gchar ** attarray = g_strsplit(attributes, ",", 0);
+ gchar ** iter = attarray;
+ Geom::Affine affine_dest = Geom::identity();
+ Geom::Affine affine_origin = Geom::identity();
+ Geom::Affine affine_previous = Geom::identity();
+ sp_svg_transform_read(SP_ITEM(dest)->getAttribute("transform"), &affine_dest);
+ sp_svg_transform_read(SP_ITEM(origin)->getAttribute("transform"), &affine_origin);
+ while (*iter != NULL) {
+ const char* attribute = (*iter);
+ if ( std::strcmp(attribute, "transform") == 0 ) {
+ if (preserve_position) {
+ Geom::Affine dest_affine = Geom::identity();
+ if (root) {
+ dest_affine *= affine_origin;
+ if (preserve_affine == Geom::identity()) {
+ dest_affine *= Geom::Translate(affine_dest.translation());
+ }
+ dest_affine *= Geom::Translate(affine_origin.translation()).inverse();
+ dest_affine *= Geom::Translate(preserve_affine.translation());
+ affine_previous = preserve_affine;
+ preserve_affine = Geom::identity();
+ gchar * str = sp_svg_transform_write(dest_affine);
+ SP_ITEM(dest)->getRepr()->setAttribute("transform", str);
+ g_free(str);
+ }
+ } else {
+ gchar * str = sp_svg_transform_write(affine_origin);
+ SP_ITEM(dest)->getRepr()->setAttribute("transform", str);
+ g_free(str);
+ }
+ } else if ( shape_dest && shape_origin && live && (std::strcmp(attribute, "d") == 0)) {
+ SPCurve *c = NULL;
+ if (inverse) {
+ c = shape_origin->getCurveBeforeLPE();
+ } else {
+ c = shape_origin->getCurve();
+ }
+ if (c) {
+ Geom::PathVector c_pv = c->get_pathvector();
+ Geom::OptRect orig_bbox = SP_ITEM(origin)->geometricBounds();
+ Geom::OptRect dest_bbox = SP_ITEM(dest)->geometricBounds();
+ if (dest_bbox && orig_bbox && root) {
+ Geom::Point orig_point = (*orig_bbox).corner(0);
+ Geom::Point dest_point = (*dest_bbox).corner(0);
+ if (scale != 100.0) {
+ double scale_affine = scale/100.0;
+ Geom::Scale scale = Geom::Scale(scale_affine);
+ c_pv *= Geom::Translate(orig_point).inverse();
+ c_pv *= scale;
+ c_pv *= Geom::Translate(orig_point);
+ }
+ if (preserve_position) {
+ c_pv *= Geom::Translate(dest_point - orig_point);
+ }
+ }
+ if (inverse) {
+ c_pv *= i2anc_affine(origin, sp_lpe_item);
+ } else {
+ c_pv *= i2anc_affine(dest, sp_lpe_item);
+ }
+ c->set_pathvector(c_pv);
+ if (!path_origin) {
+ shape_dest->setCurveInsync(c, TRUE);
+ gchar *str = sp_svg_write_path(c_pv);
+ dest->getRepr()->setAttribute(attribute, str);
+ g_free(str);
+ } else {
+ shape_dest->setCurve(c, TRUE);
+ }
+ c->unref();
+ } else {
+ dest->getRepr()->setAttribute(attribute, NULL);
+ }
+ } else {
+ dest->getRepr()->setAttribute(attribute, origin->getRepr()->attribute(attribute));
+ }
+ iter++;
+ }
+ g_strfreev (attarray);
+ SPCSSAttr *css_origin = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css_origin, origin->getRepr()->attribute("style"));
+ SPCSSAttr *css_dest = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css_dest, dest->getRepr()->attribute("style"));
+ gchar ** styleattarray = g_strsplit(style_attributes, ",", 0);
+ gchar ** styleiter = styleattarray;
+ while (*styleiter != NULL) {
+ const char* attribute = (*styleiter);
+ const char* origin_attribute = sp_repr_css_property(css_origin, attribute, "");
+ if (!strlen(origin_attribute)) { //==0
+ sp_repr_css_set_property (css_dest, attribute, NULL);
+ } else {
+ sp_repr_css_set_property (css_dest, attribute, origin_attribute);
+ }
+ styleiter++;
+ }
+ g_strfreev (styleattarray);
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css_dest,css_str);
+ dest->getRepr()->setAttribute("style", css_str.c_str());
+}
+
+void
+LPECloneOriginal::doBeforeEffect (SPLPEItem const* lpeitem){
+ if (linkeditem.linksToItem()) {
+ linkeditem.setInverse(inverse);
+ if ( preserve_position_changed != preserve_position ) {
+ if (!preserve_position) {
+ sp_svg_transform_read(SP_ITEM(sp_lpe_item)->getAttribute("transform"), &preserve_affine);
+ }
+ preserve_position_changed = preserve_position;
+ }
+ Glib::ustring attr = "";
+ if (d) {
+ attr.append("d,");
+ }
+ if (transform) {
+ attr.append("transform,");
+ }
+ attr.append(Glib::ustring(attributes.param_getSVGValue()).append(","));
+ if (attr.size() && !Glib::ustring(attributes.param_getSVGValue()).size()) {
+ attr.erase (attr.size()-1, 1);
+ }
+ Glib::ustring style_attr = "";
+ if (fill) {
+ style_attr.append("fill,").append("fill-rule,");
+ }
+ if (stroke) {
+ style_attr.append("stroke,").append("stroke-width,").append("stroke-linecap,").append("stroke-linejoin,");
+ style_attr.append("stroke-opacity,").append("stroke-miterlimit,").append("stroke-dasharray,");
+ style_attr.append("stroke-opacity,").append("stroke-dashoffset,").append("marker-start,");
+ style_attr.append("marker-mid,").append("marker-end,");
+ }
+ if (paintorder) {
+ style_attr.append("paint-order,");
+ }
+ if (filter) {
+ style_attr.append("filter,");
+ }
+ if (opacity) {
+ style_attr.append("opacity,");
+ }
+ if (style_attr.size() && !Glib::ustring(style_attributes.param_getSVGValue()).size()) {
+ style_attr.erase (style_attr.size()-1, 1);
+ }
+ style_attr.append(Glib::ustring(style_attributes.param_getSVGValue()).append(","));
+
+ SPItem * from = inverse ? SP_ITEM(sp_lpe_item) : SP_ITEM(linkeditem.getObject());
+ SPItem * to = !inverse ? SP_ITEM(sp_lpe_item) : SP_ITEM(linkeditem.getObject());
+ cloneAttrbutes(from, to, true, g_strdup(attr.c_str()), g_strdup(style_attr.c_str()), true);
+ Geom::OptRect bbox = from->geometricBounds();
+ if (bbox && preserve_position && origin != Geom::Point(0,0)) {
+ origin = (*bbox).corner(0) - origin;
+ to->transform *= Geom::Translate(origin);
+ }
+ bbox = from->geometricBounds();
+ if (bbox && preserve_position) {
+ origin = (*bbox).corner(0);
+ }
+ }
+}
+
+
+Gtk::Widget *
+LPECloneOriginal::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might
+ // still be pointing to this widget.
+ Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(2);
+ Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) );
+ vbox_expander->set_border_width(0);
+ vbox_expander->set_spacing(2);
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter * param = *it;
+ if (param->param_key == "linkedpath") {
+ ++it;
+ continue;
+ }
+ Gtk::Widget * widg = param->param_newWidget();
+ Glib::ustring * tip = param->param_getTooltip();
+ if (widg) {
+ if (param->param_key != "attributes" &&
+ param->param_key != "style_attributes") {
+ vbox->pack_start(*widg, true, true, 2);
+ } else {
+ vbox_expander->pack_start(*widg, true, true, 2);
+ }
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+
+ ++it;
+ }
+ expander = Gtk::manage(new Gtk::Expander(Glib::ustring(_("Show attributes override"))));
+ expander->add(*vbox_expander);
+ expander->set_expanded(expanded);
+ expander->property_expanded().signal_changed().connect(sigc::mem_fun(*this, &LPECloneOriginal::onExpanderChanged) );
+ vbox->pack_start(*expander, true, true, 2);
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+void
+LPECloneOriginal::onExpanderChanged()
+{
+ expanded = expander->get_expanded();
+ if(expanded) {
+ expander->set_label (Glib::ustring(_("Hide attributes override")));
+ } else {
+ expander->set_label (Glib::ustring(_("Show attributes override")));
+ }
}
LPECloneOriginal::~LPECloneOriginal()
@@ -25,12 +343,21 @@ LPECloneOriginal::~LPECloneOriginal()
}
-void LPECloneOriginal::doEffect (SPCurve * curve)
+void
+LPECloneOriginal::transform_multiply(Geom::Affine const& postmul, bool set)
+{
+ if (linkeditem.linksToItem()) {
+ linkeditem.getObject()->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+}
+
+void
+LPECloneOriginal::doEffect (SPCurve * curve)
{
- if ( linked_path.linksToPath() ) {
- Geom::PathVector linked_pathv = linked_path.get_pathvector();
- if ( !linked_pathv.empty() ) {
- curve->set_pathvector(linked_pathv);
+ if (linkeditem.linksToItem() && !inverse) {
+ SPShape * shape = getCurrentShape();
+ if(shape){
+ curve->set_pathvector(shape->getCurve()->get_pathvector());
}
}
}
diff --git a/src/live_effects/lpe-clone-original.h b/src/live_effects/lpe-clone-original.h
index abf65ded8..9bab8553f 100644
--- a/src/live_effects/lpe-clone-original.h
+++ b/src/live_effects/lpe-clone-original.h
@@ -8,24 +8,48 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
+#include <gtkmm/expander.h>
#include "live_effects/effect.h"
+#include "live_effects/parameter/originalitem.h"
#include "live_effects/parameter/originalpath.h"
+#include "live_effects/parameter/parameter.h"
+#include "live_effects/parameter/point.h"
+#include "live_effects/parameter/text.h"
+#include "live_effects/lpegroupbbox.h"
namespace Inkscape {
namespace LivePathEffect {
-class LPECloneOriginal : public Effect {
+class LPECloneOriginal : public Effect, GroupBBoxEffect {
public:
LPECloneOriginal(LivePathEffectObject *lpeobject);
virtual ~LPECloneOriginal();
-
virtual void doEffect (SPCurve * curve);
+ virtual void doBeforeEffect (SPLPEItem const* lpeitem);
+ virtual void transform_multiply(Geom::Affine const& postmul, bool set);
+ virtual Gtk::Widget * newWidget();
+ void onExpanderChanged();
+ void cloneAttrbutes(SPObject *origin, SPObject *dest, bool live, const char * attributes, const char * style_attributes, bool root);
private:
- OriginalPathParam linked_path;
-
-private:
+ OriginalItemParam linkeditem;
+ ScalarParam scale;
+ BoolParam preserve_position;
+ BoolParam inverse;
+ BoolParam d;
+ BoolParam transform;
+ BoolParam fill;
+ BoolParam stroke;
+ BoolParam paintorder;
+ BoolParam opacity;
+ BoolParam filter;
+ TextParam attributes;
+ TextParam style_attributes;
+ Geom::Point origin;
+ bool preserve_position_changed;
+ bool expanded;
+ Gtk::Expander * expander;
+ Geom::Affine preserve_affine;
LPECloneOriginal(const LPECloneOriginal&);
LPECloneOriginal& operator=(const LPECloneOriginal&);
};
diff --git a/src/live_effects/lpe-constructgrid.cpp b/src/live_effects/lpe-constructgrid.cpp
index b1e0edaac..db620fa95 100644
--- a/src/live_effects/lpe-constructgrid.cpp
+++ b/src/live_effects/lpe-constructgrid.cpp
@@ -10,12 +10,9 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-constructgrid.h"
-
-#include <2geom/path.h>
-#include <2geom/transforms.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -27,8 +24,8 @@ LPEConstructGrid::LPEConstructGrid(LivePathEffectObject *lpeobject) :
nr_x(_("Size _X:"), _("The size of the grid in X direction."), "nr_x", &wr, this, 5),
nr_y(_("Size _Y:"), _("The size of the grid in Y direction."), "nr_y", &wr, this, 5)
{
- registerParameter( dynamic_cast<Parameter *>(&nr_x) );
- registerParameter( dynamic_cast<Parameter *>(&nr_y) );
+ registerParameter(&nr_x);
+ registerParameter(&nr_y);
nr_x.param_make_integer();
nr_y.param_make_integer();
diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp
index efea76039..3abcbf217 100644
--- a/src/live_effects/lpe-copy_rotate.cpp
+++ b/src/live_effects/lpe-copy_rotate.cpp
@@ -11,38 +11,32 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
+#include <gtkmm.h>
#include <gdk/gdk.h>
#include <2geom/path-intersection.h>
#include <2geom/sbasis-to-bezier.h>
+#include <2geom/intersection-graph.h>
#include "live_effects/lpe-copy_rotate.h"
-#include <2geom/path.h>
-#include <2geom/transforms.h>
-#include <2geom/angle.h>
-
-#include "knot-holder-entity.h"
-#include "knotholder.h"
+#include "display/curve.h"
+#include "svg/path-string.h"
+#include "svg/svg.h"
+#include "style.h"
+#include "helper/geom.h"
+#include "xml/sp-css-attr.h"
+#include "path-chemistry.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
-namespace CR {
-
-class KnotHolderEntityStartingAngle : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityStartingAngle(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
+static const Util::EnumData<RotateMethod> RotateMethodData[RM_END] = {
+ { RM_NORMAL, N_("Normal"), "normal" },
+ { RM_KALEIDOSCOPE, N_("Kaleidoscope"), "kaleidoskope" },
+ { RM_FUSE, N_("Fuse paths"), "fuse_paths" }
};
-
-class KnotHolderEntityRotationAngle : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityRotationAngle(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
-};
-
-} // namespace CR
+static const Util::EnumDataConverter<RotateMethod>
+RMConverter(RotateMethodData, RM_END);
bool
pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3)
@@ -61,28 +55,49 @@ pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &
LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
- origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"),
- starting_angle(_("Starting:"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0),
- rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 60.0),
- num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 6),
+ method(_("Method:"), _("Rotate methods"), "method", RMConverter, &wr, this, RM_NORMAL),
+ origin(_("Origin"), _("Adjust origin of the rotation"), "origin", &wr, this, _("Adjust origin of the rotation")),
+ starting_point(_("Start point"), _("Starting point to define start angle"), "starting_point", &wr, this, _("Adjust starting point to define start angle")),
+ starting_angle(_("Starting angle"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0),
+ rotation_angle(_("Rotation angle"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 60.0),
+ num_copies(_("Number of copies"), _("Number of copies of the original path"), "num_copies", &wr, this, 6),
+ gap(_("Gap"), _("Gap"), "gap", &wr, this, -0.0001),
copies_to_360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copies_to_360", &wr, this, true),
- fuse_paths(_("Fuse paths"), _("Fuse paths by helper line, use fill-rule: evenodd for best result"), "fuse_paths", &wr, this, false),
+ mirror_copies(_("Mirror copies"), _("Mirror between copies"), "mirror_copies", &wr, this, false),
+ split_items(_("Split elements"), _("Split elements, this allow gradients and other paints."), "split_items", &wr, this, false),
dist_angle_handle(100.0)
{
show_orig_path = true;
_provides_knotholder_entities = true;
- apply_to_clippath_and_mask = true;
-
+ //0.92 compatibility
+ if (this->getRepr()->attribute("fuse_paths") && strcmp(this->getRepr()->attribute("fuse_paths"), "true") == 0){
+ this->getRepr()->setAttribute("fuse_paths", NULL);
+ this->getRepr()->setAttribute("method", "kaleidoskope");
+ this->getRepr()->setAttribute("mirror_copies", "true");
+ };
// register all your parameters here, so Inkscape knows which parameters this effect has:
- registerParameter(&copies_to_360);
- registerParameter(&fuse_paths);
+ registerParameter(&method);
+ registerParameter(&num_copies);
registerParameter(&starting_angle);
+ registerParameter(&starting_point);
registerParameter(&rotation_angle);
- registerParameter(&num_copies);
+ registerParameter(&gap);
registerParameter(&origin);
+ registerParameter(&copies_to_360);
+ registerParameter(&mirror_copies);
+ registerParameter(&split_items);
+ gap.param_set_range(-99999.0, 99999.0);
+ gap.param_set_increments(0.1, 0.1);
+ gap.param_set_digits(5);
+ num_copies.param_set_range(1, 999999);
num_copies.param_make_integer(true);
- num_copies.param_set_range(0, 1000);
+ apply_to_clippath_and_mask = true;
+ previous_num_copies = num_copies;
+ previous_origin = Geom::Point(0,0);
+ previous_start_point = Geom::Point(0,0);
+ starting_point.param_widget_is_visible(false);
+ reset = false;
}
LPECopyRotate::~LPECopyRotate()
@@ -91,6 +106,242 @@ LPECopyRotate::~LPECopyRotate()
}
void
+LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem)
+{
+ if (split_items) {
+ is_load = false;
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ items.clear();
+ container = dynamic_cast<SPObject *>(sp_lpe_item->parent);
+ Inkscape::XML::Node *root = sp_lpe_item->document->getReprRoot();
+ Inkscape::XML::Node *root_origin = document->getReprRoot();
+ if (root_origin != root) {
+ return;
+ }
+ if (previous_num_copies != num_copies) {
+ gint numcopies_gap = previous_num_copies - num_copies;
+ if (numcopies_gap > 0 && num_copies != 0) {
+ guint counter = num_copies - 1;
+ while (numcopies_gap > 0) {
+ const char * id = g_strdup(Glib::ustring("rotated-").append(std::to_string(counter)).append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str());
+ if (!id || strlen(id) == 0) {
+ return;
+ }
+ SPObject *elemref = NULL;
+ if ((elemref = document->getObjectById(id))) {
+ SP_ITEM(elemref)->setHidden(true);
+ }
+ counter++;
+ numcopies_gap--;
+ }
+ }
+ previous_num_copies = num_copies;
+ }
+ SPObject *elemref = NULL;
+ const char * id = g_strdup(Glib::ustring("rotated-").append("0").append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str());
+ guint counter = 0;
+ while((elemref = document->getObjectById(id))) {
+ id = g_strdup(Glib::ustring("rotated-").append(std::to_string(counter)).append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str());
+ if (SP_ITEM(elemref)->isHidden()) {
+ items.push_back(id);
+ }
+ counter++;
+ }
+ Geom::Affine m = Geom::Translate(-origin) * Geom::Rotate(-(Geom::rad_from_deg(starting_angle)));
+ for (size_t i = 1; i < num_copies; ++i) {
+ Geom::Affine r = Geom::identity();
+ if(mirror_copies && i%2 != 0) {
+ r *= Geom::Rotate(Geom::Angle(half_dir)).inverse();
+ r *= Geom::Scale(1, -1);
+ r *= Geom::Rotate(Geom::Angle(half_dir));
+ }
+
+ Geom::Rotate rot(-(Geom::rad_from_deg(rotation_angle * i)));
+ Geom::Affine t = m * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
+ if (method != RM_NORMAL) {
+ if(mirror_copies && i%2 != 0) {
+ t = m * r * rot * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
+ }
+ } else {
+ if(mirror_copies && i%2 != 0) {
+ t = m * Geom::Rotate(Geom::rad_from_deg(-rotation_angle)) * r * rot * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
+ }
+ }
+ t *= sp_lpe_item->transform;
+ toItem(t, i-1, reset);
+ }
+ reset = false;
+ } else {
+ processObjects(LPE_ERASE);
+ items.clear();
+ }
+}
+
+void
+LPECopyRotate::cloneD(SPObject *orig, SPObject *dest, Geom::Affine transform, bool root, bool reset)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ if ( SP_IS_GROUP(orig) && SP_IS_GROUP(dest) && SP_GROUP(orig)->getItemCount() == SP_GROUP(dest)->getItemCount() ) {
+ std::vector< SPObject * > childs = orig->childList(true);
+ size_t index = 0;
+ for (std::vector<SPObject * >::iterator obj_it = childs.begin();
+ obj_it != childs.end(); ++obj_it) {
+ SPObject *dest_child = dest->nthChild(index);
+ cloneD(*obj_it, dest_child, transform, false, reset);
+ index++;
+ }
+ }
+ SPShape * shape = SP_SHAPE(orig);
+ if (shape && !SP_IS_PATH(dest)) {
+ const char * id = dest->getId();
+ Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0);
+ dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL);
+ dest->getRepr()->setAttribute("d", id);
+ }
+ if (SP_IS_PATH(dest) && shape) {
+ SPCurve *c = NULL;
+ if (root) {
+ c = new SPCurve();
+ c->set_pathvector(pathvector_after_effect);
+ } else {
+ c = shape->getCurve();
+ }
+ if (c) {
+ SP_PATH(dest)->setCurve(c, TRUE);
+ c->unref();
+ } else {
+ dest->getRepr()->setAttribute("d", NULL);
+ }
+ if (reset) {
+ dest->getRepr()->setAttribute("style", shape->getRepr()->attribute("style"));
+ }
+ }
+}
+
+void
+LPECopyRotate::toItem(Geom::Affine transform, size_t i, bool reset)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ const char * elemref_id = g_strdup(Glib::ustring("rotated-").append(std::to_string(i)).append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str());
+ items.push_back(elemref_id);
+ SPObject *elemref= NULL;
+ Inkscape::XML::Node *phantom = NULL;
+ if ((elemref = document->getObjectById(elemref_id))) {
+ phantom = elemref->getRepr();
+ } else {
+ phantom = sp_lpe_item->getRepr()->duplicate(xml_doc);
+ std::vector<const char *> attrs;
+ attrs.push_back("inkscape:path-effect");
+ attrs.push_back("inkscape:original-d");
+ attrs.push_back("sodipodi:type");
+ attrs.push_back("sodipodi:rx");
+ attrs.push_back("sodipodi:ry");
+ attrs.push_back("sodipodi:cx");
+ attrs.push_back("sodipodi:cy");
+ attrs.push_back("sodipodi:end");
+ attrs.push_back("sodipodi:start");
+ attrs.push_back("inkscape:flatsided");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:rounded");
+ attrs.push_back("sodipodi:arg1");
+ attrs.push_back("sodipodi:arg2");
+ attrs.push_back("sodipodi:r1");
+ attrs.push_back("sodipodi:r2");
+ attrs.push_back("sodipodi:sides");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("sodipodi:argument");
+ attrs.push_back("sodipodi:expansion");
+ attrs.push_back("sodipodi:radius");
+ attrs.push_back("sodipodi:revolution");
+ attrs.push_back("sodipodi:t0");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("x");
+ attrs.push_back("y");
+ attrs.push_back("rx");
+ attrs.push_back("ry");
+ attrs.push_back("width");
+ attrs.push_back("height");
+ phantom->setAttribute("id", elemref_id);
+ for(const char * attr : attrs) {
+ phantom->setAttribute(attr, NULL);
+ }
+ }
+ if (!elemref) {
+ elemref = container->appendChildRepr(phantom);
+ Inkscape::GC::release(phantom);
+ }
+ cloneD(SP_OBJECT(sp_lpe_item), elemref, transform, true, reset);
+ gchar *str = sp_svg_transform_write(transform);
+ elemref->getRepr()->setAttribute("transform" , str);
+ g_free(str);
+ SP_ITEM(elemref)->setHidden(false);
+ if (elemref->parent != container) {
+ Inkscape::XML::Node *copy = phantom->duplicate(xml_doc);
+ copy->setAttribute("id", elemref_id);
+ container->appendChildRepr(copy);
+ Inkscape::GC::release(copy);
+ elemref->deleteObject();
+ }
+}
+
+void
+LPECopyRotate::resetStyles(){
+ reset = true;
+ doAfterEffect(sp_lpe_item);
+}
+
+Gtk::Widget * LPECopyRotate::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might
+ // still be pointing to this widget.
+ Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
+
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(2);
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter *param = *it;
+ Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
+ Glib::ustring *tip = param->param_getTooltip();
+ if (widg) {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+
+ ++it;
+ }
+ Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0));
+ Gtk::Button * reset_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset styles"))));
+ reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPECopyRotate::resetStyles));
+ reset_button->set_size_request(110,20);
+ vbox->pack_start(*hbox, true,true,2);
+ hbox->pack_start(*reset_button, false, false,2);
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+
+void
LPECopyRotate::doOnApply(SPLPEItem const* lpeitem)
{
using namespace Geom;
@@ -107,17 +358,14 @@ LPECopyRotate::doOnApply(SPLPEItem const* lpeitem)
void
LPECopyRotate::transform_multiply(Geom::Affine const& postmul, bool set)
{
- if(fuse_paths) {
- Geom::Coord angle = Geom::deg_from_rad(atan(-postmul[1]/postmul[0]));
- angle += starting_angle;
- starting_angle.param_set_value(angle);
- }
// cycle through all parameters. Most parameters will not need transformation, but path and point params do.
-
for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) {
Parameter * param = *it;
- param->param_transform_multiply(postmul, set);
+ if(param->param_key != "starting_point" || postmul.isRotation()) {
+ param->param_transform_multiply(postmul, set);
+ }
}
+ sp_lpe_item_update_patheffect(sp_lpe_item, false, false);
}
void
@@ -125,38 +373,54 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem)
{
using namespace Geom;
original_bbox(lpeitem);
- if (copies_to_360) {
+ if (copies_to_360 && num_copies > 2) {
rotation_angle.param_set_value(360.0/(double)num_copies);
}
- if (fuse_paths && rotation_angle * num_copies > 360 && rotation_angle > 0) {
+ if (method != RM_NORMAL && rotation_angle * num_copies > 360.1 && rotation_angle > 0 && copies_to_360) {
num_copies.param_set_value(floor(360/rotation_angle));
}
- if (fuse_paths && copies_to_360) {
- num_copies.param_set_increments(2,2);
+ if (method != RM_NORMAL && mirror_copies && copies_to_360) {
+ num_copies.param_set_increments(2.0,10.0);
if ((int)num_copies%2 !=0) {
num_copies.param_set_value(num_copies+1);
rotation_angle.param_set_value(360.0/(double)num_copies);
}
} else {
- num_copies.param_set_increments(1,1);
+ num_copies.param_set_increments(1.0, 10.0);
}
- if (dist_angle_handle < 1.0) {
- dist_angle_handle = 1.0;
- }
A = Point(boundingbox_X.min(), boundingbox_Y.middle());
B = Point(boundingbox_X.middle(), boundingbox_Y.middle());
+ if (Geom::are_near(A, B, 0.01)) {
+ B += Geom::Point(1.0, 0.0);
+ }
dir = unit_vector(B - A);
// I first suspected the minus sign to be a bug in 2geom but it is
// likely due to SVG's choice of coordinate system orientation (max)
- start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle;
- rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle;
- if ( fuse_paths || copies_to_360 ) {
- rot_pos = origin;
+ bool near_start_point = Geom::are_near(previous_start_point, (Geom::Point)starting_point, 0.01);
+ bool near_origin = Geom::are_near(previous_origin, (Geom::Point)origin, 0.01);
+ if (!near_start_point) {
+ starting_angle.param_set_value(deg_from_rad(-angle_between(dir, starting_point - origin)));
+ if (GDK_SHIFT_MASK) {
+ dist_angle_handle = L2(B - A);
+ } else {
+ dist_angle_handle = L2(starting_point - origin);
+ }
}
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
+ if (dist_angle_handle < 1.0) {
+ dist_angle_handle = 1.0;
+ }
+ double distance = dist_angle_handle;
+ if (previous_start_point != Geom::Point(0,0) || previous_origin != Geom::Point(0,0)) {
+ distance = Geom::distance(previous_origin, starting_point);
+ }
+ start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * distance;
+ if (!near_start_point || !near_origin || split_items) {
+ starting_point.param_setValue(start_pos);
+ }
+
+ previous_origin = (Geom::Point)origin;
+ previous_start_point = (Geom::Point)starting_point;
}
void
@@ -231,30 +495,21 @@ LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double s
}
Geom::PathVector tmp_path_helper;
Geom::Path append_path = original;
-
+ Geom::Point previous = original.finalPoint();
for (int i = 0; i < num_copies; ++i) {
Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * (i)));
Geom::Affine m = pre * rot * Geom::Translate(origin);
- if (i%2 != 0) {
- Geom::Point A = (Geom::Point)origin;
- Geom::Point B = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider;
- Geom::Translate m1(A[0], A[1]);
- double hyp = Geom::distance(A, B);
- double c = (B[0] - A[0]) / hyp; // cos(alpha)
- double s = (B[1] - A[1]) / hyp; // sin(alpha)
-
- Geom::Affine m2(c, -s, s, c, 0.0, 0.0);
- Geom::Scale sca(1.0, -1.0);
-
- Geom::Affine tmp_m = m1.inverse() * m2;
- m = tmp_m;
- m = m * sca;
- m = m * m2.inverse();
- m = m * m1;
+ if (i%2 != 0 && mirror_copies) {
+ Geom::Point point_a = (Geom::Point)origin;
+ Geom::Point point_b = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider;
+ Geom::Line ls(point_a, point_b);
+ m = Geom::reflection (ls.vector(), point_a);
+ append_path *= m;
} else {
append_path = original;
+ append_path *= m;
}
- append_path *= m;
+ previous = append_path.finalPoint();
if (tmp_path_helper.size() > 0) {
if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.finalPoint())) {
Geom::Path tmp_append = append_path.reversed();
@@ -340,63 +595,98 @@ LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double s
tmp_path.clear();
}
-Geom::Piecewise<Geom::D2<Geom::SBasis> >
-LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
+Geom::PathVector
+LPECopyRotate::doEffect_path (Geom::PathVector const & path_in)
{
- using namespace Geom;
-
- if (num_copies == 1 && !fuse_paths) {
- return pwd2_in;
- }
-
+ Geom::PathVector path_out;
double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max()));
- Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max()));
- double size_divider = Geom::distance(origin,bbox) + (diagonal * 2);
- Geom::Point line_start = origin + dir * Rotate(-rad_from_deg(starting_angle)) * size_divider;
- Geom::Point line_end = origin + dir * Rotate(-rad_from_deg(rotation_angle + starting_angle)) * size_divider;
- //Note:: beter way to do this
- //Whith AppendNew have problems whith the crossing order
- Geom::Path divider = Geom::Path(line_start);
+ Geom::OptRect bbox = sp_lpe_item->geometricBounds();
+ size_divider = Geom::distance(origin,bbox) + (diagonal * 6);
+ Geom::Point line_start = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))) * size_divider;
+ Geom::Point line_end = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(rotation_angle + starting_angle))) * size_divider;
+ divider = Geom::Path(line_start);
divider.appendNew<Geom::LineSegment>((Geom::Point)origin);
divider.appendNew<Geom::LineSegment>(line_end);
- Piecewise<D2<SBasis> > output;
- Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle));
- if (fuse_paths) {
- Geom::PathVector path_out;
- Geom::PathVector tmp_path;
- PathVector const original_pathv = path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001);
- for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) {
- if (path_it->empty()) {
- continue;
- }
- bool end_open = false;
- if (path_it->closed()) {
- const Geom::Curve &closingline = path_it->back_closed();
- if (!are_near(closingline.initialPoint(), closingline.finalPoint())) {
- end_open = true;
- }
- }
- Geom::Path original = (Geom::Path)(*path_it);
- if (end_open && path_it->closed()) {
- original.close(false);
- original.appendNew<Geom::LineSegment>( original.initialPoint() );
- original.close(true);
- }
- tmp_path.push_back(original);
- setFusion(tmp_path, divider, size_divider);
- path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end());
- tmp_path.clear();
+ divider.close();
+ half_dir = unit_vector(Geom::middle_point(line_start,line_end) - (Geom::Point)origin);
+ if (method != RM_NORMAL) {
+ if (method != RM_KALEIDOSCOPE) {
+ path_out = doEffect_path_post(path_in);
+ } else {
+ path_out = pathv_to_linear_and_cubic_beziers(path_in);
+ }
+ if (num_copies == 0) {
+ return path_out;
}
- if (path_out.size()>0) {
- output = paths_to_pw(path_out);
+ Geom::PathVector triangle;
+ triangle.push_back(divider);
+ Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(triangle, path_out);
+ if (pig && !path_out.empty() && !triangle.empty()) {
+ path_out = pig->getIntersection();
+ }
+ path_out *= Geom::Translate(half_dir * gap);
+ if ( !split_items ) {
+ path_out *= Geom::Translate(half_dir * gap).inverse();
+ path_out = doEffect_path_post(path_out);
}
} else {
- for (int i = 0; i < num_copies; ++i) {
- Rotate rot(-rad_from_deg(rotation_angle * i));
- Affine t = pre * rot * Translate(origin);
- output.concat(pwd2_in * t);
+ path_out = doEffect_path_post(path_in);
+ }
+ return pathv_to_linear_and_cubic_beziers(path_out);
+}
+
+Geom::PathVector
+LPECopyRotate::doEffect_path_post (Geom::PathVector const & path_in)
+{
+ if ((split_items || num_copies == 1) && method == RM_NORMAL) {
+ if (split_items) {
+ Geom::PathVector path_out = pathv_to_linear_and_cubic_beziers(path_in);
+ Geom::Affine m = Geom::Translate(-origin) * Geom::Rotate(-(Geom::rad_from_deg(starting_angle)));
+ Geom::Affine t = m * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
+ return path_out * t;
+ }
+ return path_in;
+ }
+
+ Geom::Affine pre = Geom::Translate(-origin) * Geom::Rotate(-Geom::rad_from_deg(starting_angle));
+ Geom::PathVector original_pathv = pathv_to_linear_and_cubic_beziers(path_in);
+ Geom::PathVector output_pv;
+ Geom::PathVector output;
+ for (int i = 0; i < num_copies; ++i) {
+ Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * i));
+ Geom::Affine r = Geom::identity();
+ if( i%2 != 0 && mirror_copies) {
+ r *= Geom::Rotate(Geom::Angle(half_dir)).inverse();
+ r *= Geom::Scale(1, -1);
+ r *= Geom::Rotate(Geom::Angle(half_dir));
+ }
+ Geom::Affine t = pre * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
+ if(mirror_copies && i%2 != 0) {
+ t = pre * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)).inverse() * Geom::Translate(origin);
+ }
+ if (method != RM_NORMAL) {
+ Geom::PathVector join_pv = original_pathv * t;
+ join_pv *= Geom::Translate(half_dir * rot * gap);
+ Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(output_pv, join_pv);
+ if (pig) {
+ if (!output_pv.empty()) {
+ output_pv = pig->getUnion();
+ } else {
+ output_pv = join_pv;
+ }
+ }
+ } else {
+ t = pre * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
+ if(mirror_copies && i%2 != 0) {
+ t = pre * Geom::Rotate(Geom::rad_from_deg(-starting_angle-rotation_angle)) * r * rot * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
+ }
+ output_pv = path_in * t;
+ output.insert(output.end(), output_pv.begin(), output_pv.end());
}
}
+ if (method != RM_NORMAL) {
+ output = output_pv;
+ }
return output;
}
@@ -408,7 +698,7 @@ LPECopyRotate::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geo
Geom::Path hp;
hp.start(start_pos);
hp.appendNew<Geom::LineSegment>((Geom::Point)origin);
- hp.appendNew<Geom::LineSegment>(origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle);
+ hp.appendNew<Geom::LineSegment>(origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * Geom::distance(origin,starting_point));
Geom::PathVector pathv;
pathv.push_back(hp);
hp_vec.push_back(pathv);
@@ -422,84 +712,23 @@ LPECopyRotate::resetDefaults(SPItem const* item)
}
void
-LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
-{
- {
- KnotHolderEntity *e = new CR::KnotHolderEntityStartingAngle(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
- _("Adjust the starting angle"));
- knotholder->add(e);
- }
- {
- KnotHolderEntity *e = new CR::KnotHolderEntityRotationAngle(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
- _("Adjust the rotation angle"));
- knotholder->add(e);
- }
-};
-
-namespace CR {
-
-using namespace Geom;
-
-void
-KnotHolderEntityStartingAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
+LPECopyRotate::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
{
- LPECopyRotate* lpe = dynamic_cast<LPECopyRotate *>(_effect);
-
- Geom::Point const s = snap_knot_position(p, state);
-
- // I first suspected the minus sign to be a bug in 2geom but it is
- // likely due to SVG's choice of coordinate system orientation (max)
- lpe->starting_angle.param_set_value(deg_from_rad(-angle_between(lpe->dir, s - lpe->origin)));
- if (state & GDK_SHIFT_MASK) {
- lpe->dist_angle_handle = L2(lpe->B - lpe->A);
- } else {
- lpe->dist_angle_handle = L2(p - lpe->origin);
- }
-
- // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
- sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
+ processObjects(LPE_VISIBILITY);
}
-void
-KnotHolderEntityRotationAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
+void
+LPECopyRotate::doOnRemove (SPLPEItem const* /*lpeitem*/)
{
- LPECopyRotate* lpe = dynamic_cast<LPECopyRotate *>(_effect);
-
- Geom::Point const s = snap_knot_position(p, state);
-
- // I first suspected the minus sign to be a bug in 2geom but it is
- // likely due to SVG's choice of coordinate system orientation (max)
- lpe->rotation_angle.param_set_value(deg_from_rad(-angle_between(lpe->dir, s - lpe->origin)) - lpe->starting_angle);
- if (state & GDK_SHIFT_MASK) {
- lpe->dist_angle_handle = L2(lpe->B - lpe->A);
- } else {
- lpe->dist_angle_handle = L2(p - lpe->origin);
+ //set "keep paths" hook on sp-lpe-item.cpp
+ if (keep_paths) {
+ processObjects(LPE_TO_OBJECTS);
+ items.clear();
+ return;
}
-
- // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
- sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
+ processObjects(LPE_ERASE);
}
-Geom::Point
-KnotHolderEntityStartingAngle::knot_get() const
-{
- LPECopyRotate const *lpe = dynamic_cast<LPECopyRotate const*>(_effect);
- return lpe->start_pos;
-}
-
-Geom::Point
-KnotHolderEntityRotationAngle::knot_get() const
-{
- LPECopyRotate const *lpe = dynamic_cast<LPECopyRotate const*>(_effect);
- return lpe->rot_pos;
-}
-
-} // namespace CR
-
-/* ######################## */
-
} //namespace LivePathEffect
} /* namespace Inkscape */
diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h
index 87af867df..a0a3d4dc1 100644
--- a/src/live_effects/lpe-copy_rotate.h
+++ b/src/live_effects/lpe-copy_rotate.h
@@ -15,50 +15,68 @@
*/
#include "live_effects/effect.h"
+#include "live_effects/parameter/enum.h"
+#include "live_effects/parameter/parameter.h"
+#include "live_effects/parameter/text.h"
#include "live_effects/parameter/point.h"
#include "live_effects/lpegroupbbox.h"
namespace Inkscape {
namespace LivePathEffect {
-namespace CR {
-// we need a separate namespace to avoid clashes with LPEPerpBisector
-class KnotHolderEntityStartingAngle;
-class KnotHolderEntityRotationAngle;
-}
+enum RotateMethod {
+ RM_NORMAL,
+ RM_KALEIDOSCOPE,
+ RM_FUSE,
+ RM_END
+};
class LPECopyRotate : public Effect, GroupBBoxEffect {
public:
LPECopyRotate(LivePathEffectObject *lpeobject);
virtual ~LPECopyRotate();
virtual void doOnApply (SPLPEItem const* lpeitem);
- virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
+ virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in);
+ Geom::PathVector doEffect_path_post (Geom::PathVector const & path_in);
virtual void doBeforeEffect (SPLPEItem const* lpeitem);
+ virtual void doAfterEffect (SPLPEItem const* lpeitem);
virtual void setFusion(Geom::PathVector &path_in, Geom::Path divider, double sizeDivider);
virtual void split(Geom::PathVector &path_in, Geom::Path const &divider);
virtual void resetDefaults(SPItem const* item);
virtual void transform_multiply(Geom::Affine const& postmul, bool set);
- /* the knotholder entity classes must be declared friends */
- friend class CR::KnotHolderEntityStartingAngle;
- friend class CR::KnotHolderEntityRotationAngle;
- void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
-
+ virtual void doOnRemove (SPLPEItem const* /*lpeitem*/);
+ virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/);
+ virtual Gtk::Widget * newWidget();
+ void toItem(Geom::Affine transform, size_t i, bool reset);
+ void cloneD(SPObject *orig, SPObject *dest, Geom::Affine transform, bool root, bool reset);
+ void resetStyles();
protected:
virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
private:
+ EnumParam<RotateMethod> method;
PointParam origin;
+ PointParam starting_point;
ScalarParam starting_angle;
ScalarParam rotation_angle;
ScalarParam num_copies;
+ ScalarParam gap;
BoolParam copies_to_360;
- BoolParam fuse_paths;
+ BoolParam mirror_copies;
+ BoolParam split_items;
Geom::Point A;
Geom::Point B;
Geom::Point dir;
+ Geom::Point half_dir;
Geom::Point start_pos;
- Geom::Point rot_pos;
+ Geom::Point previous_origin;
+ Geom::Point previous_start_point;
double dist_angle_handle;
+ double size_divider;
+ Geom::Path divider;
+ double previous_num_copies;
+ bool reset;
+ SPObject * container;
LPECopyRotate(const LPECopyRotate&);
LPECopyRotate& operator=(const LPECopyRotate&);
};
diff --git a/src/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp
index 609447f26..f8d2e56ca 100644
--- a/src/live_effects/lpe-curvestitch.cpp
+++ b/src/live_effects/lpe-curvestitch.cpp
@@ -13,23 +13,16 @@
*/
#include "ui/widget/scalar.h"
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-curvestitch.h"
-#include "sp-item.h"
#include "sp-path.h"
#include "svg/svg.h"
#include "xml/repr.h"
-#include <2geom/path.h>
-#include <2geom/piecewise.h>
-#include <2geom/sbasis.h>
-#include <2geom/sbasis-geometric.h>
#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/affine.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -47,20 +40,21 @@ LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) :
prop_scale(_("Scale _width:"), _("Scale the width of the stitch path"), "prop_scale", &wr, this, 1),
scale_y_rel(_("Scale _width relative to length"), _("Scale the width of the stitch path relative to its length"), "scale_y_rel", &wr, this, false)
{
- registerParameter( dynamic_cast<Parameter *>(&nrofpaths) );
- registerParameter( dynamic_cast<Parameter *>(&startpoint_edge_variation) );
- registerParameter( dynamic_cast<Parameter *>(&startpoint_spacing_variation) );
- registerParameter( dynamic_cast<Parameter *>(&endpoint_edge_variation) );
- registerParameter( dynamic_cast<Parameter *>(&endpoint_spacing_variation) );
- registerParameter( dynamic_cast<Parameter *>(&strokepath) );
- registerParameter( dynamic_cast<Parameter *>(&prop_scale) );
- registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) );
+ registerParameter(&nrofpaths);
+ registerParameter(&startpoint_edge_variation);
+ registerParameter(&startpoint_spacing_variation);
+ registerParameter(&endpoint_edge_variation);
+ registerParameter(&endpoint_spacing_variation);
+ registerParameter(&strokepath );
+ registerParameter(&prop_scale);
+ registerParameter(&scale_y_rel);
nrofpaths.param_make_integer();
nrofpaths.param_set_range(2, Geom::infinity());
prop_scale.param_set_digits(3);
prop_scale.param_set_increments(0.01, 0.10);
+ transformed = false;
}
LPECurveStitch::~LPECurveStitch()
@@ -113,8 +107,9 @@ LPECurveStitch::doEffect_path (Geom::PathVector const & path_in)
if (!Geom::are_near(start,end)) {
gdouble scaling_y = 1.0;
- if (scale_y_rel.get_value()) {
+ if (scale_y_rel.get_value() || transformed) {
scaling_y = (L2(end-start)/scaling)*prop_scale;
+ transformed = false;
} else {
scaling_y = prop_scale;
}
@@ -200,12 +195,8 @@ LPECurveStitch::transform_multiply(Geom::Affine const& postmul, bool set)
if (postmul.isTranslation()) {
strokepath.param_transform_multiply(postmul, set);
} else if (!scale_y_rel.get_value()) {
- // this basically means that for this transformation, the result should be the same as normal scaling the result path
- // don't know how to do this yet.
-// Geom::Affine new_postmul;
- //new_postmul.setIdentity();
-// new_postmul.setTranslation(postmul.translation());
-// Effect::transform_multiply(new_postmul, set);
+ transformed = true;
+ strokepath.param_transform_multiply(postmul, set);
}
}
diff --git a/src/live_effects/lpe-curvestitch.h b/src/live_effects/lpe-curvestitch.h
index c6ea66f6c..0a48046e0 100644
--- a/src/live_effects/lpe-curvestitch.h
+++ b/src/live_effects/lpe-curvestitch.h
@@ -43,6 +43,7 @@ private:
RandomParam endpoint_spacing_variation;
ScalarParam prop_scale;
BoolParam scale_y_rel;
+ bool transformed;
LPECurveStitch(const LPECurveStitch&);
LPECurveStitch& operator=(const LPECurveStitch&);
diff --git a/src/live_effects/lpe-dynastroke.cpp b/src/live_effects/lpe-dynastroke.cpp
index aeecd5d5c..33e754a8a 100644
--- a/src/live_effects/lpe-dynastroke.cpp
+++ b/src/live_effects/lpe-dynastroke.cpp
@@ -14,14 +14,10 @@
#include "display/curve.h"
//# include <libnr/n-art-bpath.h>
-#include <2geom/path.h>
-#include <2geom/sbasis.h>
-#include <2geom/sbasis-geometric.h>
#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
#include <2geom/sbasis-math.h>
-#include <2geom/piecewise.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -59,17 +55,17 @@ LPEDynastroke::LPEDynastroke(LivePathEffectObject *lpeobject) :
capping(_("Capping:"), _("left capping"), "capping", &wr, this, "M 100,5 C 50,5 0,0 0,0 0,0 50,-5 100,-5")
{
- registerParameter( dynamic_cast<Parameter *>(& method) );
- registerParameter( dynamic_cast<Parameter *>(& width) );
- registerParameter( dynamic_cast<Parameter *>(& roundness) );
- registerParameter( dynamic_cast<Parameter *>(& angle) );
- //registerParameter( dynamic_cast<Parameter *>(& modulo_pi) );
- registerParameter( dynamic_cast<Parameter *>(& start_cap) );
- registerParameter( dynamic_cast<Parameter *>(& growfor) );
- registerParameter( dynamic_cast<Parameter *>(& end_cap) );
- registerParameter( dynamic_cast<Parameter *>(& fadefor) );
- registerParameter( dynamic_cast<Parameter *>(& round_ends) );
- registerParameter( dynamic_cast<Parameter *>(& capping) );
+ registerParameter(&method);
+ registerParameter(&width);
+ registerParameter(&roundness);
+ registerParameter(&angle);
+ //registerParameter(&modulo_pi) );
+ registerParameter(&start_cap);
+ registerParameter(&growfor);
+ registerParameter(&end_cap);
+ registerParameter(&fadefor);
+ registerParameter(&round_ends);
+ registerParameter(&capping);
width.param_set_range(0, Geom::infinity());
roundness.param_set_range(0.01, 1);
diff --git a/src/live_effects/lpe-ellipse_5pts.cpp b/src/live_effects/lpe-ellipse_5pts.cpp
index 4c953bcda..28e7058d7 100644
--- a/src/live_effects/lpe-ellipse_5pts.cpp
+++ b/src/live_effects/lpe-ellipse_5pts.cpp
@@ -12,16 +12,14 @@
*/
#include "live_effects/lpe-ellipse_5pts.h"
-
-// You might need to include other 2geom files. You can add them here:
-#include <glibmm/i18n.h>
-#include <2geom/path.h>
#include <2geom/circle.h>
#include <2geom/ellipse.h>
#include <2geom/path-sink.h>
#include "inkscape.h"
#include "desktop.h"
#include "message-stack.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -171,7 +169,7 @@ LPEEllipse5Pts::doEffect_path (Geom::PathVector const & path_in)
// figure out if we have a slice, guarding against rounding errors
- Path p(Geom::Point(cos(0), sin(0)));
+ Geom::Path p(Geom::Point(cos(0), sin(0)));
double end = 2 * M_PI;
for (s = 0; s < end; s += M_PI_2) {
diff --git a/src/live_effects/lpe-embrodery-stitch-ordering.cpp b/src/live_effects/lpe-embrodery-stitch-ordering.cpp
index ac01054a9..b631065a8 100644
--- a/src/live_effects/lpe-embrodery-stitch-ordering.cpp
+++ b/src/live_effects/lpe-embrodery-stitch-ordering.cpp
@@ -38,38 +38,38 @@ using namespace Geom;
template< typename T > void delete_and_clear(std::vector<T> &vector)
{
- for( typename std::vector<T>::iterator it=vector.begin(); it!=vector.end(); ++it )
- {
- delete *it;
- }
- vector.clear();
+ for (typename std::vector<T>::iterator it = vector.begin(); it != vector.end(); ++it) {
+ delete *it;
+ }
+ vector.clear();
}
// Assert that there are no duplicates in a vector
template< typename T > void assert_unique(std::vector<T> &vector)
{
- typename std::vector<T> copy = vector;
- std::sort ( copy.begin(), copy.end());
- assert( std::unique ( copy.begin(), copy.end()) == copy.end() );
+ typename std::vector<T> copy = vector;
+ std::sort(copy.begin(), copy.end());
+ assert(std::unique(copy.begin(), copy.end()) == copy.end());
}
// remove element(s) by value
template< typename T > void remove_by_value(std::vector<T> *vector, const T &value)
{
- vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end());
+ vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end());
}
// fill a vector with increasing elements (similar to C++11 iota)
+// iota is included in some C++ libraries, not in other (it is always included for C++11)
+// To avoid issues, use our own name (not iota)
template<class OutputIterator, class Counter>
-void iota(OutputIterator begin, OutputIterator end, Counter counter)
+void fill_increasing(OutputIterator begin, OutputIterator end, Counter counter)
{
- while( begin!=end )
- {
- *begin++ = counter++;
- }
+ while (begin != end) {
+ *begin++ = counter++;
+ }
}
// check if an iteratable sequence contains an element
@@ -77,15 +77,13 @@ void iota(OutputIterator begin, OutputIterator end, Counter counter)
template<class InputIterator, class Element>
bool contains(InputIterator begin, InputIterator end, const Element &elem)
{
- while( begin!=end )
- {
- if( *begin == elem )
- {
- return true;
- }
- ++begin;
- }
- return false;
+ while (begin != end) {
+ if (*begin == elem) {
+ return true;
+ }
+ ++begin;
+ }
+ return false;
}
// Check if a vector contains an element
@@ -93,7 +91,7 @@ bool contains(InputIterator begin, InputIterator end, const Element &elem)
template<class Element>
bool contains(std::vector<Element> const &vector, const Element &elem)
{
- return contains( vector.begin(), vector.end(), elem );
+ return contains(vector.begin(), vector.end(), elem);
}
// ==================== Multi-dimensional iterator functions ====================
@@ -118,131 +116,117 @@ bool contains(std::vector<Element> const &vector, const Element &elem)
// Initialize a vector of iterators
template<class Iterator>
-void triangleit_begin(std::vector<Iterator> &iterators, Iterator const &begin, Iterator const &end, size_t n )
+void triangleit_begin(std::vector<Iterator> &iterators, Iterator const &begin, Iterator const &end, size_t n)
{
- iterators.clear();
- // limit number of dimensions to number of elements
- size_t n1=end-begin;
- n = std::min(n, n1);
- if( n )
- {
- iterators.push_back( begin );
- for( int i=1; i<n; i++ )
- {
- iterators.push_back( iterators.back()+1 );
- }
- }
+ iterators.clear();
+ // limit number of dimensions to number of elements
+ size_t n1 = end - begin;
+ n = std::min(n, n1);
+ if (n) {
+ iterators.push_back(begin);
+ for (int i = 1; i < n; i++) {
+ iterators.push_back(iterators.back() + 1);
+ }
+ }
}
// Increment a vector of iterators
template<class Iterator>
-void triangleit_incr(std::vector<Iterator> &iterators, Iterator const &end )
+void triangleit_incr(std::vector<Iterator> &iterators, Iterator const &end)
{
- size_t n=iterators.size();
-
- for( int i=0; i<n; i++ )
- {
- iterators[n-1-i]++;
- // Each dimension ends at end-i, so that there are elements left for the i higher dimensions
- if( iterators[n-1-i] != end-i )
- {
- // Assign increasing numbers to the higher dimension
- for( int j=n-i; j<n; j++ )
- {
- iterators[j] = iterators[j-1]+1;
- }
- return;
- }
- }
+ size_t n = iterators.size();
+
+ for (int i = 0; i < n; i++) {
+ iterators[n - 1 - i]++;
+ // Each dimension ends at end-i, so that there are elements left for the i higher dimensions
+ if (iterators[n - 1 - i] != end - i) {
+ // Assign increasing numbers to the higher dimension
+ for (int j = n - i; j < n; j++) {
+ iterators[j] = iterators[j - 1] + 1;
+ }
+ return;
+ }
+ }
}
// Check if a vector of iterators is at the end
template<class Iterator>
-bool triangleit_test(std::vector<Iterator> &iterators, Iterator const &end )
+bool triangleit_test(std::vector<Iterator> &iterators, Iterator const &end)
{
- if( iterators.empty() )
- {
- return false;
- }
- else
- {
- return iterators.back()!=end;
- }
+ if (iterators.empty()) {
+ return false;
+ } else {
+ return iterators.back() != end;
+ }
}
// ==================== Trivial Ordering Functions ====================
// Sub-path reordering: do nothing - keep original order
-void OrderingOriginal( std::vector<OrderingInfo> & infos )
+void OrderingOriginal(std::vector<OrderingInfo> &infos)
{
}
// Sub-path reordering: reverse every other sub path
-void OrderingZigZag( std::vector<OrderingInfo> & infos, bool revfirst )
+void OrderingZigZag(std::vector<OrderingInfo> &infos, bool revfirst)
{
- for( std::vector<OrderingInfo>::iterator it=infos.begin(); it!=infos.end(); ++it )
- {
- it->reverse = (it->index & 1) == (revfirst ? 0 : 1);
- }
+ for (std::vector<OrderingInfo>::iterator it = infos.begin(); it != infos.end(); ++it) {
+ it->reverse = (it->index & 1) == (revfirst ? 0 : 1);
+ }
}
// Sub-path reordering: continue with the neartest start or end point of yet unused sub paths
-void OrderingClosest( std::vector<OrderingInfo> & infos, bool revfirst )
+void OrderingClosest(std::vector<OrderingInfo> &infos, bool revfirst)
{
- std::vector<OrderingInfo> result;
- result.reserve( infos.size() );
-
- result.push_back( infos[0] );
- result.back().reverse = revfirst;
- Point p=result.back().GetEndRev();
-
- infos[0].used = true;
-
-
- for(unsigned int iRnd=1; iRnd<infos.size(); iRnd++ )
- {
- // find closest point to p
- unsigned iBest=0;
- bool revBest=false;
- Coord distBest=infinity();
-
- for( std::vector<OrderingInfo>::iterator it=infos.begin(); it!=infos.end(); ++it )
- {
- it->index = it - infos.begin();
- it->reverse = (it->index & 1)!=0;
-
- if( !it->used )
- {
- Coord dist = distance(p, it->GetBegOrig() );
- if( dist<distBest )
- {
- distBest = dist;
- iBest = it-infos.begin();
- revBest = false;
- }
-
- dist = distance(p, it->GetEndOrig() );
- if( dist<distBest )
- {
- distBest = dist;
- iBest = it-infos.begin();
- revBest = true;
- }
- }
- }
-
- result.push_back( infos[iBest] );
- result.back().reverse = revBest;
- p = result.back().GetEndRev();
- infos[iBest].used = true;
- }
-
- infos = result;
+ std::vector<OrderingInfo> result;
+ result.reserve(infos.size());
+
+ result.push_back(infos[0]);
+ result.back().reverse = revfirst;
+ Point p = result.back().GetEndRev();
+
+ infos[0].used = true;
+
+
+ for (unsigned int iRnd = 1; iRnd < infos.size(); iRnd++) {
+ // find closest point to p
+ unsigned iBest = 0;
+ bool revBest = false;
+ Coord distBest = infinity();
+
+ for (std::vector<OrderingInfo>::iterator it = infos.begin(); it != infos.end(); ++it) {
+ it->index = it - infos.begin();
+ it->reverse = (it->index & 1) != 0;
+
+ if (!it->used) {
+ Coord dist = distance(p, it->GetBegOrig());
+ if (dist < distBest) {
+ distBest = dist;
+ iBest = it - infos.begin();
+ revBest = false;
+ }
+
+ dist = distance(p, it->GetEndOrig());
+ if (dist < distBest) {
+ distBest = dist;
+ iBest = it - infos.begin();
+ revBest = true;
+ }
+ }
+ }
+
+ result.push_back(infos[iBest]);
+ result.back().reverse = revBest;
+ p = result.back().GetEndRev();
+ infos[iBest].used = true;
+ }
+
+ infos = result;
}
// ==================== Traveling Salesman k-opt Ordering Function and Utilities ====================
@@ -265,623 +249,579 @@ void OrderingClosest( std::vector<OrderingInfo> & infos, bool revfirst )
// Find 2 nearest points to given point
-void OrderingPoint::FindNearest2( const std::vector<OrderingInfoEx*> & infos )
+void OrderingPoint::FindNearest2(const std::vector<OrderingInfoEx *> &infos)
{
- // This implementation is not terribly elegant (unSTLish).
- // But for the first 2 elements using e.g. partial_sort is not simpler.
-
- Coord dist0 = infinity();
- Coord dist1 = infinity();
- nearest[0] = 0;
- nearest[1] = 0;
-
- for( std::vector<OrderingInfoEx*>::const_iterator it=infos.begin(); it!=infos.end(); ++it )
- {
- Coord dist = distance( point, (*it)->beg.point );
- if( dist<dist1 )
- {
- if( &(*it)->beg != this && &(*it)->end != this )
- {
- if( dist<dist0 )
- {
- nearest[1] = nearest[0];
- nearest[0] = &(*it)->beg;
- dist1 = dist0;
- dist0 = dist;
- }
- else
- {
- nearest[1] = &(*it)->beg;
- dist1 = dist;
- }
- }
- }
-
- dist = distance( point, (*it)->end.point );
- if( dist<dist1 )
- {
- if( &(*it)->beg != this && &(*it)->end != this )
- {
- if( dist<dist0 )
- {
- nearest[1] = nearest[0];
- nearest[0] = &(*it)->end;
- dist1 = dist0;
- dist0 = dist;
- }
- else
- {
- nearest[1] = &(*it)->end;
- dist1 = dist;
- }
- }
- }
- }
+ // This implementation is not terribly elegant (unSTLish).
+ // But for the first 2 elements using e.g. partial_sort is not simpler.
+
+ Coord dist0 = infinity();
+ Coord dist1 = infinity();
+ nearest[0] = 0;
+ nearest[1] = 0;
+
+ for (std::vector<OrderingInfoEx *>::const_iterator it = infos.begin(); it != infos.end(); ++it) {
+ Coord dist = distance(point, (*it)->beg.point);
+ if (dist < dist1) {
+ if (&(*it)->beg != this && &(*it)->end != this) {
+ if (dist < dist0) {
+ nearest[1] = nearest[0];
+ nearest[0] = &(*it)->beg;
+ dist1 = dist0;
+ dist0 = dist;
+ } else {
+ nearest[1] = &(*it)->beg;
+ dist1 = dist;
+ }
+ }
+ }
+
+ dist = distance(point, (*it)->end.point);
+ if (dist < dist1) {
+ if (&(*it)->beg != this && &(*it)->end != this) {
+ if (dist < dist0) {
+ nearest[1] = nearest[0];
+ nearest[0] = &(*it)->end;
+ dist1 = dist0;
+ dist0 = dist;
+ } else {
+ nearest[1] = &(*it)->end;
+ dist1 = dist;
+ }
+ }
+ }
+ }
}
// Check if "this" is among the nearest of its nearest
-void OrderingPoint::EnforceMutual( void )
+void OrderingPoint::EnforceMutual(void)
{
- if( nearest[0] && !(this==nearest[0]->nearest[0] || this==nearest[0]->nearest[1]) )
- {
- nearest[0] = 0;
- }
-
- if( nearest[1] && !(this==nearest[1]->nearest[0] || this==nearest[1]->nearest[1]) )
- {
- nearest[1] = 0;
- }
-
- if( nearest[1] && !nearest[0] )
- {
- nearest[0] = nearest[1];
- nearest[1] = 0;
- }
+ if (nearest[0] && !(this == nearest[0]->nearest[0] || this == nearest[0]->nearest[1])) {
+ nearest[0] = 0;
+ }
+
+ if (nearest[1] && !(this == nearest[1]->nearest[0] || this == nearest[1]->nearest[1])) {
+ nearest[1] = 0;
+ }
+
+ if (nearest[1] && !nearest[0]) {
+ nearest[0] = nearest[1];
+ nearest[1] = 0;
+ }
}
// Check if the subpath indices of this and other are the same, otherwise zero both nearest
-void OrderingPoint::EnforceSymmetric( const OrderingPoint &other )
+void OrderingPoint::EnforceSymmetric(const OrderingPoint &other)
{
- if( nearest[0] && !(
- ( other.nearest[0] && nearest[0]->infoex == other.nearest[0]->infoex ) ||
- ( other.nearest[1] && nearest[0]->infoex == other.nearest[1]->infoex )
- ) )
- {
- nearest[0] = 0;
- }
-
- if( nearest[1] && !(
- ( other.nearest[0] && nearest[1]->infoex == other.nearest[0]->infoex ) ||
- ( other.nearest[1] && nearest[1]->infoex == other.nearest[1]->infoex )
- ) )
- {
- nearest[1] = 0;
- }
-
- if( nearest[1] && !nearest[0] )
- {
- nearest[0] = nearest[1];
- nearest[1] = 0;
- }
+ if (nearest[0] && !(
+ (other.nearest[0] && nearest[0]->infoex == other.nearest[0]->infoex) ||
+ (other.nearest[1] && nearest[0]->infoex == other.nearest[1]->infoex)
+ )) {
+ nearest[0] = 0;
+ }
+
+ if (nearest[1] && !(
+ (other.nearest[0] && nearest[1]->infoex == other.nearest[0]->infoex) ||
+ (other.nearest[1] && nearest[1]->infoex == other.nearest[1]->infoex)
+ )) {
+ nearest[1] = 0;
+ }
+
+ if (nearest[1] && !nearest[0]) {
+ nearest[0] = nearest[1];
+ nearest[1] = 0;
+ }
}
-void OrderingPoint::Dump( void )
+void OrderingPoint::Dump(void)
{
- Coord dist0 = nearest[0] ? distance( point, nearest[0]->point ) : -1.0;
- Coord dist1 = nearest[1] ? distance( point, nearest[1]->point ) : -1.0;
- int idx0 = nearest[0] ? nearest[0]->infoex->idx : -1;
- int idx1 = nearest[1] ? nearest[1]->infoex->idx : -1;
- DebugTrace2(( "I=%d X=%.5lf Y=%.5lf d1=%.3lf d2=%.3lf i1=%d i2=%d", infoex->idx, point.x(), 297.0-point.y(), dist0, dist1, idx0, idx1 ));
+ Coord dist0 = nearest[0] ? distance(point, nearest[0]->point) : -1.0;
+ Coord dist1 = nearest[1] ? distance(point, nearest[1]->point) : -1.0;
+ int idx0 = nearest[0] ? nearest[0]->infoex->idx : -1;
+ int idx1 = nearest[1] ? nearest[1]->infoex->idx : -1;
+ DebugTrace2(("I=%d X=%.5lf Y=%.5lf d1=%.3lf d2=%.3lf i1=%d i2=%d", infoex->idx, point.x(), 297.0 - point.y(), dist0, dist1, idx0, idx1));
}
// If this element can be grouped (has neighbours) but is not yet grouped, create a new group
-void OrderingInfoEx::MakeGroup( std::vector<OrderingInfoEx*> & infos, std::vector<OrderingGroup*> *groups )
+void OrderingInfoEx::MakeGroup(std::vector<OrderingInfoEx *> &infos, std::vector<OrderingGroup *> *groups)
{
- if( grouped || !beg.HasNearest() || !end.HasNearest() ) { return; }
+ if (grouped || !beg.HasNearest() || !end.HasNearest()) {
+ return;
+ }
- groups->push_back( new OrderingGroup( groups->size() ) );
+ groups->push_back(new OrderingGroup(groups->size()));
- // Add neighbors recursively
- AddToGroup( infos, groups->back() );
+ // Add neighbors recursively
+ AddToGroup(infos, groups->back());
}
// Add this and all connected elements to the group
-void OrderingInfoEx::AddToGroup( std::vector<OrderingInfoEx*> & infos, OrderingGroup *group )
+void OrderingInfoEx::AddToGroup(std::vector<OrderingInfoEx *> &infos, OrderingGroup *group)
{
- if( grouped || !beg.HasNearest() || !end.HasNearest() ) { return; }
-
- group->items.push_back( this );
- grouped = true;
- // Note: beg and end neighbors have been checked to be symmetric
- if( beg.nearest[0] ) beg.nearest[0]->infoex->AddToGroup( infos, group );
- if( beg.nearest[1] ) beg.nearest[1]->infoex->AddToGroup( infos, group );
- if( end.nearest[0] ) end.nearest[0]->infoex->AddToGroup( infos, group );
- if( end.nearest[1] ) end.nearest[1]->infoex->AddToGroup( infos, group );
+ if (grouped || !beg.HasNearest() || !end.HasNearest()) {
+ return;
+ }
+
+ group->items.push_back(this);
+ grouped = true;
+ // Note: beg and end neighbors have been checked to be symmetric
+ if (beg.nearest[0]) {
+ beg.nearest[0]->infoex->AddToGroup(infos, group);
+ }
+ if (beg.nearest[1]) {
+ beg.nearest[1]->infoex->AddToGroup(infos, group);
+ }
+ if (end.nearest[0]) {
+ end.nearest[0]->infoex->AddToGroup(infos, group);
+ }
+ if (end.nearest[1]) {
+ end.nearest[1]->infoex->AddToGroup(infos, group);
+ }
}
// Constructor
-OrderingGroupNeighbor::OrderingGroupNeighbor( OrderingGroupPoint *me, OrderingGroupPoint *other ) :
- point( other ),
- distance( Geom::distance( me->point, other->point) )
+OrderingGroupNeighbor::OrderingGroupNeighbor(OrderingGroupPoint *me, OrderingGroupPoint *other) :
+ point(other),
+ distance(Geom::distance(me->point, other->point))
{
}
// Comparison function for sorting by distance
-bool OrderingGroupNeighbor::Compare( const OrderingGroupNeighbor &a, const OrderingGroupNeighbor &b )
+bool OrderingGroupNeighbor::Compare(const OrderingGroupNeighbor &a, const OrderingGroupNeighbor &b)
{
- return a.distance < b.distance;
+ return a.distance < b.distance;
}
// Find the nearest unused neighbor point
-OrderingGroupNeighbor *OrderingGroupPoint::FindNearestUnused( void )
+OrderingGroupNeighbor *OrderingGroupPoint::FindNearestUnused(void)
{
- for( std::vector<OrderingGroupNeighbor>::iterator it=nearest.begin(); it!=nearest.end(); ++it )
- {
- if( !it->point->used )
- {
- DebugTrace1TSP(( "Nearest: group %d, size %d, point %d, nghb %d, xFrom %.4lf, yFrom %.4lf, xTo %.4lf, yTo %.4lf, dist %.4lf",
- it->point->group->index, it->point->group->items.size(), it->point->indexInGroup, it-nearest.begin(),
- point.x(), 297-point.y(),
- it->point->point.x(), 297-it->point->point.y(),
- it->distance ));
- return &*it;
- }
- }
-
- // it shouldn't happen that we can't find any point at all
- assert( 0 );
- return 0;
+ for (std::vector<OrderingGroupNeighbor>::iterator it = nearest.begin(); it != nearest.end(); ++it) {
+ if (!it->point->used) {
+ DebugTrace1TSP(("Nearest: group %d, size %d, point %d, nghb %d, xFrom %.4lf, yFrom %.4lf, xTo %.4lf, yTo %.4lf, dist %.4lf",
+ it->point->group->index, it->point->group->items.size(), it->point->indexInGroup, it - nearest.begin(),
+ point.x(), 297 - point.y(),
+ it->point->point.x(), 297 - it->point->point.y(),
+ it->distance));
+ return &*it;
+ }
+ }
+
+ // it shouldn't happen that we can't find any point at all
+ assert(0);
+ return 0;
}
// Return the other end in the group of the point
-OrderingGroupPoint *OrderingGroupPoint::GetOtherEndGroup( void )
+OrderingGroupPoint *OrderingGroupPoint::GetOtherEndGroup(void)
{
- return group->endpoints[ indexInGroup^1 ];
+ return group->endpoints[ indexInGroup ^ 1 ];
}
// Return the alternate point (if one exists), 0 otherwise
-OrderingGroupPoint *OrderingGroupPoint::GetAltPointGroup( void )
+OrderingGroupPoint *OrderingGroupPoint::GetAltPointGroup(void)
{
- if( group->nEndPoints<4 )
- {
- return 0;
- }
+ if (group->nEndPoints < 4) {
+ return 0;
+ }
- OrderingGroupPoint *alt = group->endpoints[ indexInGroup^2 ];
- return alt->used ? 0 : alt;
+ OrderingGroupPoint *alt = group->endpoints[ indexInGroup ^ 2 ];
+ return alt->used ? 0 : alt;
}
// Sets the rev flags in the group assuming that the group starts with this point
-void OrderingGroupPoint::SetRevInGroup( void )
+void OrderingGroupPoint::SetRevInGroup(void)
{
- // If this is not a front point, the item list needs to be reversed
- group->revItemList = !front;
+ // If this is not a front point, the item list needs to be reversed
+ group->revItemList = !front;
- // If this is not a begin point, the items need to be reversed
- group->revItems = !begin;
+ // If this is not a begin point, the items need to be reversed
+ group->revItems = !begin;
}
// Mark an end point as used and also mark the two other alternating points as used
// Returns the used point
-void OrderingGroupPoint::UsePoint( void )
+void OrderingGroupPoint::UsePoint(void)
{
- group->UsePoint( indexInGroup );
+ group->UsePoint(indexInGroup);
}
// Mark an end point as unused and possibly also mark the two other alternating points as unused
// Returns the used point
-void OrderingGroupPoint::UnusePoint( void )
+void OrderingGroupPoint::UnusePoint(void)
{
- group->UnusePoint( indexInGroup );
+ group->UnusePoint(indexInGroup);
}
// Return the other end in the connection
-OrderingGroupPoint *OrderingGroupPoint::GetOtherEndConnection( void )
+OrderingGroupPoint *OrderingGroupPoint::GetOtherEndConnection(void)
{
- assert( connection );
- assert( connection->points[ indexInConnection ] == this );
- assert( connection->points[ indexInConnection^1 ] );
+ assert(connection);
+ assert(connection->points[ indexInConnection ] == this);
+ assert(connection->points[ indexInConnection ^ 1 ]);
- return connection->points[ indexInConnection^1 ];
+ return connection->points[ indexInConnection ^ 1 ];
}
// Set the end points of a group from the items
-void OrderingGroup::SetEndpoints( void )
+void OrderingGroup::SetEndpoints(void)
{
- assert( items.size()>=1 );
-
- if( items.size()==1 )
- {
- // A simple line:
- //
- // b0-front--e1
-
- nEndPoints = 2;
- endpoints[0] = new OrderingGroupPoint( items.front()->beg.point, this, 0, true, true );
- endpoints[1] = new OrderingGroupPoint( items.front()->end.point, this, 1, false, true );
- }
- else
- {
- // If the number of elements is even, the group is
- // either from items.front().beg to items.back().beg
- // or from items.front().end to items.back().end:
- // Below: b=beg, e=end, numbers are end point indices
- //
- // b0-front--e b0-front--e2
- // | |
- // b---------e b---------e
- // | |
- // b---------e b---------e
- // | |
- // b1-back---e b1-back---e3
- //
- //
- // if the number of elements is odd, it is crossed:
- //
- // b0-front--e b--front--e2
- // | |
- // b---------e b---------e
- // | |
- // b--back---e1 b3-back---e
- //
- // TODO: this is not true with the following kind of pattern
- //
- // b--front--e
- // b---------e
- // b--------e
- // b--back--e
- //
- // Here only one connection is possible, from front.end to back.beg
- //
- // TODO: also this is not true if segment direction is alternating
- //
- // TOTO: => Just see where you end up from front().begin and front().end
- //
- // the numbering is such that either end points 0 and 1 are used or 2 and 3.
- int cross = items.size()&1 ? 2 : 0;
- nEndPoints = 4;
-
- endpoints[0 ] = new OrderingGroupPoint( items.front()->beg.point, this, 0, true, true );
- endpoints[1^cross] = new OrderingGroupPoint( items.back() ->beg.point, this, 1^cross, true, false );
- endpoints[2 ] = new OrderingGroupPoint( items.front()->end.point, this, 2, false, true );
- endpoints[3^cross] = new OrderingGroupPoint( items.back() ->end.point, this, 3^cross, false, false );
- }
+ assert(items.size() >= 1);
+
+ if (items.size() == 1) {
+ // A simple line:
+ //
+ // b0-front--e1
+
+ nEndPoints = 2;
+ endpoints[0] = new OrderingGroupPoint(items.front()->beg.point, this, 0, true, true);
+ endpoints[1] = new OrderingGroupPoint(items.front()->end.point, this, 1, false, true);
+ } else {
+ // If the number of elements is even, the group is
+ // either from items.front().beg to items.back().beg
+ // or from items.front().end to items.back().end:
+ // Below: b=beg, e=end, numbers are end point indices
+ //
+ // b0-front--e b0-front--e2
+ // | |
+ // b---------e b---------e
+ // | |
+ // b---------e b---------e
+ // | |
+ // b1-back---e b1-back---e3
+ //
+ //
+ // if the number of elements is odd, it is crossed:
+ //
+ // b0-front--e b--front--e2
+ // | |
+ // b---------e b---------e
+ // | |
+ // b--back---e1 b3-back---e
+ //
+ // TODO: this is not true with the following kind of pattern
+ //
+ // b--front--e
+ // b---------e
+ // b--------e
+ // b--back--e
+ //
+ // Here only one connection is possible, from front.end to back.beg
+ //
+ // TODO: also this is not true if segment direction is alternating
+ //
+ // TOTO: => Just see where you end up from front().begin and front().end
+ //
+ // the numbering is such that either end points 0 and 1 are used or 2 and 3.
+ int cross = items.size() & 1 ? 2 : 0;
+ nEndPoints = 4;
+
+ endpoints[0 ] = new OrderingGroupPoint(items.front()->beg.point, this, 0, true, true);
+ endpoints[1 ^ cross] = new OrderingGroupPoint(items.back() ->beg.point, this, 1 ^ cross, true, false);
+ endpoints[2 ] = new OrderingGroupPoint(items.front()->end.point, this, 2, false, true);
+ endpoints[3 ^ cross] = new OrderingGroupPoint(items.back() ->end.point, this, 3 ^ cross, false, false);
+ }
}
// Add all points from another group as neighbors
-void OrderingGroup::AddNeighbors( OrderingGroup *nghb )
+void OrderingGroup::AddNeighbors(OrderingGroup *nghb)
{
- for( int iThis=0; iThis<nEndPoints; iThis++ )
- {
- for( int iNghb=0; iNghb<nghb->nEndPoints; iNghb++ )
- {
- endpoints[iThis]->nearest.push_back( OrderingGroupNeighbor( endpoints[iThis], nghb->endpoints[iNghb] ) );
- }
- }
+ for (int iThis = 0; iThis < nEndPoints; iThis++) {
+ for (int iNghb = 0; iNghb < nghb->nEndPoints; iNghb++) {
+ endpoints[iThis]->nearest.push_back(OrderingGroupNeighbor(endpoints[iThis], nghb->endpoints[iNghb]));
+ }
+ }
}
// Mark an end point as used and also mark the two other alternating points as used
// Returns the used point
-OrderingGroupPoint *OrderingGroup::UsePoint( int index )
+OrderingGroupPoint *OrderingGroup::UsePoint(int index)
{
- assert( index<nEndPoints );
- assert( !endpoints[index]->used );
- endpoints[index]->used = true;
- if( nEndPoints==4 )
- {
- int offs = index<2 ? 2 : 0;
- endpoints[0+offs]->used = true;
- endpoints[1+offs]->used = true;
- }
-
- return endpoints[index];
+ assert(index < nEndPoints);
+ assert(!endpoints[index]->used);
+ endpoints[index]->used = true;
+ if (nEndPoints == 4) {
+ int offs = index < 2 ? 2 : 0;
+ endpoints[0 + offs]->used = true;
+ endpoints[1 + offs]->used = true;
+ }
+
+ return endpoints[index];
}
// Mark an end point as unused and possibly also mark the two other alternating points as unused
// Returns the used point
-void OrderingGroup::UnusePoint( int index )
+void OrderingGroup::UnusePoint(int index)
{
- assert( index<nEndPoints );
- assert( endpoints[index]->used );
- endpoints[index]->used = false;
-
- if( nEndPoints==4 && !endpoints[index^1]->used )
- {
- int offs = index<2 ? 2 : 0;
- endpoints[0+offs]->used = false;
- endpoints[1+offs]->used = false;
- }
+ assert(index < nEndPoints);
+ assert(endpoints[index]->used);
+ endpoints[index]->used = false;
+
+ if (nEndPoints == 4 && !endpoints[index ^ 1]->used) {
+ int offs = index < 2 ? 2 : 0;
+ endpoints[0 + offs]->used = false;
+ endpoints[1 + offs]->used = false;
+ }
}
// Add an end point
-void OrderingSegment::AddPoint( OrderingGroupPoint *point )
+void OrderingSegment::AddPoint(OrderingGroupPoint *point)
{
- assert( point );
- assert( nEndPoints<4 );
- endpoints[ nEndPoints++ ] = point;
-
- // If both ends of a group are added and the group has 4 points, add the other two as well
- if( nEndPoints==2 && endpoints[0]->group == endpoints[1]->group )
- {
- OrderingGroup *group = endpoints[0]->group;
- if( group->nEndPoints==4 )
- {
- for( int i=0; i<4; i++ )
- {
- endpoints[i] = group->endpoints[i];
- }
- nEndPoints = 4;
- }
- }
+ assert(point);
+ assert(nEndPoints < 4);
+ endpoints[ nEndPoints++ ] = point;
+
+ // If both ends of a group are added and the group has 4 points, add the other two as well
+ if (nEndPoints == 2 && endpoints[0]->group == endpoints[1]->group) {
+ OrderingGroup *group = endpoints[0]->group;
+ if (group->nEndPoints == 4) {
+ for (int i = 0; i < 4; i++) {
+ endpoints[i] = group->endpoints[i];
+ }
+ nEndPoints = 4;
+ }
+ }
}
// Get begin point (taking swap and end bit into account
-OrderingGroupPoint *OrderingSegment::GetBeginPoint( unsigned int iSwap, unsigned int iEnd )
+OrderingGroupPoint *OrderingSegment::GetBeginPoint(unsigned int iSwap, unsigned int iEnd)
{
- int iPoint = ( (iEnd>>endbit) & 1 ) + ( ( (iSwap>>swapbit) & 1 ) << 1 );
- assert( iPoint< nEndPoints );
- return endpoints[iPoint];
+ int iPoint = ((iEnd >> endbit) & 1) + (((iSwap >> swapbit) & 1) << 1);
+ assert(iPoint < nEndPoints);
+ return endpoints[iPoint];
}
// Get end point (taking swap and end bit into account
-OrderingGroupPoint *OrderingSegment::GetEndPoint( unsigned int iSwap, unsigned int iEnd )
+OrderingGroupPoint *OrderingSegment::GetEndPoint(unsigned int iSwap, unsigned int iEnd)
{
- int iPoint = ( ( (iEnd>>endbit) & 1 ) ^ 1 )+ ( ( (iSwap>>swapbit) & 1 ) << 1 );
- assert( iPoint< nEndPoints );
- return endpoints[iPoint];
+ int iPoint = (((iEnd >> endbit) & 1) ^ 1) + (((iSwap >> swapbit) & 1) << 1);
+ assert(iPoint < nEndPoints);
+ return endpoints[iPoint];
}
// Find the next unused point in list
-std::vector<OrderingGroupPoint*>::iterator FindUnusedAndUse( std::vector<OrderingGroupPoint*> *unusedPoints, std::vector<OrderingGroupPoint*>::iterator const from )
+std::vector<OrderingGroupPoint *>::iterator FindUnusedAndUse(std::vector<OrderingGroupPoint *> *unusedPoints, std::vector<OrderingGroupPoint *>::iterator const from)
{
- for( std::vector<OrderingGroupPoint*>::iterator it=from; it!=unusedPoints->end(); ++it )
- {
- if( !(*it)->used )
- {
- (*it)->UsePoint();
- return it;
- }
- }
- return unusedPoints->end();
+ for (std::vector<OrderingGroupPoint *>::iterator it = from; it != unusedPoints->end(); ++it) {
+ if (!(*it)->used) {
+ (*it)->UsePoint();
+ return it;
+ }
+ }
+ return unusedPoints->end();
}
// Find the shortest reconnect between the given points
-bool FindShortestReconnect( std::vector<OrderingSegment> &segments, std::vector<OrderingGroupConnection*> &connections, std::vector<OrderingGroupConnection*> &allconnections, OrderingGroupConnection **longestConnect, Coord *total, Coord olddist )
+bool FindShortestReconnect(std::vector<OrderingSegment> &segments, std::vector<OrderingGroupConnection *> &connections, std::vector<OrderingGroupConnection *> &allconnections, OrderingGroupConnection **longestConnect, Coord *total, Coord olddist)
{
- // Find the longest connection outside of the active set
- // The longest segment is then the longest of this longest outside segment and all inside segments
- OrderingGroupConnection *longestOutside = 0;
-
- if( contains( connections, *longestConnect ) )
- {
- // The longest connection is inside the active set, so we need to search for the longest outside
- Coord length=0.0;
- for( std::vector<OrderingGroupConnection*>::iterator it=allconnections.begin(); it!=allconnections.end(); it++ )
- {
- if( (*it)->Distance() > length )
- {
- if( !contains( connections, *it ) )
- {
- longestOutside = *it;
- length = (*it)->Distance();
- }
- }
- }
- }
- else
- {
- longestOutside = *longestConnect;
- }
-
- // length of longestConnect outside
- Coord longestOutsideLength = longestOutside ? longestOutside->Distance() : 0.0;
-
- // We measure length without the longest, so subtract the longest length from the old distance
- olddist -= (*longestConnect)->Distance();
-
- // Assign a swap bit and end bit to each active connection
- int nEndBits=0;
- int nSwapBits=0;
- for(std::vector<OrderingSegment>::iterator it=segments.begin(); it!=segments.end(); it++ )
- {
- it->endbit = nEndBits++;
- if( it->nEndPoints==4 )
- {
- it->swapbit = nSwapBits++;
- }
- else
- {
- // bit 32 should always be 0
- it->swapbit = 31;
- }
- }
-
- unsigned int swapMask = (1U<<nSwapBits)-1;
- unsigned int endMask = (1U<<nEndBits)-1;
-
- // Create a permutation vector
- std::vector<int> permutation( segments.size() );
- iota (permutation.begin(), permutation.end(), 0);
-
- // best improvement
- bool improved=false;
- Coord distBest=olddist;
- std::vector<int> permutationBest;
- unsigned int iSwapBest;
- unsigned int iEndBest;
- int nTrials=0;
-
- // Loop over the permutations
- do {
- // Loop over the swap bits
- unsigned int iSwap=0;
- do {
- // Loop over the end bits
- unsigned int iEnd=0;
- do {
- // Length of all active connections
- Coord lengthTotal=0;
- // Length of longest connection (active or inactive)
- Coord lengthLongest=longestOutsideLength;
-
- // Close the loop with the end point of the last segment
- OrderingGroupPoint *prevend = segments[permutation.back()].GetEndPoint( iSwap, iEnd );
- for( std::vector<int>::iterator it=permutation.begin(); it!=permutation.end(); it++ )
- {
- OrderingGroupPoint *thisbeg= segments[*it].GetBeginPoint( iSwap, iEnd );
- Coord length = Geom::distance( thisbeg->point, prevend->point );
- lengthTotal += length;
- if( length>lengthLongest )
- {
- lengthLongest = length;
- }
- prevend = segments[*it].GetEndPoint( iSwap, iEnd );
- }
- lengthTotal -= lengthLongest;
-
- // If there is an improvement, remember the best selection
- if( lengthTotal + 1e-6 < distBest )
- {
- improved = true;
- distBest = lengthTotal;
- permutationBest = permutation;
- iSwapBest = iSwap;
- iEndBest = iEnd;
-
- // Just debug printing
- OrderingGroupPoint *prevend = segments[permutation.back()].GetEndPoint( iSwap, iEnd );
- for( std::vector<int>::iterator it=permutation.begin(); it!=permutation.end(); it++ )
- {
- OrderingGroupPoint *thisbeg= segments[*it].GetBeginPoint( iSwap, iEnd );
- DebugTrace2TSP(( "IMP 0F=%d %d %.6lf", thisbeg->group->index, thisbeg->indexInGroup, Geom::distance( thisbeg->point, prevend->point ) ));
- DebugTrace2TSP(( "IMP 0T=%d %d %.6lf", prevend->group->index, prevend->indexInGroup, Geom::distance( thisbeg->point, prevend->point ) ));
- prevend = segments[*it].GetEndPoint( iSwap, iEnd );
- }
- }
-
- nTrials++;
-
- // bit 0 is always 0, because the first segment is kept fixed
- iEnd+=2;
- } while( iEnd&endMask );
- iSwap++;
- } while( iSwap&swapMask );
- // first segment is kept fixed
- } while( std::next_permutation(permutation.begin()+1, permutation.end()) );
-
- if( improved )
- {
- DebugTrace2TSP(( "Improvement %lf->%lf in %d", olddist, distBest, nTrials ));
- // change the connections
-
- for( std::vector<OrderingGroupConnection*>::iterator it=connections.begin(); it!=connections.end(); ++it )
- {
- DebugTrace2TSP(( "WAS 0F=%d %d %.6lf", (*it)->points[0]->group->index, (*it)->points[0]->indexInGroup, (*it)->Distance() ));
- DebugTrace2TSP(( "WAS 0T=%d %d %.6lf", (*it)->points[1]->group->index, (*it)->points[1]->indexInGroup, (*it)->Distance() ));
- }
- DebugTrace2TSP(( "OLDDIST %.6lf delta %.6lf", olddist, olddist-(*longestConnect)->Distance() ));
- DebugTrace2TSP(( "LONG =%d %d %.6lf", (*longestConnect)->points[0]->group->index, (*longestConnect)->points[0]->indexInGroup, (*longestConnect)->Distance() ));
- DebugTrace2TSP(( "LONG =%d %d %.6lf", (*longestConnect)->points[1]->group->index, (*longestConnect)->points[1]->indexInGroup, (*longestConnect)->Distance() ));
-
- int perm = permutationBest.back();
-
- for( std::vector<OrderingGroupConnection*>::iterator it=connections.begin(); it!=connections.end(); ++it )
- {
- (*it)->Connect(1, segments[ perm ].GetEndPoint ( iSwapBest, iEndBest ) );
- perm = permutationBest[ it-connections.begin() ];
- (*it)->Connect(0, segments[ perm ].GetBeginPoint( iSwapBest, iEndBest ) );
-
- }
-
- for( std::vector<OrderingGroupConnection*>::iterator it=connections.begin(); it!=connections.end(); ++it )
- {
- DebugTrace2TSP(( "IS 0F=%d %d %.6lf", (*it)->points[0]->group->index, (*it)->points[0]->indexInGroup, (*it)->Distance() ));
- DebugTrace2TSP(( "IS 0T=%d %d %.6lf", (*it)->points[1]->group->index, (*it)->points[1]->indexInGroup, (*it)->Distance() ));
- }
-
- (*longestConnect) = longestOutside;
- for( std::vector<OrderingGroupConnection*>::iterator it=connections.begin(); it!=connections.end(); ++it )
- {
- if( (*it)->Distance() > (*longestConnect)->Distance() )
- {
- *longestConnect = *it;
- }
- }
- DebugTrace2TSP(( "LONG =%d %d %.6lf", (*longestConnect)->points[0]->group->index, (*longestConnect)->points[0]->indexInGroup, (*longestConnect)->Distance() ));
- DebugTrace2TSP(( "LONG =%d %d %.6lf", (*longestConnect)->points[1]->group->index, (*longestConnect)->points[1]->indexInGroup, (*longestConnect)->Distance() ));
- }
-
- return improved;
+ // Find the longest connection outside of the active set
+ // The longest segment is then the longest of this longest outside segment and all inside segments
+ OrderingGroupConnection *longestOutside = 0;
+
+ if (contains(connections, *longestConnect)) {
+ // The longest connection is inside the active set, so we need to search for the longest outside
+ Coord length = 0.0;
+ for (std::vector<OrderingGroupConnection *>::iterator it = allconnections.begin(); it != allconnections.end(); it++) {
+ if ((*it)->Distance() > length) {
+ if (!contains(connections, *it)) {
+ longestOutside = *it;
+ length = (*it)->Distance();
+ }
+ }
+ }
+ } else {
+ longestOutside = *longestConnect;
+ }
+
+ // length of longestConnect outside
+ Coord longestOutsideLength = longestOutside ? longestOutside->Distance() : 0.0;
+
+ // We measure length without the longest, so subtract the longest length from the old distance
+ olddist -= (*longestConnect)->Distance();
+
+ // Assign a swap bit and end bit to each active connection
+ int nEndBits = 0;
+ int nSwapBits = 0;
+ for (std::vector<OrderingSegment>::iterator it = segments.begin(); it != segments.end(); it++) {
+ it->endbit = nEndBits++;
+ if (it->nEndPoints == 4) {
+ it->swapbit = nSwapBits++;
+ } else {
+ // bit 32 should always be 0
+ it->swapbit = 31;
+ }
+ }
+
+ unsigned int swapMask = (1U << nSwapBits) - 1;
+ unsigned int endMask = (1U << nEndBits) - 1;
+
+ // Create a permutation vector
+ std::vector<int> permutation(segments.size());
+ fill_increasing(permutation.begin(), permutation.end(), 0);
+
+ // best improvement
+ bool improved = false;
+ Coord distBest = olddist;
+ std::vector<int> permutationBest;
+ unsigned int iSwapBest;
+ unsigned int iEndBest;
+ int nTrials = 0;
+
+ // Loop over the permutations
+ do {
+ // Loop over the swap bits
+ unsigned int iSwap = 0;
+ do {
+ // Loop over the end bits
+ unsigned int iEnd = 0;
+ do {
+ // Length of all active connections
+ Coord lengthTotal = 0;
+ // Length of longest connection (active or inactive)
+ Coord lengthLongest = longestOutsideLength;
+
+ // Close the loop with the end point of the last segment
+ OrderingGroupPoint *prevend = segments[permutation.back()].GetEndPoint(iSwap, iEnd);
+ for (std::vector<int>::iterator it = permutation.begin(); it != permutation.end(); it++) {
+ OrderingGroupPoint *thisbeg = segments[*it].GetBeginPoint(iSwap, iEnd);
+ Coord length = Geom::distance(thisbeg->point, prevend->point);
+ lengthTotal += length;
+ if (length > lengthLongest) {
+ lengthLongest = length;
+ }
+ prevend = segments[*it].GetEndPoint(iSwap, iEnd);
+ }
+ lengthTotal -= lengthLongest;
+
+ // If there is an improvement, remember the best selection
+ if (lengthTotal + 1e-6 < distBest) {
+ improved = true;
+ distBest = lengthTotal;
+ permutationBest = permutation;
+ iSwapBest = iSwap;
+ iEndBest = iEnd;
+
+ // Just debug printing
+ OrderingGroupPoint *prevend = segments[permutation.back()].GetEndPoint(iSwap, iEnd);
+ for (std::vector<int>::iterator it = permutation.begin(); it != permutation.end(); it++) {
+ OrderingGroupPoint *thisbeg = segments[*it].GetBeginPoint(iSwap, iEnd);
+ DebugTrace2TSP(("IMP 0F=%d %d %.6lf", thisbeg->group->index, thisbeg->indexInGroup, Geom::distance(thisbeg->point, prevend->point)));
+ DebugTrace2TSP(("IMP 0T=%d %d %.6lf", prevend->group->index, prevend->indexInGroup, Geom::distance(thisbeg->point, prevend->point)));
+ prevend = segments[*it].GetEndPoint(iSwap, iEnd);
+ }
+ }
+
+ nTrials++;
+
+ // bit 0 is always 0, because the first segment is kept fixed
+ iEnd += 2;
+ } while (iEnd & endMask);
+ iSwap++;
+ } while (iSwap & swapMask);
+ // first segment is kept fixed
+ } while (std::next_permutation(permutation.begin() + 1, permutation.end()));
+
+ if (improved) {
+ DebugTrace2TSP(("Improvement %lf->%lf in %d", olddist, distBest, nTrials));
+ // change the connections
+
+ for (std::vector<OrderingGroupConnection *>::iterator it = connections.begin(); it != connections.end(); ++it) {
+ DebugTrace2TSP(("WAS 0F=%d %d %.6lf", (*it)->points[0]->group->index, (*it)->points[0]->indexInGroup, (*it)->Distance()));
+ DebugTrace2TSP(("WAS 0T=%d %d %.6lf", (*it)->points[1]->group->index, (*it)->points[1]->indexInGroup, (*it)->Distance()));
+ }
+ DebugTrace2TSP(("OLDDIST %.6lf delta %.6lf", olddist, olddist - (*longestConnect)->Distance()));
+ DebugTrace2TSP(("LONG =%d %d %.6lf", (*longestConnect)->points[0]->group->index, (*longestConnect)->points[0]->indexInGroup, (*longestConnect)->Distance()));
+ DebugTrace2TSP(("LONG =%d %d %.6lf", (*longestConnect)->points[1]->group->index, (*longestConnect)->points[1]->indexInGroup, (*longestConnect)->Distance()));
+
+ int perm = permutationBest.back();
+
+ for (std::vector<OrderingGroupConnection *>::iterator it = connections.begin(); it != connections.end(); ++it) {
+ (*it)->Connect(1, segments[ perm ].GetEndPoint(iSwapBest, iEndBest));
+ perm = permutationBest[ it - connections.begin() ];
+ (*it)->Connect(0, segments[ perm ].GetBeginPoint(iSwapBest, iEndBest));
+
+ }
+
+ for (std::vector<OrderingGroupConnection *>::iterator it = connections.begin(); it != connections.end(); ++it) {
+ DebugTrace2TSP(("IS 0F=%d %d %.6lf", (*it)->points[0]->group->index, (*it)->points[0]->indexInGroup, (*it)->Distance()));
+ DebugTrace2TSP(("IS 0T=%d %d %.6lf", (*it)->points[1]->group->index, (*it)->points[1]->indexInGroup, (*it)->Distance()));
+ }
+
+ (*longestConnect) = longestOutside;
+ for (std::vector<OrderingGroupConnection *>::iterator it = connections.begin(); it != connections.end(); ++it) {
+ if ((*it)->Distance() > (*longestConnect)->Distance()) {
+ *longestConnect = *it;
+ }
+ }
+ DebugTrace2TSP(("LONG =%d %d %.6lf", (*longestConnect)->points[0]->group->index, (*longestConnect)->points[0]->indexInGroup, (*longestConnect)->Distance()));
+ DebugTrace2TSP(("LONG =%d %d %.6lf", (*longestConnect)->points[1]->group->index, (*longestConnect)->points[1]->indexInGroup, (*longestConnect)->Distance()));
+ }
+
+ return improved;
}
// Check if connections form a tour
-void AssertIsTour( std::vector<OrderingGroup*> &groups, std::vector<OrderingGroupConnection*> &connections, OrderingGroupConnection *longestConnection )
+void AssertIsTour(std::vector<OrderingGroup *> &groups, std::vector<OrderingGroupConnection *> &connections, OrderingGroupConnection *longestConnection)
{
- for( std::vector<OrderingGroupConnection*>::iterator it=connections.begin(); it!=connections.end(); it++ )
- {
- for( int i=0; i<2; i++ )
- {
- OrderingGroupPoint *pnt=(*it)->points[i];
- assert( pnt->connection == *it );
- assert( pnt->connection->points[pnt->indexInConnection] == pnt );
- assert( pnt->group->endpoints[pnt->indexInGroup] == pnt );
- }
- }
-
- Coord length1=0;
- Coord longest1=0;
- OrderingGroupPoint *current = connections.front()->points[0];
-
- for( unsigned int n=0; n<connections.size(); n++ )
- {
- DebugTrace2TSP(( "Tour test 1 %p g=%d/%d c=%d/%d %p %p %.6lf %.3lf %.3lf %d %d %d", current, current->group->index, current->indexInGroup, current->connection->index, current->indexInConnection, current->connection->points[0], current->connection->points[1], current->connection->Distance(), current->point.x(), 297-current->point.y(), current->begin, current->front, current->group->items.size() ));
- Coord length = current->connection->Distance();
- length1 += length;
- longest1 = std::max( length, longest1 );
- current = current->GetOtherEndConnection();
-
- DebugTrace2TSP(( "Tour test 2 %p g=%d/%d c=%d/%d %p %p %.6lf %.3lf %.3lf %d %d %d", current, current->group->index, current->indexInGroup, current->connection->index, current->indexInConnection, current->connection->points[0], current->connection->points[1], current->connection->Distance(), current->point.x(), 297-current->point.y(), current->begin, current->front, current->group->items.size() ));
- current = current->GetOtherEndGroup();
- }
- DebugTrace2TSP(( "Tour test 3 %p g=%d/%d c=%d/%d %p %p", current, current->group->index, current->indexInGroup, current->connection->index, current->indexInConnection, current->connection->points[0], current->connection->points[1] ));
- assert( current == connections.front()->points[0] );
-
- // The other direction
- Coord length2=0;
- Coord longest2=0;
- current = connections.front()->points[0];
- for( unsigned int n=0; n<connections.size(); n++ )
- {
- current = current->GetOtherEndGroup();
- Coord length = current->connection->Distance();
- length2 += length;
- longest2 = std::max( length, longest2 );
- current = current->GetOtherEndConnection();
- }
- assert( current == connections.front()->points[0] );
-
- DebugTrace1TSP(( "Tour length %.6lf(%.6lf) longest %.6lf(%.6lf) remaining %.6lf(%.6lf)", length1, length2, longest1, longest2, length1-longest1, length2-longest2 ));
+ for (std::vector<OrderingGroupConnection *>::iterator it = connections.begin(); it != connections.end(); it++) {
+ for (int i = 0; i < 2; i++) {
+ OrderingGroupPoint *pnt = (*it)->points[i];
+ assert(pnt->connection == *it);
+ assert(pnt->connection->points[pnt->indexInConnection] == pnt);
+ assert(pnt->group->endpoints[pnt->indexInGroup] == pnt);
+ }
+ }
+
+ Coord length1 = 0;
+ Coord longest1 = 0;
+ OrderingGroupPoint *current = connections.front()->points[0];
+
+ for (unsigned int n = 0; n < connections.size(); n++) {
+ DebugTrace2TSP(("Tour test 1 %p g=%d/%d c=%d/%d %p %p %.6lf %.3lf %.3lf %d %d %d", current, current->group->index, current->indexInGroup, current->connection->index, current->indexInConnection, current->connection->points[0], current->connection->points[1], current->connection->Distance(), current->point.x(), 297 - current->point.y(), current->begin, current->front, current->group->items.size()));
+ Coord length = current->connection->Distance();
+ length1 += length;
+ longest1 = std::max(length, longest1);
+ current = current->GetOtherEndConnection();
+
+ DebugTrace2TSP(("Tour test 2 %p g=%d/%d c=%d/%d %p %p %.6lf %.3lf %.3lf %d %d %d", current, current->group->index, current->indexInGroup, current->connection->index, current->indexInConnection, current->connection->points[0], current->connection->points[1], current->connection->Distance(), current->point.x(), 297 - current->point.y(), current->begin, current->front, current->group->items.size()));
+ current = current->GetOtherEndGroup();
+ }
+ DebugTrace2TSP(("Tour test 3 %p g=%d/%d c=%d/%d %p %p", current, current->group->index, current->indexInGroup, current->connection->index, current->indexInConnection, current->connection->points[0], current->connection->points[1]));
+ assert(current == connections.front()->points[0]);
+
+ // The other direction
+ Coord length2 = 0;
+ Coord longest2 = 0;
+ current = connections.front()->points[0];
+ for (unsigned int n = 0; n < connections.size(); n++) {
+ current = current->GetOtherEndGroup();
+ Coord length = current->connection->Distance();
+ length2 += length;
+ longest2 = std::max(length, longest2);
+ current = current->GetOtherEndConnection();
+ }
+ assert(current == connections.front()->points[0]);
+
+ DebugTrace1TSP(("Tour length %.6lf(%.6lf) longest %.6lf(%.6lf) remaining %.6lf(%.6lf)", length1, length2, longest1, longest2, length1 - longest1, length2 - longest2));
}
// Bring a tour into linear order after a modification
@@ -891,344 +831,307 @@ void AssertIsTour( std::vector<OrderingGroup*> &groups, std::vector<OrderingGrou
* but it is difficult to know the segments, that is which endpoint of a connection is connected to which by the unmodified pieces of the tour.
* In the end it is probably better to implement the Lin-Kernighan algorithm which avoids this problem by creating connected changes. */
-void LinearizeTour( std::vector<OrderingGroupConnection*> &connections )
+void LinearizeTour(std::vector<OrderingGroupConnection *> &connections)
{
- OrderingGroupPoint *current = connections.front()->points[0];
-
- for( unsigned int iNew=0; iNew<connections.size(); iNew++ )
- {
- // swap the connection at location n with the current connection
- OrderingGroupConnection *connection = current->connection;
- unsigned int iOld = connection->index;
- assert( connections[iOld] == connection );
-
- connections[iOld] = connections[iNew];
- connections[iNew] = connection;
- connections[iOld]->index = iOld;
- connections[iNew]->index = iNew;
-
- // swap the points of a connection
- assert( current == connection->points[0] || current == connection->points[1] );
- if( current != connection->points[0] )
- {
- connection->points[1] = connection->points[0];
- connection->points[0] = current;
- connection->points[1]->indexInConnection = 1;
- connection->points[0]->indexInConnection = 0;
- }
-
- current = current->GetOtherEndConnection();
- current = current->GetOtherEndGroup();
- }
+ OrderingGroupPoint *current = connections.front()->points[0];
+
+ for (unsigned int iNew = 0; iNew < connections.size(); iNew++) {
+ // swap the connection at location n with the current connection
+ OrderingGroupConnection *connection = current->connection;
+ unsigned int iOld = connection->index;
+ assert(connections[iOld] == connection);
+
+ connections[iOld] = connections[iNew];
+ connections[iNew] = connection;
+ connections[iOld]->index = iOld;
+ connections[iNew]->index = iNew;
+
+ // swap the points of a connection
+ assert(current == connection->points[0] || current == connection->points[1]);
+ if (current != connection->points[0]) {
+ connection->points[1] = connection->points[0];
+ connection->points[0] = current;
+ connection->points[1]->indexInConnection = 1;
+ connection->points[0]->indexInConnection = 0;
+ }
+
+ current = current->GetOtherEndConnection();
+ current = current->GetOtherEndGroup();
+ }
}
// Use some Traveling Salesman Problem (TSP) like heuristics to bring several groups into a
// order with as short as possible interconnection paths
-void OrderGroups( std::vector<OrderingGroup*> *groups, const int nDims )
+void OrderGroups(std::vector<OrderingGroup *> *groups, const int nDims)
{
- // There is no point in ordering just one group
- if( groups->size()<=1 )
- {
- return;
- }
-
- // Initialize the endpoints for all groups
- for( std::vector<OrderingGroup*>::iterator it=groups->begin(); it!=groups->end(); ++it )
- {
- (*it)->SetEndpoints();
- }
-
- // Find the neighboring points for all end points of all groups and sort by distance
- for( std::vector<OrderingGroup*>::iterator itThis=groups->begin(); itThis!=groups->end(); ++itThis )
- {
- for( int i=0; i<(*itThis)->nEndPoints; i++ )
- {
- // This can be up to 2x too large, but still better than incrementing the size
- (*itThis)->endpoints[i]->nearest.reserve( 4 * groups->size() );
- }
-
- for( std::vector<OrderingGroup*>::iterator itNghb=groups->begin(); itNghb!=groups->end(); ++itNghb )
- {
- if( itThis!=itNghb )
- {
- (*itThis)->AddNeighbors( *itNghb );
- }
- }
-
- for( int i=0; i<(*itThis)->nEndPoints; i++ )
- {
- std::sort( (*itThis)->endpoints[i]->nearest.begin(), (*itThis)->endpoints[i]->nearest.end(), OrderingGroupNeighbor::Compare);
- }
- }
-
- // =========== Step 1: Create a simple nearest neighbor chain ===========
-
- // Vector of connection points
- std::vector<OrderingGroupConnection*> connections;
- connections.reserve( groups->size() );
- // Total Jump Distance
- Coord total=0.0;
-
- // Start with the first group and connect always with nearest unused point
- OrderingGroupPoint *crnt = groups->front()->endpoints[0];
-
- // The longest connection is ignored (we don't want cycles)
- OrderingGroupConnection *longestConnect=0;
-
- for( unsigned int nConnected=0; nConnected<groups->size(); nConnected++ )
- {
- // Mark both end points of the current segment as used
- crnt->UsePoint();
- crnt = crnt->GetOtherEndGroup();
- crnt->UsePoint();
-
- // if this is the last segment, Mark start point of first segment as unused,
- // so that the end can connect to it
- if( nConnected==groups->size()-1 )
- {
- groups->front()->endpoints[0]->UnusePoint();
- }
-
- // connect to next segment
- OrderingGroupNeighbor *nghb=crnt->FindNearestUnused( );
- connections.push_back( new OrderingGroupConnection( crnt, nghb->point, connections.size() ) );
- total += nghb->distance;
- crnt = nghb->point;
-
- if( !longestConnect || nghb->distance > longestConnect->Distance() )
- {
- longestConnect = connections.back();
- }
- }
-
- DebugTrace1TSP(("Total jump distance %.3lf (closed)", total ));
- DebugTrace1TSP(("Total jump distance %.3lf (open)", total-longestConnect->Distance() ));
-
- AssertIsTour( *groups, connections, longestConnect );
-
- // =========== Step 2: Choose nDims segments to clear and reconnect ===========
-
- bool improvement;
- int nRuns = 0;
- int nTrials = 0;
- int nImprovements = 0;
-
- do
- {
- improvement = false;
- nRuns ++;
- std::vector< std::vector<OrderingGroupConnection*>::iterator > iterators;
-
- for(
- triangleit_begin(iterators, connections.begin(), connections.end(), nDims );
- triangleit_test(iterators, connections.end() );
- triangleit_incr(iterators, connections.end() )
- )
- {
- nTrials ++;
-
- Coord dist = 0;
-
- std::vector<OrderingSegment> segments(iterators.size());
- std::vector<OrderingGroupConnection*> changedconnections;
- changedconnections.reserve(3);
- OrderingGroupConnection *prev = *iterators.back();
-
-
- for( size_t i=0; i<iterators.size(); i++ )
- {
- dist += (*iterators[i])->Distance();
- segments[i].AddPoint( prev->points[1] );
- segments[i].AddPoint( (*iterators[i])->points[0] );
- prev = *iterators[i];
- changedconnections.push_back(*iterators[i]);
- }
-
- if( FindShortestReconnect( segments, changedconnections, connections, &longestConnect, &total, dist ) )
- {
- nImprovements ++;
-
- AssertIsTour( *groups, connections, longestConnect );
- LinearizeTour( connections );
- AssertIsTour( *groups, connections, longestConnect );
- improvement = true;
- }
- }
- } while( improvement && nRuns<10 );
-
- DebugTrace1TSP(( "Finished after %d rounds, %d trials, %d improvements", nRuns, nTrials, nImprovements ));
-
- // =========== Step N: Create vector of groups from vector of connection points ===========
-
- std::vector<OrderingGroup*> result;
- result.reserve( groups->size() );
-
- // Go through the groups starting with the longest connection (which is this way left out)
- {
- OrderingGroupPoint *current = longestConnect->points[1];
-
- for( unsigned int n=0; n<connections.size(); n++ )
- {
- result.push_back( current->group );
- current->SetRevInGroup();
- current = current->GetOtherEndGroup();
- current = current->GetOtherEndConnection();
- }
- }
-
- assert( result.size() == groups->size() );
- assert_unique( result );
-
- delete_and_clear( connections );
-
- *groups = result;
+ // There is no point in ordering just one group
+ if (groups->size() <= 1) {
+ return;
+ }
+
+ // Initialize the endpoints for all groups
+ for (std::vector<OrderingGroup *>::iterator it = groups->begin(); it != groups->end(); ++it) {
+ (*it)->SetEndpoints();
+ }
+
+ // Find the neighboring points for all end points of all groups and sort by distance
+ for (std::vector<OrderingGroup *>::iterator itThis = groups->begin(); itThis != groups->end(); ++itThis) {
+ for (int i = 0; i < (*itThis)->nEndPoints; i++) {
+ // This can be up to 2x too large, but still better than incrementing the size
+ (*itThis)->endpoints[i]->nearest.reserve(4 * groups->size());
+ }
+
+ for (std::vector<OrderingGroup *>::iterator itNghb = groups->begin(); itNghb != groups->end(); ++itNghb) {
+ if (itThis != itNghb) {
+ (*itThis)->AddNeighbors(*itNghb);
+ }
+ }
+
+ for (int i = 0; i < (*itThis)->nEndPoints; i++) {
+ std::sort((*itThis)->endpoints[i]->nearest.begin(), (*itThis)->endpoints[i]->nearest.end(), OrderingGroupNeighbor::Compare);
+ }
+ }
+
+ // =========== Step 1: Create a simple nearest neighbor chain ===========
+
+ // Vector of connection points
+ std::vector<OrderingGroupConnection *> connections;
+ connections.reserve(groups->size());
+ // Total Jump Distance
+ Coord total = 0.0;
+
+ // Start with the first group and connect always with nearest unused point
+ OrderingGroupPoint *crnt = groups->front()->endpoints[0];
+
+ // The longest connection is ignored (we don't want cycles)
+ OrderingGroupConnection *longestConnect = 0;
+
+ for (unsigned int nConnected = 0; nConnected < groups->size(); nConnected++) {
+ // Mark both end points of the current segment as used
+ crnt->UsePoint();
+ crnt = crnt->GetOtherEndGroup();
+ crnt->UsePoint();
+
+ // if this is the last segment, Mark start point of first segment as unused,
+ // so that the end can connect to it
+ if (nConnected == groups->size() - 1) {
+ groups->front()->endpoints[0]->UnusePoint();
+ }
+
+ // connect to next segment
+ OrderingGroupNeighbor *nghb = crnt->FindNearestUnused();
+ connections.push_back(new OrderingGroupConnection(crnt, nghb->point, connections.size()));
+ total += nghb->distance;
+ crnt = nghb->point;
+
+ if (!longestConnect || nghb->distance > longestConnect->Distance()) {
+ longestConnect = connections.back();
+ }
+ }
+
+ DebugTrace1TSP(("Total jump distance %.3lf (closed)", total));
+ DebugTrace1TSP(("Total jump distance %.3lf (open)", total - longestConnect->Distance()));
+
+ AssertIsTour(*groups, connections, longestConnect);
+
+ // =========== Step 2: Choose nDims segments to clear and reconnect ===========
+
+ bool improvement;
+ int nRuns = 0;
+ int nTrials = 0;
+ int nImprovements = 0;
+
+ do {
+ improvement = false;
+ nRuns ++;
+ std::vector< std::vector<OrderingGroupConnection *>::iterator > iterators;
+
+ for (
+ triangleit_begin(iterators, connections.begin(), connections.end(), nDims);
+ triangleit_test(iterators, connections.end());
+ triangleit_incr(iterators, connections.end())
+ ) {
+ nTrials ++;
+
+ Coord dist = 0;
+
+ std::vector<OrderingSegment> segments(iterators.size());
+ std::vector<OrderingGroupConnection *> changedconnections;
+ changedconnections.reserve(3);
+ OrderingGroupConnection *prev = *iterators.back();
+
+
+ for (size_t i = 0; i < iterators.size(); i++) {
+ dist += (*iterators[i])->Distance();
+ segments[i].AddPoint(prev->points[1]);
+ segments[i].AddPoint((*iterators[i])->points[0]);
+ prev = *iterators[i];
+ changedconnections.push_back(*iterators[i]);
+ }
+
+ if (FindShortestReconnect(segments, changedconnections, connections, &longestConnect, &total, dist)) {
+ nImprovements ++;
+
+ AssertIsTour(*groups, connections, longestConnect);
+ LinearizeTour(connections);
+ AssertIsTour(*groups, connections, longestConnect);
+ improvement = true;
+ }
+ }
+ } while (improvement && nRuns < 10);
+
+ DebugTrace1TSP(("Finished after %d rounds, %d trials, %d improvements", nRuns, nTrials, nImprovements));
+
+ // =========== Step N: Create vector of groups from vector of connection points ===========
+
+ std::vector<OrderingGroup *> result;
+ result.reserve(groups->size());
+
+ // Go through the groups starting with the longest connection (which is this way left out)
+ {
+ OrderingGroupPoint *current = longestConnect->points[1];
+
+ for (unsigned int n = 0; n < connections.size(); n++) {
+ result.push_back(current->group);
+ current->SetRevInGroup();
+ current = current->GetOtherEndGroup();
+ current = current->GetOtherEndConnection();
+ }
+ }
+
+ assert(result.size() == groups->size());
+ assert_unique(result);
+
+ delete_and_clear(connections);
+
+ *groups = result;
}
// Global optimization of path length
-void OrderingAdvanced( std::vector<OrderingInfo> & infos, int nDims )
+void OrderingAdvanced(std::vector<OrderingInfo> &infos, int nDims)
{
- if( infos.size()<3 )
- {
- return;
- }
-
- // Create extended ordering info vector and copy data from normal ordering info
- std::vector<OrderingInfoEx*> infoex;
- infoex.reserve( infos.size() );
-
- for( std::vector<OrderingInfo>::const_iterator it=infos.begin(); it!=infos.end(); )
- {
- // Note: This assumes that the index in the OrderingInfo matches the vector index!
- infoex.push_back( new OrderingInfoEx( *it, infoex.size() ) );
- ++it;
- while( it!=infos.end() && it->begOrig == infoex.back()->end.point )
- {
- infoex.back()->end.point = it->endOrig;
- infoex.back()->origIndices.push_back( it->index );
- ++it;
- }
- }
-
- // Find closest 2 points for each point and enforce that 2nd nearest is not further away than 1.8xthe nearest
- // If this is not the case, clear nearest and 2nd nearest point
- for( std::vector<OrderingInfoEx*>::iterator it=infoex.begin(); it!=infoex.end(); ++it )
- {
- (*it)->beg.FindNearest2( infoex );
- (*it)->end.FindNearest2( infoex );
- }
-
- DebugTraceGrouping(
- DebugTrace2(( "STEP1" ));
- for( std::vector<OrderingInfoEx*>::iterator it=infoex.begin(); it!=infoex.end(); ++it )
- {
- (*it)->beg.Dump();
- (*it)->end.Dump();
- }
- )
-
- // Make sure the nearest points are mutual
- for( std::vector<OrderingInfoEx*>::iterator it=infoex.begin(); it!=infoex.end(); ++it )
- {
- (*it)->beg.EnforceMutual();
- (*it)->end.EnforceMutual();
- }
-
- DebugTraceGrouping(
- DebugTrace2(( "STEP2" ));
- for( std::vector<OrderingInfoEx*>::iterator it=infoex.begin(); it!=infoex.end(); ++it )
- {
- (*it)->beg.Dump();
- (*it)->end.Dump();
- }
- )
-
- // Make sure the nearest points for begin and end lead to the same sub-path (same index)
- for( std::vector<OrderingInfoEx*>::iterator it=infoex.begin(); it!=infoex.end(); ++it )
- {
- (*it)->beg.EnforceSymmetric( (*it)->end );
- (*it)->end.EnforceSymmetric( (*it)->beg );
- }
-
- DebugTraceGrouping(
- DebugTrace2(( "STEP3" ));
- for( std::vector<OrderingInfoEx*>::iterator it=infoex.begin(); it!=infoex.end(); ++it )
- {
- (*it)->beg.Dump();
- (*it)->end.Dump();
- }
- )
-
- // The remaining nearest neighbors should be 100% non ambiguous, so group them
- std::vector<OrderingGroup*> groups;
- for( std::vector<OrderingInfoEx*>::iterator it=infoex.begin(); it!=infoex.end(); ++it )
- {
- (*it)->MakeGroup( infoex, &groups );
- }
-
- // Create single groups for ungrouped lines
- std::vector<OrderingInfo> result;
- result.reserve( infos.size() );
- int nUngrouped=0;
- for( std::vector<OrderingInfoEx*>::iterator it=infoex.begin(); it!=infoex.end(); ++it )
- {
- if( !(*it)->grouped )
- {
- groups.push_back( new OrderingGroup( groups.size() ) );
- groups.back()->items.push_back( *it );
- nUngrouped++;
- }
- }
-
- DebugTraceGrouping(
- DebugTrace2(( "Ungrouped lines = %d", nUngrouped ));
- DebugTrace2(( "%d Groups found", groups.size() ));
- for( std::vector<OrderingGroup*>::iterator it=groups.begin(); it!=groups.end(); ++it )
- {
- DebugTrace2(( "Group size %d", (*it)->items.size() ));
- }
- )
-
- // Order groups, so that the connection path gets shortest
- OrderGroups( &groups, nDims );
-
- // Copy grouped lines to output
- for( std::vector<OrderingGroup*>::iterator itGroup=groups.begin(); itGroup!=groups.end(); ++itGroup )
- {
- for( unsigned int iItem=0; iItem<(*itGroup)->items.size(); iItem++ )
- {
- unsigned int iItemRev = (*itGroup)->revItemList ? (*itGroup)->items.size()-1-iItem : iItem;
- OrderingInfoEx *item = (*itGroup)->items[iItemRev];
-
- // If revItems is false, even items shall have reverse=false
- // In this case ( ( iItem & 1 ) == 0 )== true, revItems=false, (true==false) == false
- bool reverse = ( ( iItem & 1 ) == 0 ) == (*itGroup)->revItems;
- if( !reverse )
- {
- for( std::vector<int>::iterator itOrig=item->origIndices.begin(); itOrig!=item->origIndices.end(); ++itOrig )
- {
- result.push_back( infos[*itOrig] );
- result.back().reverse = false;
- }
- }
- else
- {
- for( std::vector<int>::reverse_iterator itOrig=item->origIndices.rbegin(); itOrig!=item->origIndices.rend(); ++itOrig )
- {
- result.push_back( infos[*itOrig] );
- result.back().reverse = true;
- }
- }
- }
- result.back().connect = true;
- }
-
-
- delete_and_clear( groups );
- delete_and_clear( infoex );
-
- infos=result;
+ if (infos.size() < 3) {
+ return;
+ }
+
+ // Create extended ordering info vector and copy data from normal ordering info
+ std::vector<OrderingInfoEx *> infoex;
+ infoex.reserve(infos.size());
+
+ for (std::vector<OrderingInfo>::const_iterator it = infos.begin(); it != infos.end();) {
+ // Note: This assumes that the index in the OrderingInfo matches the vector index!
+ infoex.push_back(new OrderingInfoEx(*it, infoex.size()));
+ ++it;
+ while (it != infos.end() && it->begOrig == infoex.back()->end.point) {
+ infoex.back()->end.point = it->endOrig;
+ infoex.back()->origIndices.push_back(it->index);
+ ++it;
+ }
+ }
+
+ // Find closest 2 points for each point and enforce that 2nd nearest is not further away than 1.8xthe nearest
+ // If this is not the case, clear nearest and 2nd nearest point
+ for (std::vector<OrderingInfoEx *>::iterator it = infoex.begin(); it != infoex.end(); ++it) {
+ (*it)->beg.FindNearest2(infoex);
+ (*it)->end.FindNearest2(infoex);
+ }
+
+ DebugTraceGrouping(
+ DebugTrace2(("STEP1"));
+ for (std::vector<OrderingInfoEx *>::iterator it = infoex.begin(); it != infoex.end(); ++it) {
+ (*it)->beg.Dump();
+ (*it)->end.Dump();
+ }
+ )
+
+ // Make sure the nearest points are mutual
+ for (std::vector<OrderingInfoEx *>::iterator it = infoex.begin(); it != infoex.end(); ++it) {
+ (*it)->beg.EnforceMutual();
+ (*it)->end.EnforceMutual();
+ }
+
+ DebugTraceGrouping(
+ DebugTrace2(("STEP2"));
+ for (std::vector<OrderingInfoEx *>::iterator it = infoex.begin(); it != infoex.end(); ++it) {
+ (*it)->beg.Dump();
+ (*it)->end.Dump();
+ }
+ )
+
+ // Make sure the nearest points for begin and end lead to the same sub-path (same index)
+ for (std::vector<OrderingInfoEx *>::iterator it = infoex.begin(); it != infoex.end(); ++it) {
+ (*it)->beg.EnforceSymmetric((*it)->end);
+ (*it)->end.EnforceSymmetric((*it)->beg);
+ }
+
+ DebugTraceGrouping(
+ DebugTrace2(("STEP3"));
+ for (std::vector<OrderingInfoEx *>::iterator it = infoex.begin(); it != infoex.end(); ++it) {
+ (*it)->beg.Dump();
+ (*it)->end.Dump();
+ }
+ )
+
+ // The remaining nearest neighbors should be 100% non ambiguous, so group them
+ std::vector<OrderingGroup *> groups;
+ for (std::vector<OrderingInfoEx *>::iterator it = infoex.begin(); it != infoex.end(); ++it) {
+ (*it)->MakeGroup(infoex, &groups);
+ }
+
+ // Create single groups for ungrouped lines
+ std::vector<OrderingInfo> result;
+ result.reserve(infos.size());
+ int nUngrouped = 0;
+ for (std::vector<OrderingInfoEx *>::iterator it = infoex.begin(); it != infoex.end(); ++it) {
+ if (!(*it)->grouped) {
+ groups.push_back(new OrderingGroup(groups.size()));
+ groups.back()->items.push_back(*it);
+ nUngrouped++;
+ }
+ }
+
+ DebugTraceGrouping(
+ DebugTrace2(("Ungrouped lines = %d", nUngrouped));
+ DebugTrace2(("%d Groups found", groups.size()));
+ for (std::vector<OrderingGroup *>::iterator it = groups.begin(); it != groups.end(); ++it) {
+ DebugTrace2(("Group size %d", (*it)->items.size()));
+ }
+ )
+
+ // Order groups, so that the connection path gets shortest
+ OrderGroups(&groups, nDims);
+
+ // Copy grouped lines to output
+ for (std::vector<OrderingGroup *>::iterator itGroup = groups.begin(); itGroup != groups.end(); ++itGroup) {
+ for (unsigned int iItem = 0; iItem < (*itGroup)->items.size(); iItem++) {
+ unsigned int iItemRev = (*itGroup)->revItemList ? (*itGroup)->items.size() - 1 - iItem : iItem;
+ OrderingInfoEx *item = (*itGroup)->items[iItemRev];
+
+ // If revItems is false, even items shall have reverse=false
+ // In this case ( ( iItem & 1 ) == 0 )== true, revItems=false, (true==false) == false
+ bool reverse = ((iItem & 1) == 0) == (*itGroup)->revItems;
+ if (!reverse) {
+ for (std::vector<int>::iterator itOrig = item->origIndices.begin(); itOrig != item->origIndices.end(); ++itOrig) {
+ result.push_back(infos[*itOrig]);
+ result.back().reverse = false;
+ }
+ } else {
+ for (std::vector<int>::reverse_iterator itOrig = item->origIndices.rbegin(); itOrig != item->origIndices.rend(); ++itOrig) {
+ result.push_back(infos[*itOrig]);
+ result.back().reverse = true;
+ }
+ }
+ }
+ result.back().connect = true;
+ }
+
+
+ delete_and_clear(groups);
+ delete_and_clear(infoex);
+
+ infos = result;
}
} // namespace LPEEmbroderyStitchOrdering
diff --git a/src/live_effects/lpe-embrodery-stitch-ordering.h b/src/live_effects/lpe-embrodery-stitch-ordering.h
index 98c952fdd..b2b5d36db 100644
--- a/src/live_effects/lpe-embrodery-stitch-ordering.h
+++ b/src/live_effects/lpe-embrodery-stitch-ordering.h
@@ -18,19 +18,30 @@ namespace LPEEmbroderyStitchOrdering {
// Structure keeping information on the ordering and reversing of sub paths
// Used for simple ordering functions like zig-zag
-struct OrderingInfo
-{
- int index;
- bool reverse;
- bool used;
- bool connect;
- Geom::Point begOrig; // begin point in original orientation
- Geom::Point endOrig; // end point in original orientation
-
- Geom::Point GetBegOrig() const { return begOrig; }
- Geom::Point GetEndOrig() const { return endOrig; }
- Geom::Point GetBegRev() const { return reverse ? endOrig : begOrig; }
- Geom::Point GetEndRev() const { return reverse ? begOrig : endOrig; }
+struct OrderingInfo {
+ int index;
+ bool reverse;
+ bool used;
+ bool connect;
+ Geom::Point begOrig; // begin point in original orientation
+ Geom::Point endOrig; // end point in original orientation
+
+ Geom::Point GetBegOrig() const
+ {
+ return begOrig;
+ }
+ Geom::Point GetEndOrig() const
+ {
+ return endOrig;
+ }
+ Geom::Point GetBegRev() const
+ {
+ return reverse ? endOrig : begOrig;
+ }
+ Geom::Point GetEndRev() const
+ {
+ return reverse ? begOrig : endOrig;
+ }
};
// Structure for a path end-point in OrderingInfoEx.
@@ -38,33 +49,38 @@ struct OrderingInfo
struct OrderingInfoEx;
-struct OrderingPoint
-{
- OrderingPoint( const Geom::Point &pointIn, OrderingInfoEx *infoexIn, bool beginIn ) :
- point( pointIn ),
- infoex( infoexIn ),
- begin( beginIn )
- {
- nearest[0] = nearest[1] = 0;
- }
-
- // Check if both nearest values are valid
- bool IsNearestValid() const { return nearest[0] && nearest[1]; }
- // Check if at least one nearest values are valid
- bool HasNearest() const { return nearest[0] || nearest[1]; }
- // Find 2 nearest points to given point
- void FindNearest2( const std::vector<OrderingInfoEx*> & infos );
- // Check if "this" is among the nearest of its nearest
- void EnforceMutual( void );
- // Check if the subpath indices of this and other are the same, otherwise zero both nearest
- void EnforceSymmetric( const OrderingPoint &other );
- // Dump point information
- void Dump( void );
-
- Geom::Point point;
- OrderingInfoEx *infoex;
- bool begin;
- const OrderingPoint * nearest[2];
+struct OrderingPoint {
+ OrderingPoint(const Geom::Point &pointIn, OrderingInfoEx *infoexIn, bool beginIn) :
+ point(pointIn),
+ infoex(infoexIn),
+ begin(beginIn)
+ {
+ nearest[0] = nearest[1] = 0;
+ }
+
+ // Check if both nearest values are valid
+ bool IsNearestValid() const
+ {
+ return nearest[0] && nearest[1];
+ }
+ // Check if at least one nearest values are valid
+ bool HasNearest() const
+ {
+ return nearest[0] || nearest[1];
+ }
+ // Find 2 nearest points to given point
+ void FindNearest2(const std::vector<OrderingInfoEx *> &infos);
+ // Check if "this" is among the nearest of its nearest
+ void EnforceMutual(void);
+ // Check if the subpath indices of this and other are the same, otherwise zero both nearest
+ void EnforceSymmetric(const OrderingPoint &other);
+ // Dump point information
+ void Dump(void);
+
+ Geom::Point point;
+ OrderingInfoEx *infoex;
+ bool begin;
+ const OrderingPoint *nearest[2];
};
// Structure keeping information on the ordering and reversing of sub paths
@@ -74,185 +90,178 @@ struct OrderingPoint
struct OrderingGroup;
-struct OrderingInfoEx
-{
- OrderingInfoEx( const OrderingInfo &infoIn, int idxIn ) :
- beg( infoIn.begOrig, this, true ),
- end( infoIn.endOrig, this, false ),
- idx( idxIn ),
- grouped( false )
- {
- origIndices.push_back( infoIn.index );
- }
-
- // If this element can be grouped (has neighbours) but is not yet grouped, create a new group
- void MakeGroup( std::vector<OrderingInfoEx*> & infos, std::vector<OrderingGroup*> *groups );
- // Add this and all connected elements to the group
- void AddToGroup( std::vector<OrderingInfoEx*> & infos, OrderingGroup *group );
-
- int idx;
- bool grouped; // true if this element has been grouped
- OrderingPoint beg; // begin point in original orientation
- OrderingPoint end; // end point in original orientation
- std::vector<int> origIndices; // Indices of the original OrderInfos (more than 1 if directly connected
+struct OrderingInfoEx {
+ OrderingInfoEx(const OrderingInfo &infoIn, int idxIn) :
+ beg(infoIn.begOrig, this, true),
+ end(infoIn.endOrig, this, false),
+ idx(idxIn),
+ grouped(false)
+ {
+ origIndices.push_back(infoIn.index);
+ }
+
+ // If this element can be grouped (has neighbours) but is not yet grouped, create a new group
+ void MakeGroup(std::vector<OrderingInfoEx *> &infos, std::vector<OrderingGroup *> *groups);
+ // Add this and all connected elements to the group
+ void AddToGroup(std::vector<OrderingInfoEx *> &infos, OrderingGroup *group);
+
+ int idx;
+ bool grouped; // true if this element has been grouped
+ OrderingPoint beg; // begin point in original orientation
+ OrderingPoint end; // end point in original orientation
+ std::vector<int> origIndices; // Indices of the original OrderInfos (more than 1 if directly connected
};
// Neighbor information for OrderingGroupPoint - a distance and a OrderingGroupPoint
struct OrderingGroupPoint;
-struct OrderingGroupNeighbor
-{
- OrderingGroupNeighbor( OrderingGroupPoint *me, OrderingGroupPoint *other );
+struct OrderingGroupNeighbor {
+ OrderingGroupNeighbor(OrderingGroupPoint *me, OrderingGroupPoint *other);
- // Distance from owner of this neighbor info
- Geom::Coord distance;
- // Neighbor point (which in turn contains a pointer to the neighbor group
- OrderingGroupPoint *point;
+ // Distance from owner of this neighbor info
+ Geom::Coord distance;
+ // Neighbor point (which in turn contains a pointer to the neighbor group
+ OrderingGroupPoint *point;
- // Comparison function for sorting by distance
- static bool Compare( const OrderingGroupNeighbor &a, const OrderingGroupNeighbor &b );
+ // Comparison function for sorting by distance
+ static bool Compare(const OrderingGroupNeighbor &a, const OrderingGroupNeighbor &b);
};
// An end point in an OrderingGroup, with nearest neighbor information
struct OrderingGroupConnection;
-struct OrderingGroupPoint
-{
- OrderingGroupPoint( const Geom::Point &pointIn, OrderingGroup *groupIn, int indexIn, bool beginIn, bool frontIn ) :
- point( pointIn ),
- group( groupIn ),
- indexInGroup( indexIn ),
- connection( 0 ),
- indexInConnection( 0 ),
- begin( beginIn ),
- front( frontIn ),
- used( false )
- {
- }
-
- // Find the nearest unused neighbor point
- OrderingGroupNeighbor *FindNearestUnused( void );
- // Return the other end in the group of the point
- OrderingGroupPoint *GetOtherEndGroup( void );
- // Return the alternate point (if one exists), 0 otherwise
- OrderingGroupPoint *GetAltPointGroup( void );
- // Sets the rev flags in the group assuming that the group starts with this point
- void SetRevInGroup( void );
- // Mark an end point as used and also mark the two other alternating points as used
- // Returns the used point
- void UsePoint( void );
- // Mark an end point as unused and possibly also mark the two other alternating points as unused
- // Returns the used point
- void UnusePoint( void );
- // Return the other end in the connection
- OrderingGroupPoint *GetOtherEndConnection( void );
-
- // The coordinates of the point
- Geom::Point point;
- // The group to which the point belongs
- OrderingGroup *group;
- // The end-point index within the group
- int indexInGroup;
- // The connection, which connects this point
- OrderingGroupConnection *connection;
- // The end point index in the connection
- int indexInConnection;
- // True if this is a begin point (rather than an end point)
- bool begin;
- // True if this is a front point (rather than a back point)
- bool front;
- // True if the point is used/connected to another point
- bool used;
- // The nearest neighbors, to which this group end point may connect
- std::vector<OrderingGroupNeighbor> nearest;
+struct OrderingGroupPoint {
+ OrderingGroupPoint(const Geom::Point &pointIn, OrderingGroup *groupIn, int indexIn, bool beginIn, bool frontIn) :
+ point(pointIn),
+ group(groupIn),
+ indexInGroup(indexIn),
+ connection(0),
+ indexInConnection(0),
+ begin(beginIn),
+ front(frontIn),
+ used(false)
+ {
+ }
+
+ // Find the nearest unused neighbor point
+ OrderingGroupNeighbor *FindNearestUnused(void);
+ // Return the other end in the group of the point
+ OrderingGroupPoint *GetOtherEndGroup(void);
+ // Return the alternate point (if one exists), 0 otherwise
+ OrderingGroupPoint *GetAltPointGroup(void);
+ // Sets the rev flags in the group assuming that the group starts with this point
+ void SetRevInGroup(void);
+ // Mark an end point as used and also mark the two other alternating points as used
+ // Returns the used point
+ void UsePoint(void);
+ // Mark an end point as unused and possibly also mark the two other alternating points as unused
+ // Returns the used point
+ void UnusePoint(void);
+ // Return the other end in the connection
+ OrderingGroupPoint *GetOtherEndConnection(void);
+
+ // The coordinates of the point
+ Geom::Point point;
+ // The group to which the point belongs
+ OrderingGroup *group;
+ // The end-point index within the group
+ int indexInGroup;
+ // The connection, which connects this point
+ OrderingGroupConnection *connection;
+ // The end point index in the connection
+ int indexInConnection;
+ // True if this is a begin point (rather than an end point)
+ bool begin;
+ // True if this is a front point (rather than a back point)
+ bool front;
+ // True if the point is used/connected to another point
+ bool used;
+ // The nearest neighbors, to which this group end point may connect
+ std::vector<OrderingGroupNeighbor> nearest;
};
// A connection between two points/groups
-struct OrderingGroupConnection
-{
- OrderingGroupConnection( OrderingGroupPoint *fromIn, OrderingGroupPoint *toIn, int indexIn ) :
- index( indexIn )
- {
- assert( fromIn->connection==0 );
- assert( toIn->connection==0 );
- points[0]=0;
- points[1]=0;
- Connect( 0, fromIn );
- Connect( 1, toIn );
- }
-
- // Connect one of the conection endpoints to the given point
- void Connect( int index, OrderingGroupPoint *point )
- {
- assert( point );
- points[index] = point;
- point->connection = this;
- point->indexInConnection = index;
- }
-
- // Get length of connection
- Geom::Coord Distance( )
- {
- return Geom::distance( points[0]->point, points[1]->point );
- }
-
- OrderingGroupPoint *points[2];
- // index of connection in the connections vector (just for debugging)
- int index;
+struct OrderingGroupConnection {
+ OrderingGroupConnection(OrderingGroupPoint *fromIn, OrderingGroupPoint *toIn, int indexIn) :
+ index(indexIn)
+ {
+ assert(fromIn->connection == 0);
+ assert(toIn->connection == 0);
+ points[0] = 0;
+ points[1] = 0;
+ Connect(0, fromIn);
+ Connect(1, toIn);
+ }
+
+ // Connect one of the conection endpoints to the given point
+ void Connect(int index, OrderingGroupPoint *point)
+ {
+ assert(point);
+ points[index] = point;
+ point->connection = this;
+ point->indexInConnection = index;
+ }
+
+ // Get length of connection
+ Geom::Coord Distance()
+ {
+ return Geom::distance(points[0]->point, points[1]->point);
+ }
+
+ OrderingGroupPoint *points[2];
+ // index of connection in the connections vector (just for debugging)
+ int index;
};
// A group of OrderingInfoEx, which build a block in path interconnect length optimization.
// A block can have two sets of endpoints.
// If a block has 2 sets of endpoints, one can swap between the two sets.
-struct OrderingGroup
-{
- OrderingGroup( int indexIn ) :
- nEndPoints( 0 ),
- revItemList( false ),
- revItems( false ),
- index( indexIn )
- {
- for( int i=0; i<sizeof(endpoints)/sizeof(*endpoints); i++ )
- {
- endpoints[i] = 0;
- }
- }
-
- ~OrderingGroup()
- {
- for( int i=0; i<nEndPoints; i++ )
- {
- delete endpoints[i];
- }
- }
-
- // Set the endpoints of a group from the items
- void SetEndpoints( void );
- // Add all points from another group as neighbors
- void AddNeighbors( OrderingGroup *nghb );
- // Mark an end point as used and also mark the two other alternating points as used
- // Returns the used point
- OrderingGroupPoint *UsePoint( int index );
- // Mark an end point as unused and possibly also mark the two other alternating points as unused
- // Returns the used point
- void UnusePoint( int index );
-
- // Items on the group
- std::vector<OrderingInfoEx*> items;
- // End points of the group
- OrderingGroupPoint *endpoints[4];
- // Number of endpoints used (either 2 or 4)
- int nEndPoints;
- // Index of the group (just for debugging purposes)
- int index;
- // If true, the items in the group shall be output from back to front.
- bool revItemList;
- // If false, the individual items are output alternatingly normal-reversed
- // If true, the individual items are output alternatingly reversed-normal
- bool revItems;
+struct OrderingGroup {
+ OrderingGroup(int indexIn) :
+ nEndPoints(0),
+ revItemList(false),
+ revItems(false),
+ index(indexIn)
+ {
+ for (int i = 0; i < sizeof(endpoints) / sizeof(*endpoints); i++) {
+ endpoints[i] = 0;
+ }
+ }
+
+ ~OrderingGroup()
+ {
+ for (int i = 0; i < nEndPoints; i++) {
+ delete endpoints[i];
+ }
+ }
+
+ // Set the endpoints of a group from the items
+ void SetEndpoints(void);
+ // Add all points from another group as neighbors
+ void AddNeighbors(OrderingGroup *nghb);
+ // Mark an end point as used and also mark the two other alternating points as used
+ // Returns the used point
+ OrderingGroupPoint *UsePoint(int index);
+ // Mark an end point as unused and possibly also mark the two other alternating points as unused
+ // Returns the used point
+ void UnusePoint(int index);
+
+ // Items on the group
+ std::vector<OrderingInfoEx *> items;
+ // End points of the group
+ OrderingGroupPoint *endpoints[4];
+ // Number of endpoints used (either 2 or 4)
+ int nEndPoints;
+ // Index of the group (just for debugging purposes)
+ int index;
+ // If true, the items in the group shall be output from back to front.
+ bool revItemList;
+ // If false, the individual items are output alternatingly normal-reversed
+ // If true, the individual items are output alternatingly reversed-normal
+ bool revItems;
};
// A segment is either a OrderingGroup or a series of groups and connections.
@@ -260,43 +269,42 @@ struct OrderingGroup
// If a segment is just one ordering group, it has the same number of end points as the ordering group
// A main difference between a segment and a group is that the segment does not own the end points.
-struct OrderingSegment
-{
- OrderingSegment() :
- nEndPoints(0),
- endbit(0),
- swapbit(0)
- {}
-
- // Add an end point
- void AddPoint( OrderingGroupPoint *point );
- // Get begin point (taking swap and end bit into account
- OrderingGroupPoint *GetBeginPoint( unsigned int iSwap, unsigned int iEnd );
- // Get end point (taking swap and end bit into account
- OrderingGroupPoint *GetEndPoint( unsigned int iSwap, unsigned int iEnd );
-
- // End points of the group
- OrderingGroupPoint *endpoints[4];
- // Number of endpoints used (either 2 or 4)
- int nEndPoints;
- // bit index in the end counter
- int endbit;
- // bit index in the swap counter
- int swapbit;
+struct OrderingSegment {
+ OrderingSegment() :
+ nEndPoints(0),
+ endbit(0),
+ swapbit(0)
+ {}
+
+ // Add an end point
+ void AddPoint(OrderingGroupPoint *point);
+ // Get begin point (taking swap and end bit into account
+ OrderingGroupPoint *GetBeginPoint(unsigned int iSwap, unsigned int iEnd);
+ // Get end point (taking swap and end bit into account
+ OrderingGroupPoint *GetEndPoint(unsigned int iSwap, unsigned int iEnd);
+
+ // End points of the group
+ OrderingGroupPoint *endpoints[4];
+ // Number of endpoints used (either 2 or 4)
+ int nEndPoints;
+ // bit index in the end counter
+ int endbit;
+ // bit index in the swap counter
+ int swapbit;
};
// Sub-path reordering: do nothing - keep original order
-void OrderingOriginal( std::vector<OrderingInfo> & infos );
+void OrderingOriginal(std::vector<OrderingInfo> &infos);
// Sub-path reordering: reverse every other sub path
-void OrderingZigZag( std::vector<OrderingInfo> & infos, bool revfirst );
+void OrderingZigZag(std::vector<OrderingInfo> &infos, bool revfirst);
// Sub-path reordering: continue with the neartest start or end point of yet unused sub paths
-void OrderingClosest( std::vector<OrderingInfo> & infos, bool revfirst );
+void OrderingClosest(std::vector<OrderingInfo> &infos, bool revfirst);
// Global optimization of path length
-void OrderingAdvanced( std::vector<OrderingInfo> & infos, int nDims );
+void OrderingAdvanced(std::vector<OrderingInfo> &infos, int nDims);
} //LPEEmbroderyStitchOrdering
} //namespace LivePathEffect
diff --git a/src/live_effects/lpe-embrodery-stitch.cpp b/src/live_effects/lpe-embrodery-stitch.cpp
index e55d0b268..f2342032b 100644
--- a/src/live_effects/lpe-embrodery-stitch.cpp
+++ b/src/live_effects/lpe-embrodery-stitch.cpp
@@ -26,58 +26,58 @@ using namespace Geom;
using namespace LPEEmbroderyStitchOrdering;
static const Util::EnumData<LPEEmbroderyStitch::order_method> OrderMethodData[LPEEmbroderyStitch::order_method_count] = {
- { LPEEmbroderyStitch::order_method_no_reorder, N_("no reordering"), "no-reorder" },
- { LPEEmbroderyStitch::order_method_zigzag, N_("zig-zag"), "zig-zag" },
- { LPEEmbroderyStitch::order_method_zigzag_rev_first, N_("zig-zag, reverse first"), "zig-zag-rev-first" },
- { LPEEmbroderyStitch::order_method_closest, N_("closest"), "closest" },
- { LPEEmbroderyStitch::order_method_closest_rev_first, N_("closest, reverse first"), "closest-rev-first" },
- { LPEEmbroderyStitch::order_method_tsp_kopt_2, N_("traveling salesman 2-opt (fast, bad)"), "tsp-2opt" },
- { LPEEmbroderyStitch::order_method_tsp_kopt_3, N_("traveling salesman 3-opt (fast, ok)"), "tsp-3opt" },
- { LPEEmbroderyStitch::order_method_tsp_kopt_4, N_("traveling salesman 4-opt (seconds)"), "tsp-4opt" },
- { LPEEmbroderyStitch::order_method_tsp_kopt_5, N_("traveling salesman 5-opt (miutes)"), "tsp-5opt" }
+ { LPEEmbroderyStitch::order_method_no_reorder, N_("no reordering"), "no-reorder" },
+ { LPEEmbroderyStitch::order_method_zigzag, N_("zig-zag"), "zig-zag" },
+ { LPEEmbroderyStitch::order_method_zigzag_rev_first, N_("zig-zag, reverse first"), "zig-zag-rev-first" },
+ { LPEEmbroderyStitch::order_method_closest, N_("closest"), "closest" },
+ { LPEEmbroderyStitch::order_method_closest_rev_first, N_("closest, reverse first"), "closest-rev-first" },
+ { LPEEmbroderyStitch::order_method_tsp_kopt_2, N_("traveling salesman 2-opt (fast, bad)"), "tsp-2opt" },
+ { LPEEmbroderyStitch::order_method_tsp_kopt_3, N_("traveling salesman 3-opt (fast, ok)"), "tsp-3opt" },
+ { LPEEmbroderyStitch::order_method_tsp_kopt_4, N_("traveling salesman 4-opt (seconds)"), "tsp-4opt" },
+ { LPEEmbroderyStitch::order_method_tsp_kopt_5, N_("traveling salesman 5-opt (miutes)"), "tsp-5opt" }
};
static const Util::EnumDataConverter<LPEEmbroderyStitch::order_method>
- OrderMethodConverter(OrderMethodData, sizeof(OrderMethodData)/sizeof(*OrderMethodData));
+OrderMethodConverter(OrderMethodData, sizeof(OrderMethodData) / sizeof(*OrderMethodData));
static const Util::EnumData<LPEEmbroderyStitch::connect_method> ConnectMethodData[LPEEmbroderyStitch::connect_method_count] = {
- { LPEEmbroderyStitch::connect_method_line, N_("straight line"), "line" },
- { LPEEmbroderyStitch::connect_method_move_point_from, N_("move to begin"), "move-begin" },
- { LPEEmbroderyStitch::connect_method_move_point_mid, N_("move to middle"), "move-middle" },
- { LPEEmbroderyStitch::connect_method_move_point_to, N_("move to end"), "move-end" }
+ { LPEEmbroderyStitch::connect_method_line, N_("straight line"), "line" },
+ { LPEEmbroderyStitch::connect_method_move_point_from, N_("move to begin"), "move-begin" },
+ { LPEEmbroderyStitch::connect_method_move_point_mid, N_("move to middle"), "move-middle" },
+ { LPEEmbroderyStitch::connect_method_move_point_to, N_("move to end"), "move-end" }
};
static const Util::EnumDataConverter<LPEEmbroderyStitch::connect_method>
- ConnectMethodConverter(ConnectMethodData, sizeof(ConnectMethodData)/sizeof(*ConnectMethodData));
+ConnectMethodConverter(ConnectMethodData, sizeof(ConnectMethodData) / sizeof(*ConnectMethodData));
LPEEmbroderyStitch::LPEEmbroderyStitch(LivePathEffectObject *lpeobject) :
- Effect(lpeobject),
- ordering(_("Ordering method"), _("Method used to order sub paths"), "ordering", OrderMethodConverter, &wr, this, order_method_no_reorder),
- connection(_("Connection method"), _("Method to connect end points of sub paths"), "connection", ConnectMethodConverter, &wr, this, connect_method_line),
- stitch_length(_("Stitch length"), _("If not 0, linearize path with given step length"), "stitch-length", &wr, this, 10.0),
- stitch_min_length(_("Minimum stitch length [%]"), _("Combine steps shorter than this [%]"), "stitch-min-length", &wr, this, 25.0),
- stitch_pattern(_("Stitch pattern"), _("Select between different stitch patterns"), "stitch_pattern", &wr, this, 0),
- show_stitches(_("Show stitches"), _("Show stitches as small gaps (just for inspection - don't use for output)"), "show-stitches", &wr, this, false),
- show_stitch_gap(_("Show stitch gap"), _("Gap between stitches when showing stitches"), "show-stitch-gap", &wr, this, 0.5),
- jump_if_longer( _("Jump if longer"), _("Jump connection if longer than"), "jump-if-longer", &wr, this, 100)
+ Effect(lpeobject),
+ ordering(_("Ordering method"), _("Method used to order sub paths"), "ordering", OrderMethodConverter, &wr, this, order_method_no_reorder),
+ connection(_("Connection method"), _("Method to connect end points of sub paths"), "connection", ConnectMethodConverter, &wr, this, connect_method_line),
+ stitch_length(_("Stitch length"), _("If not 0, linearize path with given step length"), "stitch-length", &wr, this, 10.0),
+ stitch_min_length(_("Minimum stitch length [%]"), _("Combine steps shorter than this [%]"), "stitch-min-length", &wr, this, 25.0),
+ stitch_pattern(_("Stitch pattern"), _("Select between different stitch patterns"), "stitch_pattern", &wr, this, 0),
+ show_stitches(_("Show stitches"), _("Show stitches as small gaps (just for inspection - don't use for output)"), "show-stitches", &wr, this, false),
+ show_stitch_gap(_("Show stitch gap"), _("Gap between stitches when showing stitches"), "show-stitch-gap", &wr, this, 0.5),
+ jump_if_longer(_("Jump if longer"), _("Jump connection if longer than"), "jump-if-longer", &wr, this, 100)
{
- registerParameter( dynamic_cast<Parameter *>(&ordering) );
- registerParameter( dynamic_cast<Parameter *>(&connection) );
- registerParameter( dynamic_cast<Parameter *>(&stitch_length) );
- registerParameter( dynamic_cast<Parameter *>(&stitch_min_length) );
- registerParameter( dynamic_cast<Parameter *>(&stitch_pattern) );
- registerParameter( dynamic_cast<Parameter *>(&show_stitches) );
- registerParameter( dynamic_cast<Parameter *>(&show_stitch_gap) );
- registerParameter( dynamic_cast<Parameter *>(&jump_if_longer) );
-
- stitch_length.param_set_digits(1);
- stitch_length.param_set_range(1, 10000);
- stitch_min_length.param_set_digits(1);
- stitch_min_length.param_set_range(0, 100);
- stitch_pattern.param_make_integer();
- stitch_pattern.param_set_range(0, 2);
- show_stitch_gap.param_set_range(0.001, 10);
- jump_if_longer.param_set_range(0.0, 1000000);
+ registerParameter(dynamic_cast<Parameter *>(&ordering));
+ registerParameter(dynamic_cast<Parameter *>(&connection));
+ registerParameter(dynamic_cast<Parameter *>(&stitch_length));
+ registerParameter(dynamic_cast<Parameter *>(&stitch_min_length));
+ registerParameter(dynamic_cast<Parameter *>(&stitch_pattern));
+ registerParameter(dynamic_cast<Parameter *>(&show_stitches));
+ registerParameter(dynamic_cast<Parameter *>(&show_stitch_gap));
+ registerParameter(dynamic_cast<Parameter *>(&jump_if_longer));
+
+ stitch_length.param_set_digits(1);
+ stitch_length.param_set_range(1, 10000);
+ stitch_min_length.param_set_digits(1);
+ stitch_min_length.param_set_range(0, 100);
+ stitch_pattern.param_make_integer();
+ stitch_pattern.param_set_range(0, 2);
+ show_stitch_gap.param_set_range(0.001, 10);
+ jump_if_longer.param_set_range(0.0, 1000000);
}
LPEEmbroderyStitch::~LPEEmbroderyStitch()
@@ -85,303 +85,304 @@ LPEEmbroderyStitch::~LPEEmbroderyStitch()
}
-double LPEEmbroderyStitch::GetPatternInitialStep( int pattern, int line )
+double LPEEmbroderyStitch::GetPatternInitialStep(int pattern, int line)
{
- switch(pattern)
- {
- case 0:
- return 0.0;
-
- case 1:
- switch(line%4)
- {
- case 0: return 0.0;
- case 1: return 0.25;
- case 2: return 0.50;
- case 3: return 0.75;
- }
- return 0.0;
-
- case 2:
- switch(line%4)
- {
- case 0: return 0.0;
- case 1: return 0.5;
- case 2: return 0.75;
- case 3: return 0.25;
- }
- return 0.0;
-
- default:
- return 0.0;
- }
+ switch (pattern) {
+ case 0:
+ return 0.0;
+
+ case 1:
+ switch (line % 4) {
+ case 0:
+ return 0.0;
+ case 1:
+ return 0.25;
+ case 2:
+ return 0.50;
+ case 3:
+ return 0.75;
+ }
+ return 0.0;
+
+ case 2:
+ switch (line % 4) {
+ case 0:
+ return 0.0;
+ case 1:
+ return 0.5;
+ case 2:
+ return 0.75;
+ case 3:
+ return 0.25;
+ }
+ return 0.0;
+
+ default:
+ return 0.0;
+ }
}
-Point LPEEmbroderyStitch::GetStartPointInterpolAfterRev( std::vector<OrderingInfo> const & info, unsigned i)
+Point LPEEmbroderyStitch::GetStartPointInterpolAfterRev(std::vector<OrderingInfo> const &info, unsigned i)
{
- Point start_this = info[i].GetBegRev();
-
- if( i==0 )
- return start_this;
-
- if( !info[i-1].connect )
- return start_this;
-
- Point end_prev = info[i-1].GetEndRev();
-
- switch( connection.get_value() )
- {
- case connect_method_line: return start_this;
- case connect_method_move_point_from: return end_prev;
- case connect_method_move_point_mid: return 0.5*start_this+0.5*end_prev;
- case connect_method_move_point_to: return start_this;
- default: return start_this;
- }
+ Point start_this = info[i].GetBegRev();
+
+ if (i == 0) {
+ return start_this;
+ }
+
+ if (!info[i - 1].connect) {
+ return start_this;
+ }
+
+ Point end_prev = info[i - 1].GetEndRev();
+
+ switch (connection.get_value()) {
+ case connect_method_line:
+ return start_this;
+ case connect_method_move_point_from:
+ return end_prev;
+ case connect_method_move_point_mid:
+ return 0.5 * start_this + 0.5 * end_prev;
+ case connect_method_move_point_to:
+ return start_this;
+ default:
+ return start_this;
+ }
}
-Point LPEEmbroderyStitch::GetEndPointInterpolAfterRev( std::vector<OrderingInfo> const & info, unsigned i)
+Point LPEEmbroderyStitch::GetEndPointInterpolAfterRev(std::vector<OrderingInfo> const &info, unsigned i)
{
- Point end_this = info[i].GetEndRev();
-
- if( i+1==info.size() )
- return end_this;
-
- if( !info[i].connect )
- return end_this;
-
- Point start_next = info[i+1].GetBegRev();
-
- switch( connection.get_value() )
- {
- case connect_method_line: return end_this;
- case connect_method_move_point_from: return end_this;
- case connect_method_move_point_mid: return 0.5*start_next+0.5*end_this;
- case connect_method_move_point_to: return start_next;
- default: return end_this;
- }
+ Point end_this = info[i].GetEndRev();
+
+ if (i + 1 == info.size()) {
+ return end_this;
+ }
+
+ if (!info[i].connect) {
+ return end_this;
+ }
+
+ Point start_next = info[i + 1].GetBegRev();
+
+ switch (connection.get_value()) {
+ case connect_method_line:
+ return end_this;
+ case connect_method_move_point_from:
+ return end_this;
+ case connect_method_move_point_mid:
+ return 0.5 * start_next + 0.5 * end_this;
+ case connect_method_move_point_to:
+ return start_next;
+ default:
+ return end_this;
+ }
}
-Point LPEEmbroderyStitch::GetStartPointInterpolBeforeRev( std::vector<OrderingInfo> const & info, unsigned i)
+Point LPEEmbroderyStitch::GetStartPointInterpolBeforeRev(std::vector<OrderingInfo> const &info, unsigned i)
{
- if( info[i].reverse )
- return GetEndPointInterpolAfterRev( info, i);
- else
- return GetStartPointInterpolAfterRev( info, i);
+ if (info[i].reverse) {
+ return GetEndPointInterpolAfterRev(info, i);
+ } else {
+ return GetStartPointInterpolAfterRev(info, i);
+ }
}
-Point LPEEmbroderyStitch::GetEndPointInterpolBeforeRev( std::vector<OrderingInfo> const & info, unsigned i)
+Point LPEEmbroderyStitch::GetEndPointInterpolBeforeRev(std::vector<OrderingInfo> const &info, unsigned i)
{
- if( info[i].reverse )
- return GetStartPointInterpolAfterRev( info, i);
- else
- return GetEndPointInterpolAfterRev( info, i);
+ if (info[i].reverse) {
+ return GetStartPointInterpolAfterRev(info, i);
+ } else {
+ return GetEndPointInterpolAfterRev(info, i);
+ }
}
-PathVector LPEEmbroderyStitch::doEffect_path (PathVector const & path_in)
+PathVector LPEEmbroderyStitch::doEffect_path(PathVector const &path_in)
{
- if (path_in.size() >= 2) {
- PathVector path_out;
-
- // Create vectors with start and end points
- std::vector<OrderingInfo> orderinginfos( path_in.size() );
- // connect next path to this one
- bool connect_with_previous=false;
-
- for( PathVector::const_iterator it=path_in.begin(); it!=path_in.end(); ++it )
- {
- OrderingInfo &info = orderinginfos[ it-path_in.begin() ];
- info.index = it-path_in.begin();
- info.reverse = false;
- info.used = false;
- info.connect = true;
- info.begOrig = it->front().initialPoint();
- info.endOrig = it->back().finalPoint();
- }
-
- // Compute sub-path ordering
- switch( ordering.get_value() )
- {
- case order_method_no_reorder:
- OrderingOriginal( orderinginfos );
- break;
-
- case order_method_zigzag:
- OrderingZigZag( orderinginfos, false );
- break;
-
- case order_method_zigzag_rev_first:
- OrderingZigZag( orderinginfos, true );
- break;
-
- case order_method_closest:
- OrderingClosest( orderinginfos, false );
- break;
-
- case order_method_closest_rev_first:
- OrderingClosest( orderinginfos, true );
- break;
-
- case order_method_tsp_kopt_2:
- OrderingAdvanced( orderinginfos, 2 );
- break;
-
- case order_method_tsp_kopt_3:
- OrderingAdvanced( orderinginfos, 3 );
- break;
-
- case order_method_tsp_kopt_4:
- OrderingAdvanced( orderinginfos, 4 );
- break;
-
- case order_method_tsp_kopt_5:
- OrderingAdvanced( orderinginfos, 5 );
- break;
-
- }
-
- // Iterate over sub-paths in order found above
- // Divide paths into stitches (currently always equidistant)
- // Interpolate between neighboring paths, so that their ends coincide
- for( std::vector<OrderingInfo>::const_iterator it=orderinginfos.begin(); it!=orderinginfos.end(); ++it )
- {
- // info index
- unsigned iInfo = it-orderinginfos.begin();
- // subpath index
- unsigned iPath = it->index;
- // decide of path shall be reversed
- bool reverse = it->reverse;
- // minimum stitch length in absolute measure
- double stitch_min_length_abs = stitch_min_length*0.01*stitch_length;
-
- // convert path to piecewise
- Piecewise<D2<SBasis> > pwOrig = path_in[iPath].toPwSb();
- // make piecewise equidistant in time
- Piecewise<D2<SBasis> > pwEqdist = arc_length_parametrization(pwOrig);
- Piecewise<D2<SBasis> > pwStitch;
-
- // cut into stitches
- double cutpos=0.0;
- Interval pwdomain = pwEqdist.domain();
-
- // step length of first stitch
- double step = GetPatternInitialStep( stitch_pattern, iInfo )*stitch_length;
- if(step<stitch_min_length_abs)
- {
- step+=stitch_length;
- }
-
- bool last=false;
- bool first=true;
- double posnext;
- for(double pos=pwdomain.min(); !last; pos=posnext, cutpos+=1.0 )
- {
- // start point
- Point p1;
- if(first)
- {
- p1 = GetStartPointInterpolBeforeRev( orderinginfos, iInfo );
- first = false;
- }
- else
- {
- p1 = pwEqdist.valueAt(pos);
- }
-
- // end point of this stitch
- Point p2;
- posnext=pos+step;
- // last stitch is to end
- if(posnext>=pwdomain.max()-stitch_min_length_abs)
- {
- p2 = GetEndPointInterpolBeforeRev( orderinginfos, iInfo);
- last = true;
- }
- else
- {
- p2 = pwEqdist.valueAt(posnext);
- }
-
- pwStitch.push_cut(cutpos);
- pwStitch.push_seg( D2<SBasis>( SBasis(Linear(p1[X],p2[X])), SBasis(Linear(p1[Y],p2[Y])) ) );
-
- // stitch length for all except first step
- step = stitch_length;
- }
- pwStitch.push_cut(cutpos);
-
- if(reverse)
- {
- pwStitch = Geom::reverse(pwStitch);
- }
-
- if( it->connect && iInfo!= orderinginfos.size()-1 )
- {
- // Connect this segment with the previous segment by a straight line
- Point end = pwStitch.lastValue();
- Point start_next = GetStartPointInterpolAfterRev(orderinginfos, iInfo+1);
- // connect end and start point
- if( end != start_next && distance(end, start_next)<=jump_if_longer )
- {
- cutpos+=1.0;
- pwStitch.push_seg( D2<SBasis>( SBasis(Linear(end[X],start_next[X])), SBasis(Linear(end[Y],start_next[Y])) ) );
- pwStitch.push_cut(cutpos);
- }
- }
-
- if( show_stitches )
- {
- for( std::vector< D2<SBasis> >::iterator it=pwStitch.segs.begin(); it!=pwStitch.segs.end(); ++it )
- {
- // Create anew piecewise with just one segment
- Piecewise<D2<SBasis> > pwOne;
- pwOne.push_cut(0);
- pwOne.push_seg( *it );
- pwOne.push_cut(1);
-
- // make piecewise equidistant in time
- Piecewise<D2<SBasis> > pwOneEqdist = arc_length_parametrization(pwOne);
- Interval pwdomain = pwOneEqdist.domain();
-
- // Compute the points of teh shortened piece
- Coord len = pwdomain.max()-pwdomain.min();
- Coord offs = 0.5 * (show_stitch_gap < 0.5*len ? show_stitch_gap : 0.5*len );
- Point p1 = pwOneEqdist.valueAt(pwdomain.min()+offs);
- Point p2 = pwOneEqdist.valueAt(pwdomain.max()-offs);
- Piecewise<D2<SBasis> > pwOneGap;
-
- // Create Linear SBasis
- D2<SBasis> sbasis = D2<SBasis>( SBasis(Linear(p1[X],p2[X])), SBasis(Linear(p1[Y],p2[Y])) );
-
- // Convert to path and add to path list
- Geom::Path path=path_from_sbasis(sbasis , LPE_CONVERSION_TOLERANCE, false );
- path_out.push_back(path);
- }
- }
- else
- {
- PathVector pathv = path_from_piecewise(pwStitch, LPE_CONVERSION_TOLERANCE);
- for( size_t ipv=0; ipv<pathv.size(); ipv++)
- {
- if( connect_with_previous )
- path_out.back().append( pathv[ipv] );
- else
- path_out.push_back(pathv[ipv]);
- }
- }
-
- connect_with_previous = it->connect;
- }
-
- return path_out;
- } else {
- return path_in;
- }
+ if (path_in.size() >= 2) {
+ PathVector path_out;
+
+ // Create vectors with start and end points
+ std::vector<OrderingInfo> orderinginfos(path_in.size());
+ // connect next path to this one
+ bool connect_with_previous = false;
+
+ for (PathVector::const_iterator it = path_in.begin(); it != path_in.end(); ++it) {
+ OrderingInfo &info = orderinginfos[ it - path_in.begin() ];
+ info.index = it - path_in.begin();
+ info.reverse = false;
+ info.used = false;
+ info.connect = true;
+ info.begOrig = it->front().initialPoint();
+ info.endOrig = it->back().finalPoint();
+ }
+
+ // Compute sub-path ordering
+ switch (ordering.get_value()) {
+ case order_method_no_reorder:
+ OrderingOriginal(orderinginfos);
+ break;
+
+ case order_method_zigzag:
+ OrderingZigZag(orderinginfos, false);
+ break;
+
+ case order_method_zigzag_rev_first:
+ OrderingZigZag(orderinginfos, true);
+ break;
+
+ case order_method_closest:
+ OrderingClosest(orderinginfos, false);
+ break;
+
+ case order_method_closest_rev_first:
+ OrderingClosest(orderinginfos, true);
+ break;
+
+ case order_method_tsp_kopt_2:
+ OrderingAdvanced(orderinginfos, 2);
+ break;
+
+ case order_method_tsp_kopt_3:
+ OrderingAdvanced(orderinginfos, 3);
+ break;
+
+ case order_method_tsp_kopt_4:
+ OrderingAdvanced(orderinginfos, 4);
+ break;
+
+ case order_method_tsp_kopt_5:
+ OrderingAdvanced(orderinginfos, 5);
+ break;
+
+ }
+
+ // Iterate over sub-paths in order found above
+ // Divide paths into stitches (currently always equidistant)
+ // Interpolate between neighboring paths, so that their ends coincide
+ for (std::vector<OrderingInfo>::const_iterator it = orderinginfos.begin(); it != orderinginfos.end(); ++it) {
+ // info index
+ unsigned iInfo = it - orderinginfos.begin();
+ // subpath index
+ unsigned iPath = it->index;
+ // decide of path shall be reversed
+ bool reverse = it->reverse;
+ // minimum stitch length in absolute measure
+ double stitch_min_length_abs = stitch_min_length * 0.01 * stitch_length;
+
+ // convert path to piecewise
+ Piecewise<D2<SBasis> > pwOrig = path_in[iPath].toPwSb();
+ // make piecewise equidistant in time
+ Piecewise<D2<SBasis> > pwEqdist = arc_length_parametrization(pwOrig);
+ Piecewise<D2<SBasis> > pwStitch;
+
+ // cut into stitches
+ double cutpos = 0.0;
+ Interval pwdomain = pwEqdist.domain();
+
+ // step length of first stitch
+ double step = GetPatternInitialStep(stitch_pattern, iInfo) * stitch_length;
+ if (step < stitch_min_length_abs) {
+ step += stitch_length;
+ }
+
+ bool last = false;
+ bool first = true;
+ double posnext;
+ for (double pos = pwdomain.min(); !last; pos = posnext, cutpos += 1.0) {
+ // start point
+ Point p1;
+ if (first) {
+ p1 = GetStartPointInterpolBeforeRev(orderinginfos, iInfo);
+ first = false;
+ } else {
+ p1 = pwEqdist.valueAt(pos);
+ }
+
+ // end point of this stitch
+ Point p2;
+ posnext = pos + step;
+ // last stitch is to end
+ if (posnext >= pwdomain.max() - stitch_min_length_abs) {
+ p2 = GetEndPointInterpolBeforeRev(orderinginfos, iInfo);
+ last = true;
+ } else {
+ p2 = pwEqdist.valueAt(posnext);
+ }
+
+ pwStitch.push_cut(cutpos);
+ pwStitch.push_seg(D2<SBasis>(SBasis(Linear(p1[X], p2[X])), SBasis(Linear(p1[Y], p2[Y]))));
+
+ // stitch length for all except first step
+ step = stitch_length;
+ }
+ pwStitch.push_cut(cutpos);
+
+ if (reverse) {
+ pwStitch = Geom::reverse(pwStitch);
+ }
+
+ if (it->connect && iInfo != orderinginfos.size() - 1) {
+ // Connect this segment with the previous segment by a straight line
+ Point end = pwStitch.lastValue();
+ Point start_next = GetStartPointInterpolAfterRev(orderinginfos, iInfo + 1);
+ // connect end and start point
+ if (end != start_next && distance(end, start_next) <= jump_if_longer) {
+ cutpos += 1.0;
+ pwStitch.push_seg(D2<SBasis>(SBasis(Linear(end[X], start_next[X])), SBasis(Linear(end[Y], start_next[Y]))));
+ pwStitch.push_cut(cutpos);
+ }
+ }
+
+ if (show_stitches) {
+ for (std::vector< D2<SBasis> >::iterator it = pwStitch.segs.begin(); it != pwStitch.segs.end(); ++it) {
+ // Create anew piecewise with just one segment
+ Piecewise<D2<SBasis> > pwOne;
+ pwOne.push_cut(0);
+ pwOne.push_seg(*it);
+ pwOne.push_cut(1);
+
+ // make piecewise equidistant in time
+ Piecewise<D2<SBasis> > pwOneEqdist = arc_length_parametrization(pwOne);
+ Interval pwdomain = pwOneEqdist.domain();
+
+ // Compute the points of teh shortened piece
+ Coord len = pwdomain.max() - pwdomain.min();
+ Coord offs = 0.5 * (show_stitch_gap < 0.5 * len ? show_stitch_gap : 0.5 * len);
+ Point p1 = pwOneEqdist.valueAt(pwdomain.min() + offs);
+ Point p2 = pwOneEqdist.valueAt(pwdomain.max() - offs);
+ Piecewise<D2<SBasis> > pwOneGap;
+
+ // Create Linear SBasis
+ D2<SBasis> sbasis = D2<SBasis>(SBasis(Linear(p1[X], p2[X])), SBasis(Linear(p1[Y], p2[Y])));
+
+ // Convert to path and add to path list
+ Geom::Path path = path_from_sbasis(sbasis , LPE_CONVERSION_TOLERANCE, false);
+ path_out.push_back(path);
+ }
+ } else {
+ PathVector pathv = path_from_piecewise(pwStitch, LPE_CONVERSION_TOLERANCE);
+ for (size_t ipv = 0; ipv < pathv.size(); ipv++) {
+ if (connect_with_previous) {
+ path_out.back().append(pathv[ipv]);
+ } else {
+ path_out.push_back(pathv[ipv]);
+ }
+ }
+ }
+
+ connect_with_previous = it->connect;
+ }
+
+ return path_out;
+ } else {
+ return path_in;
+ }
}
void
-LPEEmbroderyStitch::resetDefaults(SPItem const* item)
+LPEEmbroderyStitch::resetDefaults(SPItem const *item)
{
- Effect::resetDefaults(item);
+ Effect::resetDefaults(item);
}
@@ -391,7 +392,7 @@ LPEEmbroderyStitch::resetDefaults(SPItem const* item)
* special casing is probably needed, because rotation should not be propagated to the strokepath.
*/
void
-LPEEmbroderyStitch::transform_multiply(Affine const& postmul, bool set)
+LPEEmbroderyStitch::transform_multiply(Affine const &postmul, bool set)
{
}
diff --git a/src/live_effects/lpe-embrodery-stitch.h b/src/live_effects/lpe-embrodery-stitch.h
index 1d4f9ab0e..67803f37b 100644
--- a/src/live_effects/lpe-embrodery-stitch.h
+++ b/src/live_effects/lpe-embrodery-stitch.h
@@ -26,33 +26,31 @@ public:
LPEEmbroderyStitch(LivePathEffectObject *lpeobject);
virtual ~LPEEmbroderyStitch();
- virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in);
+ virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in);
- virtual void resetDefaults(SPItem const* item);
+ virtual void resetDefaults(SPItem const *item);
- virtual void transform_multiply(Geom::Affine const& postmul, bool set);
+ virtual void transform_multiply(Geom::Affine const &postmul, bool set);
- enum order_method
- {
- order_method_no_reorder,
- order_method_zigzag,
- order_method_zigzag_rev_first,
- order_method_closest,
- order_method_closest_rev_first,
- order_method_tsp_kopt_2,
- order_method_tsp_kopt_3,
- order_method_tsp_kopt_4,
- order_method_tsp_kopt_5,
- order_method_count
- };
- enum connect_method
- {
- connect_method_line,
- connect_method_move_point_from,
- connect_method_move_point_mid,
- connect_method_move_point_to,
- connect_method_count
- };
+ enum order_method {
+ order_method_no_reorder,
+ order_method_zigzag,
+ order_method_zigzag_rev_first,
+ order_method_closest,
+ order_method_closest_rev_first,
+ order_method_tsp_kopt_2,
+ order_method_tsp_kopt_3,
+ order_method_tsp_kopt_4,
+ order_method_tsp_kopt_5,
+ order_method_count
+ };
+ enum connect_method {
+ connect_method_line,
+ connect_method_move_point_from,
+ connect_method_move_point_mid,
+ connect_method_move_point_to,
+ connect_method_count
+ };
private:
EnumParam<order_method> ordering;
@@ -64,14 +62,14 @@ private:
ScalarParam show_stitch_gap;
ScalarParam jump_if_longer;
- LPEEmbroderyStitch(const LPEEmbroderyStitch&);
- LPEEmbroderyStitch& operator=(const LPEEmbroderyStitch&);
+ LPEEmbroderyStitch(const LPEEmbroderyStitch &);
+ LPEEmbroderyStitch &operator=(const LPEEmbroderyStitch &);
- double GetPatternInitialStep( int pattern, int line );
- Geom::Point GetStartPointInterpolAfterRev( std::vector<OrderingInfo> const & info, unsigned i);
- Geom::Point GetEndPointInterpolAfterRev( std::vector<OrderingInfo> const & info, unsigned i);
- Geom::Point GetStartPointInterpolBeforeRev( std::vector<OrderingInfo> const & info, unsigned i);
- Geom::Point GetEndPointInterpolBeforeRev( std::vector<OrderingInfo> const & info, unsigned i);
+ double GetPatternInitialStep(int pattern, int line);
+ Geom::Point GetStartPointInterpolAfterRev(std::vector<OrderingInfo> const &info, unsigned i);
+ Geom::Point GetEndPointInterpolAfterRev(std::vector<OrderingInfo> const &info, unsigned i);
+ Geom::Point GetStartPointInterpolBeforeRev(std::vector<OrderingInfo> const &info, unsigned i);
+ Geom::Point GetEndPointInterpolBeforeRev(std::vector<OrderingInfo> const &info, unsigned i);
};
} //namespace LivePathEffect
diff --git a/src/live_effects/lpe-envelope.cpp b/src/live_effects/lpe-envelope.cpp
index e873c0b15..8528ab14d 100644
--- a/src/live_effects/lpe-envelope.cpp
+++ b/src/live_effects/lpe-envelope.cpp
@@ -5,22 +5,10 @@
*/
#include "live_effects/lpe-envelope.h"
-#include "sp-shape.h"
-#include "sp-item.h"
-#include "sp-path.h"
-#include "sp-item-group.h"
#include "display/curve.h"
-#include "svg/svg.h"
-#include "ui/widget/scalar.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
-#include <2geom/sbasis.h>
-#include <2geom/sbasis-geometric.h>
-#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/piecewise.h>
-
-#include <algorithm>
using std::vector;
namespace Inkscape {
@@ -35,12 +23,12 @@ LPEEnvelope::LPEEnvelope(LivePathEffectObject *lpeobject) :
xx(_("_Enable left & right paths"), _("Enable the left and right deformation paths"), "xx", &wr, this, true),
yy(_("_Enable top & bottom paths"), _("Enable the top and bottom deformation paths"), "yy", &wr, this, true)
{
- registerParameter( dynamic_cast<Parameter *>(&yy) );
- registerParameter( dynamic_cast<Parameter *>(&xx) );
- registerParameter( dynamic_cast<Parameter *>(&bend_path1) );
- registerParameter( dynamic_cast<Parameter *>(&bend_path2) );
- registerParameter( dynamic_cast<Parameter *>(&bend_path3) );
- registerParameter( dynamic_cast<Parameter *>(&bend_path4) );
+ registerParameter(&yy);
+ registerParameter(&xx);
+ registerParameter(&bend_path1);
+ registerParameter(&bend_path2);
+ registerParameter(&bend_path3);
+ registerParameter(&bend_path4);
concatenate_before_pwd2 = true;
apply_to_clippath_and_mask = true;
}
@@ -61,7 +49,7 @@ Geom::Piecewise<Geom::D2<Geom::SBasis> >
LPEEnvelope::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
{
- if(xx.get_value() == false && yy.get_value() == false)
+ if(!xx.get_value() && !yy.get_value())
{
return pwd2_in;
}
@@ -172,7 +160,7 @@ LPEEnvelope::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd
output_y = ybis*(compose((uskeleton1),x1) + y1*compose(n1,x1) )
+ y*(compose((uskeleton3),x3) + y3*compose(n3,x3) );
output_y /= (boundingbox_Y.extent());
- if(xx.get_value() == false && yy.get_value() == true)
+ if(!xx.get_value() && yy.get_value())
{
return output_y;
}
@@ -181,13 +169,13 @@ LPEEnvelope::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd
output_x = x*(compose((uskeleton2),y2) + -x2*compose(n2,y2) )
+ xbis*(compose((uskeleton4),y4) + -x4*compose(n4,y4) );
output_x /= (boundingbox_X.extent());
- if(xx.get_value() == true && yy.get_value() == false)
+ if(xx.get_value() && !yy.get_value())
{
return output_x;
}
/*output : Deformation by Up, Left, Right and Down Bend Paths*/
- if(xx.get_value() == true && yy.get_value() == true)
+ if(xx.get_value() && yy.get_value())
{
Piecewise<SBasis> xsqr = x*xbis; /* xsqr = x * (BBox_X - x) */
Piecewise<SBasis> ysqr = y*ybis; /* xsqr = y * (BBox_Y - y) */
diff --git a/src/live_effects/lpe-extrude.cpp b/src/live_effects/lpe-extrude.cpp
index 8b3f4714a..4a3ad7508 100644
--- a/src/live_effects/lpe-extrude.cpp
+++ b/src/live_effects/lpe-extrude.cpp
@@ -12,15 +12,10 @@
*/
#include "live_effects/lpe-extrude.h"
-
+#include "sp-item.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
-#include <2geom/path.h>
-#include <2geom/piecewise.h>
-#include <2geom/transforms.h>
-#include <algorithm>
-
-#include "sp-item.h"
namespace Inkscape {
namespace LivePathEffect {
@@ -32,7 +27,7 @@ LPEExtrude::LPEExtrude(LivePathEffectObject *lpeobject) :
show_orig_path = true;
concatenate_before_pwd2 = false;
- registerParameter( dynamic_cast<Parameter *>(&extrude_vector) );
+ registerParameter(&extrude_vector);
}
LPEExtrude::~LPEExtrude()
@@ -66,7 +61,7 @@ LPEExtrude::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2
using namespace Geom;
// generate connecting lines (the 'sides' of the extrusion)
- Path path(Point(0.,0.));
+ Geom::Path path(Point(0.,0.));
path.appendNew<Geom::LineSegment>( extrude_vector.getVector() );
Piecewise<D2<SBasis> > connector = path.toPwSb();
diff --git a/src/live_effects/lpe-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp
index 574ec3580..40fa91c68 100644
--- a/src/live_effects/lpe-fill-between-many.cpp
+++ b/src/live_effects/lpe-fill-between-many.cpp
@@ -4,17 +4,14 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <gtkmm/box.h>
#include "live_effects/lpe-fill-between-many.h"
#include "display/curve.h"
-#include "sp-item.h"
-#include "2geom/path.h"
#include "sp-shape.h"
#include "sp-text.h"
-#include "2geom/bezier-curve.h"
-
+#include "svg/svg.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
namespace Inkscape {
@@ -22,10 +19,18 @@ namespace LivePathEffect {
LPEFillBetweenMany::LPEFillBetweenMany(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
- linked_paths(_("Linked path:"), _("Paths from which to take the original path data"), "linkedpaths", &wr, this)
+ linked_paths(_("Linked path:"), _("Paths from which to take the original path data"), "linkedpaths", &wr, this),
+ fuse(_("Fuse coincident points"), _("Fuse coincident points"), "fuse", &wr, this, false),
+ allow_transforms(_("Allow transforms"), _("Allow transforms"), "allow_transforms", &wr, this, false),
+ join(_("Join subpaths"), _("Join subpaths"), "join", &wr, this, true),
+ close(_("Close"), _("Close path"), "close", &wr, this, true)
{
- registerParameter( dynamic_cast<Parameter *>(&linked_paths) );
- //perceived_path = true;
+ registerParameter(&linked_paths);
+ registerParameter(&fuse);
+ registerParameter(&allow_transforms);
+ registerParameter(&join);
+ registerParameter(&close);
+ transformmultiply = false;
}
LPEFillBetweenMany::~LPEFillBetweenMany()
@@ -47,22 +52,50 @@ void LPEFillBetweenMany::doEffect (SPCurve * curve)
linked_path = (*iter)->_pathvector.front();
}
- if (!res_pathv.empty()) {
+ if (!res_pathv.empty() && join) {
linked_path = linked_path * SP_ITEM(obj)->getRelativeTransform(firstObj);
- res_pathv.front().appendNew<Geom::LineSegment>(linked_path.initialPoint());
+ if (!are_near(res_pathv.front().finalPoint(), linked_path.initialPoint(), 0.01) || !fuse) {
+ res_pathv.front().appendNew<Geom::LineSegment>(linked_path.initialPoint());
+ } else {
+ linked_path.setInitial(res_pathv.front().finalPoint());
+ }
res_pathv.front().append(linked_path);
} else {
firstObj = SP_ITEM(obj);
+ if (close && !join) {
+ linked_path.close();
+ }
res_pathv.push_back(linked_path);
}
}
}
- if (!res_pathv.empty()) {
+ if (!res_pathv.empty() && close) {
res_pathv.front().close();
}
+ if (res_pathv.empty()) {
+ res_pathv = curve->get_pathvector();
+ }
+ if(!allow_transforms && !transformmultiply) {
+ Geom::Affine affine = Geom::identity();
+ sp_svg_transform_read(SP_ITEM(sp_lpe_item)->getAttribute("transform"), &affine);
+ res_pathv *= affine.inverse();
+ }
+ if(transformmultiply) {
+ transformmultiply = false;
+ }
curve->set_pathvector(res_pathv);
}
+void
+LPEFillBetweenMany::transform_multiply(Geom::Affine const& postmul, bool set)
+{
+ if(!allow_transforms && sp_lpe_item) {
+ SP_ITEM(sp_lpe_item)->transform *= postmul.inverse();
+ transformmultiply = true;
+ sp_lpe_item_update_patheffect(sp_lpe_item, false, false);
+ }
+}
+
} // namespace LivePathEffect
} /* namespace Inkscape */
diff --git a/src/live_effects/lpe-fill-between-many.h b/src/live_effects/lpe-fill-between-many.h
index 99ee8b15f..fe824e936 100644
--- a/src/live_effects/lpe-fill-between-many.h
+++ b/src/live_effects/lpe-fill-between-many.h
@@ -19,12 +19,16 @@ class LPEFillBetweenMany : public Effect {
public:
LPEFillBetweenMany(LivePathEffectObject *lpeobject);
virtual ~LPEFillBetweenMany();
-
+ virtual void transform_multiply(Geom::Affine const& postmul, bool set);
virtual void doEffect (SPCurve * curve);
private:
OriginalPathArrayParam linked_paths;
-
+ BoolParam fuse;
+ BoolParam allow_transforms;
+ BoolParam join;
+ BoolParam close;
+ bool transformmultiply;
private:
LPEFillBetweenMany(const LPEFillBetweenMany&);
LPEFillBetweenMany& operator=(const LPEFillBetweenMany&);
diff --git a/src/live_effects/lpe-fill-between-strokes.cpp b/src/live_effects/lpe-fill-between-strokes.cpp
index 89ea80545..f8d86ae99 100644
--- a/src/live_effects/lpe-fill-between-strokes.cpp
+++ b/src/live_effects/lpe-fill-between-strokes.cpp
@@ -3,17 +3,14 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-fill-between-strokes.h"
#include "display/curve.h"
-#include "sp-item.h"
-#include "2geom/path.h"
#include "sp-shape.h"
#include "sp-text.h"
-#include "2geom/bezier-curve.h"
+#include "svg/svg.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -22,12 +19,20 @@ LPEFillBetweenStrokes::LPEFillBetweenStrokes(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this),
second_path(_("Second path:"), _("Second path from which to take the original path data"), "secondpath", &wr, this),
- reverse_second(_("Reverse Second"), _("Reverses the second path order"), "reversesecond", &wr, this)
+ reverse_second(_("Reverse Second"), _("Reverses the second path order"), "reversesecond", &wr, this),
+ fuse(_("Fuse coincident points"), _("Fuse coincident points"), "fuse", &wr, this, false),
+ allow_transforms(_("Allow transforms"), _("Allow transforms"), "allow_transforms", &wr, this, false),
+ join(_("Join subpaths"), _("Join subpaths"), "join", &wr, this, true),
+ close(_("Close"), _("Close path"), "close", &wr, this, true)
{
- registerParameter( dynamic_cast<Parameter *>(&linked_path) );
- registerParameter( dynamic_cast<Parameter *>(&second_path) );
- registerParameter( dynamic_cast<Parameter *>(&reverse_second) );
- //perceived_path = true;
+ registerParameter(&linked_path);
+ registerParameter(&second_path);
+ registerParameter(&reverse_second);
+ registerParameter(&fuse);
+ registerParameter(&allow_transforms);
+ registerParameter(&join);
+ registerParameter(&close);
+ transformmultiply = false;
}
LPEFillBetweenStrokes::~LPEFillBetweenStrokes()
@@ -38,6 +43,13 @@ LPEFillBetweenStrokes::~LPEFillBetweenStrokes()
void LPEFillBetweenStrokes::doEffect (SPCurve * curve)
{
if (curve) {
+ Geom::Affine affine = Geom::identity();
+ if(!allow_transforms && !transformmultiply) {
+ sp_svg_transform_read(SP_ITEM(sp_lpe_item)->getAttribute("transform"), &affine);
+ }
+ if(transformmultiply) {
+ transformmultiply = false;
+ }
if ( linked_path.linksToPath() && second_path.linksToPath() && linked_path.getObject() && second_path.getObject() ) {
Geom::PathVector linked_pathv = linked_path.get_pathvector();
Geom::PathVector second_pathv = second_path.get_pathvector();
@@ -55,22 +67,33 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve)
}
if ( !result_linked_pathv.empty() && !result_second_pathv.empty() && !result_linked_pathv.front().closed() ) {
- if (reverse_second.get_value())
- {
- result_linked_pathv.front().appendNew<Geom::LineSegment>(result_second_pathv.front().finalPoint());
- result_linked_pathv.front().append(result_second_pathv.front().reversed());
+ if (reverse_second.get_value()) {
+ result_second_pathv.front() = result_second_pathv.front().reversed();
}
- else
- {
- result_linked_pathv.front().appendNew<Geom::LineSegment>(result_second_pathv.front().initialPoint());
+ if (join) {
+ if (!are_near(result_linked_pathv.front().finalPoint(), result_second_pathv.front().initialPoint(),0.01) || !fuse) {
+ result_linked_pathv.front().appendNew<Geom::LineSegment>(result_second_pathv.front().initialPoint());
+ } else {
+ result_second_pathv.front().setInitial(result_linked_pathv.front().finalPoint());
+ }
result_linked_pathv.front().append(result_second_pathv.front());
+ if (close) {
+ result_linked_pathv.front().close();
+ }
+ } else {
+ if (close) {
+ result_linked_pathv.front().close();
+ result_second_pathv.front().close();
+ }
+ result_linked_pathv.push_back(result_second_pathv.front());
}
+ result_linked_pathv *= affine.inverse();
curve->set_pathvector(result_linked_pathv);
- }
- else if ( !result_linked_pathv.empty() ) {
+ } else if ( !result_linked_pathv.empty() ) {
+ result_linked_pathv *= affine.inverse();
curve->set_pathvector(result_linked_pathv);
- }
- else if ( !result_second_pathv.empty() ) {
+ } else if ( !result_second_pathv.empty() ) {
+ result_second_pathv *= affine.inverse();
curve->set_pathvector(result_second_pathv);
}
}
@@ -83,6 +106,10 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve)
result_pathv.push_back((*iter));
}
if ( !result_pathv.empty() ) {
+ result_pathv *= affine.inverse();
+ if (close) {
+ result_pathv.front().close();
+ }
curve->set_pathvector(result_pathv);
}
}
@@ -95,12 +122,26 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve)
result_pathv.push_back((*iter));
}
if ( !result_pathv.empty() ) {
+ result_pathv *= affine.inverse();
+ if (close) {
+ result_pathv.front().close();
+ }
curve->set_pathvector(result_pathv);
}
}
}
}
+void
+LPEFillBetweenStrokes::transform_multiply(Geom::Affine const& postmul, bool set)
+{
+ if(!allow_transforms && sp_lpe_item) {
+ SP_ITEM(sp_lpe_item)->transform *= postmul.inverse();
+ transformmultiply = true;
+ sp_lpe_item_update_patheffect(sp_lpe_item, false, false);
+ }
+}
+
} // namespace LivePathEffect
} /* namespace Inkscape */
diff --git a/src/live_effects/lpe-fill-between-strokes.h b/src/live_effects/lpe-fill-between-strokes.h
index ec57b1852..5bbd6e7da 100644
--- a/src/live_effects/lpe-fill-between-strokes.h
+++ b/src/live_effects/lpe-fill-between-strokes.h
@@ -19,13 +19,18 @@ class LPEFillBetweenStrokes : public Effect {
public:
LPEFillBetweenStrokes(LivePathEffectObject *lpeobject);
virtual ~LPEFillBetweenStrokes();
-
+ virtual void transform_multiply(Geom::Affine const& postmul, bool set);
virtual void doEffect (SPCurve * curve);
private:
OriginalPathParam linked_path;
OriginalPathParam second_path;
BoolParam reverse_second;
+ BoolParam fuse;
+ BoolParam allow_transforms;
+ BoolParam join;
+ BoolParam close;
+ bool transformmultiply;
private:
LPEFillBetweenStrokes(const LPEFillBetweenStrokes&);
diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp
index 07760b172..11298bcbe 100644
--- a/src/live_effects/lpe-fillet-chamfer.cpp
+++ b/src/live_effects/lpe-fillet-chamfer.cpp
@@ -4,91 +4,158 @@
*
* Copyright (C) 2014 Author(s)
*
- * Special thanks to Johan Engelen for the base of the effect -powerstroke-
- * Also to ScislaC for point me to the idea
- * Also su_v for his construvtive feedback and time
- * Also to Mc- (IRC nick) for his important contribution to find real time
- * values based on
- * and finaly to Liam P. White for his big help on coding, that save me a lot of hours
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "live_effects/lpe-fillet-chamfer.h"
-
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/elliptical-arc.h>
-#include <2geom/line.h>
-#include "desktop.h"
+#include "live_effects/lpe-fillet-chamfer.h"
+#include "helper/geom.h"
#include "display/curve.h"
-#include "helper/geom-nodetype.h"
#include "helper/geom-curves.h"
-#include "helper/geom.h"
-
-#include "live_effects/parameter/filletchamferpointarray.h"
-
-// for programmatically updating knots
-#include "ui/tools-switch.h"
+#include "helper/geom-satellite.h"
+#include <2geom/elliptical-arc.h>
+#include "knotholder.h"
+#include <boost/optional.hpp>
// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
-using namespace Geom;
namespace Inkscape {
namespace LivePathEffect {
-static const Util::EnumData<FilletMethod> FilletMethodData[FM_END] = {
- { FM_AUTO, N_("Auto"), "auto" },
+static const Util::EnumData<Filletmethod> FilletmethodData[] = {
+ { FM_AUTO, N_("Auto"), "auto" },
{ FM_ARC, N_("Force arc"), "arc" },
{ FM_BEZIER, N_("Force bezier"), "bezier" }
};
-static const Util::EnumDataConverter<FilletMethod>
-FMConverter(FilletMethodData, FM_END);
-
-const double tolerance = 0.001;
-const double gapHelper = 0.00001;
-
-LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) :
- Effect(lpeobject),
- fillet_chamfer_values(_("Fillet point"), _("Fillet point"), "fillet_chamfer_values", &wr, this),
- hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, false),
- ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), "ignore_radius_0", &wr, this, false),
- only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false),
- flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false),
- use_knot_distance(_("Use knots distance instead radius"), _("Use knots distance instead radius"), "use_knot_distance", &wr, this, false),
- method(_("Method:"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO),
- radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr, this, 0.),
- chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps", &wr, this, 0),
-
- helper_size(_("Helper size with direction:"), _("Helper size with direction"), "helper_size", &wr, this, 0)
+static const Util::EnumDataConverter<Filletmethod> FMConverter(FilletmethodData, FM_END);
+
+LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject)
+ : Effect(lpeobject),
+ unit(_("Unit"), _("Unit"), "unit", &wr, this, "px"),
+ satellites_param("Satellites_param", "Satellites_param",
+ "satellites_param", &wr, this),
+ method(_("Method:"), _("Methods to calculate the fillet or chamfer"),
+ "method", FMConverter, &wr, this, FM_AUTO),
+ mode(_("Mode:"), _("Mode, fillet or chamfer"),
+ "mode", &wr, this, "F", true),
+ radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr,
+ this, 0.0),
+ chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps",
+ &wr, this, 1),
+ flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"),
+ "flexible", &wr, this, false),
+ mirror_knots(_("Mirror Knots"), _("Mirror Knots"), "mirror_knots", &wr,
+ this, true),
+ only_selected(_("Change only selected nodes"),
+ _("Change only selected nodes"), "only_selected", &wr, this,
+ false),
+ use_knot_distance(_("Use knots distance instead radius"),
+ _("Use knots distance instead radius"),
+ "use_knot_distance", &wr, this, false),
+ hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this,
+ false),
+ apply_no_radius(_("Apply changes if radius = 0"), _("Apply changes if radius = 0"), "apply_no_radius", &wr, this, true),
+ apply_with_radius(_("Apply changes if radius > 0"), _("Apply changes if radius > 0"), "apply_with_radius", &wr, this, true),
+ helper_size(_("Helper path size with direction to node:"),
+ _("Helper path size with direction to node"), "helper_size", &wr, this, 0),
+ _pathvector_satellites(NULL),
+ _degenerate_hide(false)
{
- registerParameter(&fillet_chamfer_values);
+ registerParameter(&satellites_param);
+ registerParameter(&unit);
registerParameter(&method);
+ registerParameter(&mode);
registerParameter(&radius);
registerParameter(&chamfer_steps);
registerParameter(&helper_size);
registerParameter(&flexible);
registerParameter(&use_knot_distance);
- registerParameter(&ignore_radius_0);
+ registerParameter(&mirror_knots);
+ registerParameter(&apply_no_radius);
+ registerParameter(&apply_with_radius);
registerParameter(&only_selected);
registerParameter(&hide_knots);
- radius.param_set_range(0., infinity());
+ radius.param_set_range(0.0, Geom::infinity());
radius.param_set_increments(1, 1);
radius.param_set_digits(4);
- radius.param_overwrite_widget(true);
+ radius.param_set_undo(false);
chamfer_steps.param_set_range(1, 999);
chamfer_steps.param_set_increments(1, 1);
chamfer_steps.param_set_digits(0);
- chamfer_steps.param_overwrite_widget(true);
- helper_size.param_set_range(0, infinity());
+ helper_size.param_set_range(0, 999);
helper_size.param_set_increments(5, 5);
helper_size.param_set_digits(0);
- helper_size.param_overwrite_widget(true);
- fillet_chamfer_values.set_chamfer_steps(3);
+ _provides_knotholder_entities = true;
}
-LPEFilletChamfer::~LPEFilletChamfer() {}
+void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem)
+{
+ SPLPEItem *splpeitem = const_cast<SPLPEItem *>(lpeItem);
+ SPShape *shape = dynamic_cast<SPShape *>(splpeitem);
+ if (shape) {
+ Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(shape->getCurve()->get_pathvector());
+ Satellites satellites;
+ double power = radius;
+ std::cout << power << "power\n";
+ if (!flexible) {
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ SPNamedView *nv = sp_document_namedview(document, NULL);
+ Glib::ustring display_unit = nv->display_units->abbr;
+ power = Inkscape::Util::Quantity::convert(power, unit.get_abbreviation(), display_unit.c_str());
+ }
+ std::cout << power << "power22222222\n";
+ SatelliteType satellite_type = FILLET;
+ std::map<std::string, SatelliteType> gchar_map_to_satellite_type =
+ boost::assign::map_list_of("F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE);
+ std::map<std::string, SatelliteType>::iterator it = gchar_map_to_satellite_type.find(std::string(mode.param_getSVGValue()));
+ if (it != gchar_map_to_satellite_type.end()) {
+ satellite_type = it->second;
+ }
+ for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
+ if (path_it->empty()) {
+ continue;
+ }
+ std::vector<Satellite> subpath_satellites;
+ for (Geom::Path::const_iterator curve_it = path_it->begin(); curve_it != path_it->end(); ++curve_it) {
+ //Maybe we want this satellites...
+ //if (curve_it->isDegenerate()) {
+ // continue
+ //}
+ Satellite satellite(satellite_type);
+ satellite.setSteps(chamfer_steps);
+ satellite.setAmount(power);
+ satellite.setIsTime(flexible);
+ satellite.setHasMirror(mirror_knots);
+ satellite.setHidden(hide_knots);
+ subpath_satellites.push_back(satellite);
+ }
+ //we add the last satellite on open path because _pathvector_satellites is related to nodes, not curves
+ //so maybe in the future we can need this last satellite in other effects
+ //dont remove for this effect because _pathvector_satellites class has methods when the path is modiffied
+ //and we want one method for all uses
+ if (!path_it->closed()) {
+ Satellite satellite(satellite_type);
+ satellite.setSteps(chamfer_steps);
+ satellite.setAmount(power);
+ satellite.setIsTime(flexible);
+ satellite.setHasMirror(mirror_knots);
+ satellite.setHidden(hide_knots);
+ subpath_satellites.push_back(satellite);
+ }
+ satellites.push_back(subpath_satellites);
+ }
+ _pathvector_satellites = new PathVectorSatellites();
+ _pathvector_satellites->setPathVector(pathv);
+ _pathvector_satellites->setSatellites(satellites);
+ satellites_param.setPathVectorSatellites(_pathvector_satellites);
+ } else {
+ g_warning("LPE Fillet/Chamfer can only be applied to shapes (not groups).");
+ SPLPEItem *item = const_cast<SPLPEItem *>(lpeItem);
+ item->removeCurrentPathEffect(false);
+ }
+}
Gtk::Widget *LPEFilletChamfer::newWidget()
{
@@ -99,54 +166,50 @@ Gtk::Widget *LPEFilletChamfer::newWidget()
vbox->set_border_width(5);
vbox->set_homogeneous(false);
vbox->set_spacing(2);
- Gtk::HBox *advertaising = Gtk::manage(new Gtk::HBox(true, 0));
- Gtk::Button *advert = Gtk::manage(new Gtk::Button(Glib::ustring(_("IMPORTANT! New version soon..."))));
- advertaising->pack_start(*advert, true, true, 2);
- vbox->pack_start(*advertaising, true, true, 2);
- Gtk::HBox *advertaising2 = Gtk::manage(new Gtk::HBox(true, 0));
- Gtk::Button *advert2 = Gtk::manage(new Gtk::Button(Glib::ustring(_("Not compatible. Convert to path after."))));
- advertaising2->pack_start(*advert2, true, true, 2);
- vbox->pack_start(*advertaising2, true, true, 2);
std::vector<Parameter *>::iterator it = param_vector.begin();
while (it != param_vector.end()) {
if ((*it)->widget_is_visible) {
Parameter *param = *it;
Gtk::Widget *widg = param->param_newWidget();
if (param->param_key == "radius") {
- Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
- widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::updateFillet));
- widg = widgRegistered;
+ Inkscape::UI::Widget::Scalar *widg_registered =
+ Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
+ widg_registered->signal_value_changed().connect(
+ sigc::mem_fun(*this, &LPEFilletChamfer::updateAmount));
+ widg = widg_registered;
if (widg) {
- Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg);
- std::vector<Gtk::Widget *> childList = scalarParameter->get_children();
- Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);
- entryWidg->set_width_chars(6);
+ Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg);
+ std::vector<Gtk::Widget *> childList = scalar_parameter->get_children();
+ Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]);
+ entry_widget->set_width_chars(6);
}
+// } else if (param->param_key == "unit") {
+// Inkscape::UI::Widget::RegisteredUnitMenu* widg_registered =
+// Gtk::manage(dynamic_cast< Inkscape::UI::Widget::RegisteredUnitMenu *>(widg));
+// widg_registered->setUnit(unit.get_abbreviation());
+// widg_registered->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change unit parameter"));
+// widg_registered->getUnitMenu()->signal_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::convertUnit));
+// widg = widg_registered;
} else if (param->param_key == "chamfer_steps") {
- Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
- widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamferSubdivisions));
- widg = widgRegistered;
+ Inkscape::UI::Widget::Scalar *widg_registered =
+ Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
+ widg_registered->signal_value_changed().connect(
+ sigc::mem_fun(*this, &LPEFilletChamfer::updateChamferSteps));
+ widg = widg_registered;
if (widg) {
- Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg);
- std::vector<Gtk::Widget *> childList = scalarParameter->get_children();
- Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);
- entryWidg->set_width_chars(3);
+ Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg);
+ std::vector<Gtk::Widget *> childList = scalar_parameter->get_children();
+ Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]);
+ entry_widget->set_width_chars(3);
}
- } else if (param->param_key == "flexible") {
- Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
- widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleFlexFixed));
} else if (param->param_key == "helper_size") {
- Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
- widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots));
- } else if (param->param_key == "hide_knots") {
- Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
- widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleHide));
+ Inkscape::UI::Widget::Scalar *widg_registered =
+ Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
+ widg_registered->signal_value_changed().connect(
+ sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots));
} else if (param->param_key == "only_selected") {
Gtk::manage(widg);
- } else if (param->param_key == "ignore_radius_0") {
- Gtk::manage(widg);
}
-
Glib::ustring *tip = param->param_getTooltip();
if (widg) {
vbox->pack_start(*widg, true, true, 2);
@@ -158,504 +221,407 @@ Gtk::Widget *LPEFilletChamfer::newWidget()
}
}
}
-
++it;
}
- Gtk::HBox *filletContainer = Gtk::manage(new Gtk::HBox(true, 0));
- Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet"))));
- fillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet));
- filletContainer->pack_start(*fillet, true, true, 2);
- Gtk::Button *inverseFillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet"))));
- inverseFillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseFillet));
- filletContainer->pack_start(*inverseFillet, true, true, 2);
-
- Gtk::HBox *chamferContainer = Gtk::manage(new Gtk::HBox(true, 0));
+ Gtk::HBox *fillet_container = Gtk::manage(new Gtk::HBox(true, 0));
+ Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet"))));
+ fillet->signal_clicked()
+ .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),FILLET));
+
+ fillet_container->pack_start(*fillet, true, true, 2);
+ Gtk::Button *inverse_fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet"))));
+ inverse_fillet->signal_clicked()
+ .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_FILLET));
+ fillet_container->pack_start(*inverse_fillet, true, true, 2);
+
+ Gtk::HBox *chamfer_container = Gtk::manage(new Gtk::HBox(true, 0));
Gtk::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer"))));
- chamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer));
+ chamfer->signal_clicked()
+ .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),CHAMFER));
- chamferContainer->pack_start(*chamfer, true, true, 2);
- Gtk::Button *inverseChamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer"))));
- inverseChamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseChamfer));
- chamferContainer->pack_start(*inverseChamfer, true, true, 2);
+ chamfer_container->pack_start(*chamfer, true, true, 2);
+ Gtk::Button *inverse_chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer"))));
+ inverse_chamfer->signal_clicked()
+ .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_CHAMFER));
+ chamfer_container->pack_start(*inverse_chamfer, true, true, 2);
- vbox->pack_start(*filletContainer, true, true, 2);
- vbox->pack_start(*chamferContainer, true, true, 2);
+ vbox->pack_start(*fillet_container, true, true, 2);
+ vbox->pack_start(*chamfer_container, true, true, 2);
return vbox;
}
-void LPEFilletChamfer::toggleHide()
-{
- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
- std::vector<Geom::Point> result;
- for (std::vector<Point>::const_iterator point_it = filletChamferData.begin();
- point_it != filletChamferData.end(); ++point_it) {
- if (hide_knots) {
- result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y]) * -1));
- } else {
- result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y])));
- }
- }
- fillet_chamfer_values.param_set_and_write_new_value(result);
- refreshKnots();
-}
-
-void LPEFilletChamfer::toggleFlexFixed()
+void LPEFilletChamfer::refreshKnots()
{
- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
- std::vector<Geom::Point> result;
- unsigned int i = 0;
- for (std::vector<Point>::const_iterator point_it = filletChamferData.begin();
- point_it != filletChamferData.end(); ++point_it) {
- if (flexible) {
- result.push_back(Point(fillet_chamfer_values.to_time(i, (*point_it)[X]),
- (*point_it)[Y]));
- } else {
- result.push_back(Point(fillet_chamfer_values.to_len(i, (*point_it)[X]),
- (*point_it)[Y]));
- }
- i++;
+ if (satellites_param._knoth) {
+ satellites_param._knoth->update_knots();
}
- if (flexible) {
- radius.param_set_range(0., 100);
- radius.param_set_value(0);
- } else {
- radius.param_set_range(0., infinity());
- radius.param_set_value(0);
- }
- fillet_chamfer_values.param_set_and_write_new_value(result);
}
-void LPEFilletChamfer::updateFillet()
+void LPEFilletChamfer::updateAmount()
{
- double power = 0;
+ setSelected(_pathvector_satellites);
+ double power = radius;
if (!flexible) {
- power = radius * -1;
- } else {
- power = radius;
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ SPNamedView *nv = sp_document_namedview(document, NULL);
+ Glib::ustring display_unit = nv->display_units->abbr;
+ power = Inkscape::Util::Quantity::convert(power, unit.get_abbreviation(), display_unit.c_str());
}
- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
- doUpdateFillet(path_from_piecewise(pwd2, tolerance), power);
- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
+ _pathvector_satellites->updateAmount(power, apply_no_radius, apply_with_radius, only_selected,
+ use_knot_distance, flexible);
+ satellites_param.setPathVectorSatellites(_pathvector_satellites);
}
-void LPEFilletChamfer::fillet()
-{
- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
- doChangeType(path_from_piecewise(pwd2, tolerance), 1);
- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to fillet"));
-}
-
-void LPEFilletChamfer::inverseFillet()
-{
- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
- doChangeType(path_from_piecewise(pwd2, tolerance), 2);
- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet"));
-}
+//void LPEFilletChamfer::convertUnit()
+//{
+// SPDocument * document = SP_ACTIVE_DOCUMENT;
+// SPNamedView *nv = sp_document_namedview(document, NULL);
+// Glib::ustring display_unit = nv->display_units->abbr;
+// _pathvector_satellites->convertUnit(unit.get_abbreviation(), display_unit, apply_no_radius, apply_with_radius);
+// satellites_param.setPathVectorSatellites(_pathvector_satellites);
+//}
-void LPEFilletChamfer::chamferSubdivisions()
+void LPEFilletChamfer::updateChamferSteps()
{
- fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
- doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 5000);
- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
+ setSelected(_pathvector_satellites);
+ _pathvector_satellites->updateSteps(chamfer_steps, apply_no_radius, apply_with_radius, only_selected);
+ satellites_param.setPathVectorSatellites(_pathvector_satellites);
}
-void LPEFilletChamfer::chamfer()
+void LPEFilletChamfer::updateSatelliteType(SatelliteType satellitetype)
{
- fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
- doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3000);
- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to chamfer"));
+ std::map<SatelliteType, gchar const *> satellite_type_to_gchar_map =
+ boost::assign::map_list_of(FILLET, "F")(INVERSE_FILLET, "IF")(CHAMFER, "C")(INVERSE_CHAMFER, "IC")(INVALID_SATELLITE, "KO");
+ mode.param_setValue((Glib::ustring)satellite_type_to_gchar_map.at(satellitetype));
+ setSelected(_pathvector_satellites);
+ _pathvector_satellites->updateSatelliteType(satellitetype, apply_no_radius, apply_with_radius, only_selected);
+ satellites_param.setPathVectorSatellites(_pathvector_satellites);
}
-void LPEFilletChamfer::inverseChamfer()
-{
- fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
- doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 4000);
- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet"));
-}
-
-void LPEFilletChamfer::refreshKnots()
-{
- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
- fillet_chamfer_values.recalculate_knots(pwd2);
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
- if (tools_isactive(desktop, TOOLS_NODES)) {
- tools_switch(desktop, TOOLS_SELECT);
- tools_switch(desktop, TOOLS_NODES);
- }
- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Knots and helper paths refreshed"));
-}
-
-void LPEFilletChamfer::doUpdateFillet(Geom::PathVector const &original_pathv, double power)
-{
- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
- std::vector<Geom::Point> result;
- Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv);
- int counter = 0;
- for (PathVector::const_iterator path_it = original_pathv_processed.begin();
- path_it != original_pathv_processed.end(); ++path_it) {
- if (path_it->empty())
- continue;
-
- 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();
- if (path_it->closed() && path_it->back_closed().isDegenerate()) {
- const Curve &closingline = path_it->back_closed();
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- curve_endit = path_it->end_open();
- }
- }
- double powerend = 0;
- while (curve_it1 != curve_endit) {
- powerend = power;
- if (power < 0 && !use_knot_distance) {
- powerend = fillet_chamfer_values.rad_to_len(counter,powerend);
- }
- if (power > 0) {
- powerend = counter + (power / 100);
- }
- if (ignore_radius_0 && (filletChamferData[counter][X] == 0 ||
- filletChamferData[counter][X] == counter)) {
- powerend = filletChamferData[counter][X];
- }
- if (filletChamferData[counter][Y] == 0) {
- powerend = filletChamferData[counter][X];
- }
- if (only_selected && !isNodePointSelected(curve_it1->initialPoint())) {
- powerend = filletChamferData[counter][X];
+void LPEFilletChamfer::setSelected(PathVectorSatellites *_pathvector_satellites){
+ Geom::PathVector const pathv = _pathvector_satellites->getPathVector();
+ Satellites satellites = _pathvector_satellites->getSatellites();
+ for (size_t i = 0; i < satellites.size(); ++i) {
+ for (size_t j = 0; j < satellites[i].size(); ++j) {
+ Geom::Curve const &curve_in = pathv[i][j];
+ if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){
+ satellites[i][j].setSelected(true);
+ } else {
+ satellites[i][j].setSelected(false);
}
- result.push_back(Point(powerend, filletChamferData[counter][Y]));
- ++curve_it1;
- ++curve_it2;
- counter++;
}
}
- fillet_chamfer_values.param_set_and_write_new_value(result);
+ _pathvector_satellites->setSatellites(satellites);
}
-void LPEFilletChamfer::doChangeType(Geom::PathVector const &original_pathv, int type)
+void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem)
{
- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
- std::vector<Geom::Point> result;
- Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv);
- int counter = 0;
- for (PathVector::const_iterator path_it = original_pathv_processed.begin(); path_it != original_pathv_processed.end(); ++path_it) {
- int pathCounter = 0;
- if (path_it->empty())
- continue;
-
- 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();
- if (path_it->closed() && path_it->back_closed().isDegenerate()) {
- const Curve &closingline = path_it->back_closed();
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- curve_endit = path_it->end_open();
- }
+ if (sp_curve) {
+ //fillet chamfer specific calls
+ satellites_param.setUseDistance(use_knot_distance);
+ satellites_param.setCurrentZoom(current_zoom);
+ //mandatory call
+ satellites_param.setEffectType(effectType());
+ Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(sp_curve->get_pathvector());
+ //if are diferent sizes call to recalculate
+ //TODO: Update the satellite data in paths modified,
+ Satellites satellites = satellites_param.data();
+ if (satellites.empty()) {
+ doOnApply(lpeItem);
+ satellites = satellites_param.data();
}
- while (curve_it1 != curve_endit) {
- bool toggle = true;
- if (filletChamferData[counter][Y] == 0 ||
- (ignore_radius_0 && (filletChamferData[counter][X] == 0 ||
- filletChamferData[counter][X] == counter)) ||
- (only_selected && !isNodePointSelected(curve_it1->initialPoint()))) {
- toggle = false;
- }
- if (toggle) {
- if(type >= 5000){
- if(filletChamferData[counter][Y] >= 3000 && filletChamferData[counter][Y] < 4000){
- type = type - 2000;
- } else if (filletChamferData[counter][Y] >= 4000 && filletChamferData[counter][Y] < 5000){
- type = type - 1000;
- }
+ if (_pathvector_satellites) {
+ size_t number_nodes = pathv.nodes().size();
+ size_t previous_number_nodes = _pathvector_satellites->getTotalSatellites();
+ if (number_nodes != previous_number_nodes) {
+ Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(sp_curve->get_pathvector());
+ Satellites satellites;
+ double power = radius;
+ if (!flexible) {
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ SPNamedView *nv = sp_document_namedview(document, NULL);
+ Glib::ustring display_unit = nv->display_units->abbr;
+ power = Inkscape::Util::Quantity::convert(power, unit.get_abbreviation(), display_unit.c_str());
}
- result.push_back(Point(filletChamferData[counter][X], type));
- } else {
- result.push_back(filletChamferData[counter]);
- }
- ++curve_it1;
- if (curve_it2 != curve_endit) {
- ++curve_it2;
+ SatelliteType satellite_type = FILLET;
+ std::map<std::string, SatelliteType> gchar_map_to_satellite_type =
+ boost::assign::map_list_of("F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE);
+ std::map<std::string, SatelliteType>::iterator it = gchar_map_to_satellite_type.find(std::string(mode.param_getSVGValue()));
+ if (it != gchar_map_to_satellite_type.end()) {
+ satellite_type = it->second;
+ }
+ Satellite satellite(satellite_type);
+ satellite.setSteps(chamfer_steps);
+ satellite.setAmount(power);
+ satellite.setIsTime(flexible);
+ satellite.setHasMirror(mirror_knots);
+ satellite.setHidden(hide_knots);
+ _pathvector_satellites->recalculateForNewPathVector(pathv, satellite);
+ satellites = _pathvector_satellites->getSatellites();
}
- counter++;
- pathCounter++;
}
- }
- fillet_chamfer_values.param_set_and_write_new_value(result);
-}
-
-void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem)
-{
- if (SP_IS_SHAPE(lpeItem)) {
- std::vector<Point> point;
- PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeItem)->_curve->get_pathvector());
- Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv);
- for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) {
- if (path_it->empty())
- continue;
-
- 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();
- if (path_it->closed()) {
- const Geom::Curve &closingline = path_it->back_closed();
- // the closing line segment is always of type
- // Geom::LineSegment.
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- // closingline.isDegenerate() did not work, because it only checks for
- // *exact* zero length, which goes wrong for relative coordinates and
- // rounding errors...
- // the closing line segment has zero-length. So stop before that one!
- curve_endit = path_it->end_open();
- }
- }
- int counter = 0;
- while (curve_it1 != curve_endit) {
- std::pair<std::size_t, std::size_t> positions = fillet_chamfer_values.get_positions(counter, original_pathv);
- Geom::NodeType nodetype;
- if (positions.second == 0) {
- if (path_it->closed()) {
- Piecewise<D2<SBasis> > u;
- u.push_cut(0);
- u.push(pwd2_in[fillet_chamfer_values.last_index(counter, original_pathv)], 1);
- Geom::Curve const * A = path_from_piecewise(u, 0.1)[0][0].duplicate();
- nodetype = get_nodetype(*A, *curve_it1);
+ if (_degenerate_hide) {
+ satellites_param.setGlobalKnotHide(true);
+ } else {
+ satellites_param.setGlobalKnotHide(false);
+ }
+ if (hide_knots) {
+ satellites_param.setHelperSize(0);
+ } else {
+ satellites_param.setHelperSize(helper_size);
+ }
+ for (size_t i = 0; i < satellites.size(); ++i) {
+ for (size_t j = 0; j < satellites[i].size(); ++j) {
+ Geom::Curve const &curve_in = pathv[i][j];
+ if (satellites[i][j].is_time != flexible) {
+ satellites[i][j].is_time = flexible;
+ double amount = satellites[i][j].amount;
+ if (pathv[i].size() == j) {
+ continue;
+ }
+ if (satellites[i][j].is_time) {
+ double time = timeAtArcLength(amount, curve_in);
+ satellites[i][j].amount = time;
} else {
- nodetype = NODE_NONE;
+ double size = arcLengthAt(amount, curve_in);
+ satellites[i][j].amount = size;
}
- } else {
- nodetype = get_nodetype((*path_it)[counter - 1], *curve_it1);
}
- if (nodetype == NODE_CUSP) {
- point.push_back(Point(0, 1));
- } else {
- point.push_back(Point(0, 0));
+ if (satellites[i][j].has_mirror != mirror_knots) {
+ satellites[i][j].has_mirror = mirror_knots;
}
- ++curve_it1;
- if (curve_it2 != curve_endit) {
- ++curve_it2;
+ satellites[i][j].hidden = hide_knots;
+ if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){
+ satellites[i][j].setSelected(true);
}
- counter++;
}
}
- fillet_chamfer_values.param_set_and_write_new_value(point);
- } else {
- g_warning("LPE Fillet can only be applied to shapes (not groups).");
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeItem);
- item->removeCurrentPathEffect(false);
- }
-}
-
-void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem)
-{
- if (SP_IS_SHAPE(lpeItem)) {
- if(hide_knots){
- fillet_chamfer_values.set_helper_size(0);
- } else {
- fillet_chamfer_values.set_helper_size(helper_size);
- }
- fillet_chamfer_values.set_use_distance(use_knot_distance);
- SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast<SPPath const *>(lpeItem)
- ->get_original_curve()
- : SP_SHAPE(lpeItem)->getCurve();
- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
- if (!filletChamferData.empty() && getKnotsNumber(c) != (int)
- filletChamferData.size()) {
- PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(c->get_pathvector());
- Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv);
- fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in);
+ if (!_pathvector_satellites) {
+ _pathvector_satellites = new PathVectorSatellites();
}
+ _pathvector_satellites->setPathVector(pathv);
+ _pathvector_satellites->setSatellites(satellites);
+ satellites_param.setPathVectorSatellites(_pathvector_satellites, false);
+ refreshKnots();
} else {
g_warning("LPE Fillet can only be applied to shapes (not groups).");
}
}
-int LPEFilletChamfer::getKnotsNumber(SPCurve const *c)
+void
+LPEFilletChamfer::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
{
- int nKnots = c->nodes_in_path();
- PathVector const pv = pathv_to_linear_and_cubic_beziers(c->get_pathvector());
- for (Geom::PathVector::const_iterator path_it = pv.begin();
- path_it != pv.end(); ++path_it) {
- if (!(*path_it).closed()) {
- nKnots--;
- }
- }
- return nKnots;
+ hp_vec.push_back(_hp);
}
void
-LPEFilletChamfer::adjustForNewPath(Geom::PathVector const &path_in)
+LPEFilletChamfer::addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps)
{
- if (!path_in.empty()) {
- fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb());
+ setSelected(_pathvector_satellites);
+ double path_subdivision = 1.0 / steps;
+ for (size_t i = 1; i < steps; i++) {
+ Geom::Point chamfer_step = path_chamfer.pointAt(path_subdivision * i);
+ tmp_path.appendNew<Geom::LineSegment>(chamfer_step);
}
+ tmp_path.appendNew<Geom::LineSegment>(end_arc_point);
}
Geom::PathVector
LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in)
{
- Geom::PathVector pathvector_out;
- Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(pathv_to_linear_and_cubic_beziers(path_in));
- pwd2_in = remove_short_cuts(pwd2_in, .01);
- Piecewise<D2<SBasis> > der = derivative(pwd2_in);
- Piecewise<D2<SBasis> > n = rot90(unitVector(der));
- fillet_chamfer_values.set_pwd2(pwd2_in, n);
- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
- unsigned int counter = 0;
+ const double GAP_HELPER = 0.00001;
+ Geom::PathVector path_out;
+ size_t path = 0;
const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0);
- Geom::PathVector path_in_processed = pathv_to_linear_and_cubic_beziers(path_in);
- for (PathVector::const_iterator path_it = path_in_processed.begin();
- path_it != path_in_processed.end(); ++path_it) {
- if (path_it->empty())
+ _degenerate_hide = false;
+ Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(path_in);
+ Satellites satellites = _pathvector_satellites->getSatellites();
+ for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
+ if (path_it->empty()) {
continue;
- Geom::Path path_out;
- 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();
- if (path_it->closed()) {
- const Geom::Curve &closingline = path_it->back_closed();
- // the closing line segment is always of type
- // Geom::LineSegment.
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- // closingline.isDegenerate() did not work, because it only checks for
- // *exact* zero length, which goes wrong for relative coordinates and
- // rounding errors...
- // the closing line segment has zero-length. So stop before that one!
- curve_endit = path_it->end_open();
- }
}
- unsigned int counterCurves = 0;
- while (curve_it1 != curve_endit) {
- Curve *curve_it2Fixed = (*path_it->begin()).duplicate();
- if(!path_it->closed() || curve_it2 != curve_endit){
- curve_it2Fixed = (*curve_it2).duplicate();
+ Geom::Path tmp_path;
+ if (path_it->size() == 1) {
+ path++;
+ tmp_path.start(path_it[0].pointAt(0));
+ tmp_path.append(path_it[0]);
+ path_out.push_back(tmp_path);
+ continue;
+ }
+ double time0 = 0;
+ size_t curve = 0;
+ for (Geom::Path::const_iterator curve_it1 = path_it->begin(); curve_it1 != path_it->end(); ++curve_it1) {
+ size_t next_index = curve + 1;
+ if (curve == pathv[path].size() - 1 && pathv[path].closed()) {
+ next_index = 0;
+ }
+ //append last extreme of paths on open paths
+ if (curve == pathv[path].size() -1 && !pathv[path].closed()) { //the path is open and we are at end of path
+ if (time0 != 1) { //Previous satellite not at 100% amount
+ Geom::Curve *last_curve = curve_it1->portion(time0, 1);
+ last_curve->setInitial(tmp_path.finalPoint());
+ tmp_path.append(*last_curve);
+ }
+ continue;
}
- bool last = curve_it2 == curve_endit;
- std::vector<double> times = fillet_chamfer_values.get_times(counter, path_in, last);
- Curve *knotCurve1 = curve_it1->portion(times[0], times[1]);
- if (counterCurves > 0) {
- knotCurve1->setInitial(path_out.finalPoint());
+ Geom::Curve const &curve_it2 = pathv[path][next_index];
+ Satellite satellite = satellites[path][next_index];
+ if (Geom::are_near((*curve_it1).initialPoint(), (*curve_it1).finalPoint())) {
+ _degenerate_hide = true;
+ g_warning("Knots hidded if consecutive nodes has the same position.");
+ return path_in;
+ }
+ if (!curve) { //curve == 0
+ if (!path_it->closed()) {
+ time0 = 0;
+ } else {
+ time0 = satellites[path][0].time(*curve_it1);
+ }
+ }
+ double s = satellite.arcDistance(curve_it2);
+ double time1 = satellite.time(s, true, (*curve_it1));
+ double time2 = satellite.time(curve_it2);
+ if (time1 <= time0) {
+ time1 = time0;
+ }
+ if (time2 > 1) {
+ time2 = 1;
+ }
+ Geom::Curve *knot_curve_1 = curve_it1->portion(time0, time1);
+ Geom::Curve *knot_curve_2 = curve_it2.portion(time2, 1);
+ if (curve > 0) {
+ knot_curve_1->setInitial(tmp_path.finalPoint());
} else {
- path_out.start((*curve_it1).pointAt(times[0]));
+ tmp_path.start((*curve_it1).pointAt(time0));
}
- Curve *knotCurve2 = curve_it2Fixed->portion(times[2], 1);
- Point startArcPoint = knotCurve1->finalPoint();
- Point endArcPoint = curve_it2Fixed->pointAt(times[2]);
- double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K;
- double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K;
- Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1);
- Ray ray1(startArcPoint, curve_it1->finalPoint());
- if (cubic1) {
- ray1.setPoints((*cubic1)[2], startArcPoint);
+
+ Geom::Point start_arc_point = knot_curve_1->finalPoint();
+ Geom::Point end_arc_point = curve_it2.pointAt(time2);
+ //add a gap helper
+ if (time2 == 1) {
+ end_arc_point = curve_it2.pointAt(time2 - GAP_HELPER);
}
- Point handle1 = Point::polar(ray1.angle(),k1) + startArcPoint;
- Geom::CubicBezier const *cubic2 =
- dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2);
- Ray ray2(curve_it1->finalPoint(), endArcPoint);
- if (cubic2) {
- ray2.setPoints(endArcPoint, (*cubic2)[1]);
+ if (time1 == time0) {
+ start_arc_point = curve_it1->pointAt(time1 + GAP_HELPER);
}
- Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2);
- bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0;
- double angle = angle_between(ray1, ray2, ccwToggle);
- double handleAngle = ray1.angle() - angle;
- if (ccwToggle) {
- handleAngle = ray1.angle() + angle;
+
+ double k1 = distance(start_arc_point, curve_it1->finalPoint()) * K;
+ double k2 = distance(curve_it2.initialPoint(), end_arc_point) * K;
+ Geom::CubicBezier const *cubic_1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_1);
+ Geom::CubicBezier const *cubic_2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_2);
+ Geom::Ray ray_1(start_arc_point, curve_it1->finalPoint());
+ Geom::Ray ray_2(curve_it2.initialPoint(), end_arc_point);
+ if (cubic_1) {
+ ray_1.setPoints((*cubic_1)[2], start_arc_point);
}
- Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint;
- handleAngle = ray2.angle() + angle;
- if (ccwToggle) {
- handleAngle = ray2.angle() - angle;
+ if (cubic_2) {
+ ray_2.setPoints(end_arc_point, (*cubic_2)[1]);
}
- Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2);
- //straigth lines arc based
- Line const x_line(Geom::Point(0,0),Geom::Point(1,0));
- Line const angled_line(startArcPoint,endArcPoint);
- double angleArc = Geom::angle_between( x_line,angled_line);
- double radius = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint))/sin(angle/2.0);
- Coord rx = radius;
- Coord ry = rx;
-
- if (times[1] != 1) {
- if (times[1] != gapHelper && times[1] != times[0] + gapHelper) {
- path_out.append(*knotCurve1);
- }
- int type = 0;
- if(path_it->closed() && last){
- type = std::abs(filletChamferData[counter - counterCurves][Y]);
- } else if (!path_it->closed() && last){
- //0
- } else {
- type = std::abs(filletChamferData[counter + 1][Y]);
- }
- if(are_near(middle_point(startArcPoint,endArcPoint),curve_it1->finalPoint(), 0.0001)){
- path_out.appendNew<Geom::LineSegment>(endArcPoint);
- } else if (type >= 3000 && type < 4000) {
- unsigned int chamferSubs = type-3000;
- Geom::Path path_chamfer;
- path_chamfer.start(path_out.finalPoint());
- if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
- path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
- } else {
- path_chamfer.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint);
- }
- double chamfer_stepsTime = 1.0/chamferSubs;
- for(unsigned int i = 1; i < chamferSubs; i++){
- Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i);
- path_out.appendNew<Geom::LineSegment>(chamferStep);
+ bool ccw_toggle = cross(curve_it1->finalPoint() - start_arc_point, end_arc_point - start_arc_point) < 0;
+ double angle = angle_between(ray_1, ray_2, ccw_toggle);
+ double handle_angle_1 = ray_1.angle() - angle;
+ double handle_angle_2 = ray_2.angle() + angle;
+ if (ccw_toggle) {
+ handle_angle_1 = ray_1.angle() + angle;
+ handle_angle_2 = ray_2.angle() - angle;
+ }
+ Geom::Point handle_1 = Geom::Point::polar(ray_1.angle(), k1) + start_arc_point;
+ Geom::Point handle_2 = end_arc_point - Geom::Point::polar(ray_2.angle(), k2);
+ Geom::Point inverse_handle_1 = Geom::Point::polar(handle_angle_1, k1) + start_arc_point;
+ Geom::Point inverse_handle_2 = end_arc_point - Geom::Point::polar(handle_angle_2, k2);
+ if (time0 == 1) {
+ handle_1 = start_arc_point;
+ inverse_handle_1 = start_arc_point;
+ }
+ //remove gap helper
+ if (time2 == 1) {
+ end_arc_point = curve_it2.pointAt(time2);
+ }
+ if (time1 == time0) {
+ start_arc_point = curve_it1->pointAt(time0);
+ }
+ if (time1 != 1) {
+ if (time1 != time0 || (time1 == 1 && time0 == 1)) {
+ if (!knot_curve_1->isDegenerate()) {
+ tmp_path.append(*knot_curve_1);
}
- path_out.appendNew<Geom::LineSegment>(endArcPoint);
- } else if (type >= 4000 && type < 5000) {
- unsigned int chamferSubs = type-4000;
- Geom::Path path_chamfer;
- path_chamfer.start(path_out.finalPoint());
- if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
- ccwToggle = ccwToggle?0:1;
- path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
- }else{
- path_chamfer.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint);
+ }
+ SatelliteType type = satellite.satellite_type;
+ size_t steps = satellite.steps;
+ if (!steps) steps = 1;
+ Geom::Line const x_line(Geom::Point(0, 0), Geom::Point(1, 0));
+ Geom::Line const angled_line(start_arc_point, end_arc_point);
+ double arc_angle = Geom::angle_between(x_line, angled_line);
+ double radius = Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point)) /
+ sin(angle / 2.0);
+ Geom::Coord rx = radius;
+ Geom::Coord ry = rx;
+ bool eliptical = (is_straight_curve(*curve_it1) &&
+ is_straight_curve(curve_it2) && method != FM_BEZIER) ||
+ method == FM_ARC;
+ switch (type) {
+ case CHAMFER:
+ {
+ Geom::Path path_chamfer;
+ path_chamfer.start(tmp_path.finalPoint());
+ if (eliptical) {
+ ccw_toggle = ccw_toggle ? 0 : 1;
+ path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
+ } else {
+ path_chamfer.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point);
+ }
+ addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps);
}
- double chamfer_stepsTime = 1.0/chamferSubs;
- for(unsigned int i = 1; i < chamferSubs; i++){
- Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i);
- path_out.appendNew<Geom::LineSegment>(chamferStep);
+ break;
+ case INVERSE_CHAMFER:
+ {
+ Geom::Path path_chamfer;
+ path_chamfer.start(tmp_path.finalPoint());
+ if (eliptical) {
+ path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
+ } else {
+ path_chamfer.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point);
+ }
+ addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps);
}
- path_out.appendNew<Geom::LineSegment>(endArcPoint);
- } else if (type == 2) {
- if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
- ccwToggle = ccwToggle?0:1;
- path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
- }else{
- path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint);
+ break;
+ case INVERSE_FILLET:
+ {
+ if (eliptical) {
+ tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
+ } else {
+ tmp_path.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point);
+ }
}
- } else if (type == 1){
- if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
- path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
- } else {
- path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint);
+ break;
+ default: //fillet
+ {
+ if (eliptical) {
+ ccw_toggle = ccw_toggle ? 0 : 1;
+ tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
+ } else {
+ tmp_path.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point);
+ }
}
+ break;
}
} else {
- path_out.append(*knotCurve1);
- }
- if (path_it->closed() && last) {
- path_out.close();
- }
- ++curve_it1;
- if (curve_it2 != curve_endit) {
- ++curve_it2;
+ if (!knot_curve_1->isDegenerate()) {
+ tmp_path.append(*knot_curve_1);
+ }
}
- counter++;
- counterCurves++;
+ curve++;
+ time0 = time2;
+ }
+ if (path_it->closed()) {
+ tmp_path.close();
}
- pathvector_out.push_back(path_out);
+ path++;
+ path_out.push_back(tmp_path);
}
- return pathvector_out;
+ return path_out;
}
}; //namespace LivePathEffect
diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h
index 290a37f92..c628added 100644
--- a/src/live_effects/lpe-fillet-chamfer.h
+++ b/src/live_effects/lpe-fillet-chamfer.h
@@ -7,25 +7,23 @@
*
* Copyright (C) 2014 Author(s)
*
- * Special thanks to Johan Engelen for the base of the effect -powerstroke-
- * Also to ScislaC for point me to the idea
- * Also su_v for his construvtive feedback and time
- * and finaly to Liam P. White for his big help on coding, that save me a lot of hours
+ * Jabiertxof:Thanks to all people help me
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "live_effects/parameter/enum.h"
-#include "live_effects/parameter/bool.h"
-#include "live_effects/parameter/unit.h"
-
-#include "live_effects/parameter/filletchamferpointarray.h"
+#include "live_effects/parameter/satellitesarray.h"
#include "live_effects/effect.h"
+#include "live_effects/parameter/unit.h"
+#include "live_effects/parameter/hidden.h"
+#include "helper/geom-pathvectorsatellites.h"
+#include "helper/geom-satellite.h"
namespace Inkscape {
namespace LivePathEffect {
-enum FilletMethod {
+enum Filletmethod {
FM_AUTO,
FM_ARC,
FM_BEZIER,
@@ -35,41 +33,39 @@ enum FilletMethod {
class LPEFilletChamfer : public Effect {
public:
LPEFilletChamfer(LivePathEffectObject *lpeobject);
- virtual ~LPEFilletChamfer();
-
+ virtual void doBeforeEffect(SPLPEItem const *lpeItem);
virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in);
-
virtual void doOnApply(SPLPEItem const *lpeItem);
- virtual void doBeforeEffect(SPLPEItem const *lpeItem);
- virtual void adjustForNewPath(Geom::PathVector const &path_in);
- virtual Gtk::Widget* newWidget();
-
- int getKnotsNumber(SPCurve const *c);
- void toggleHide();
- void toggleFlexFixed();
- void chamfer();
- void chamferSubdivisions();
- void inverseChamfer();
- void fillet();
- void inverseFillet();
- void updateFillet();
- void doUpdateFillet(Geom::PathVector const& original_pathv, double power);
- void doChangeType(Geom::PathVector const& original_pathv, int type);
+ virtual Gtk::Widget *newWidget();
+ Geom::Ray getRay(Geom::Point start, Geom::Point end, Geom::Curve *curve, bool reverse);
+ void addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps);
+ void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
+ void updateSatelliteType(SatelliteType satellitetype);
+ void setSelected(PathVectorSatellites *_pathvector_satellites);
+ //void convertUnit();
+ void updateChamferSteps();
+ void updateAmount();
void refreshKnots();
- FilletChamferPointArrayParam fillet_chamfer_values;
+ SatellitesArrayParam satellites_param;
private:
-
- BoolParam hide_knots;
- BoolParam ignore_radius_0;
- BoolParam only_selected;
- BoolParam flexible;
- BoolParam use_knot_distance;
- EnumParam<FilletMethod> method;
+ UnitParam unit;
+ EnumParam<Filletmethod> method;
ScalarParam radius;
ScalarParam chamfer_steps;
+ BoolParam flexible;
+ HiddenParam mode;
+ BoolParam mirror_knots;
+ BoolParam only_selected;
+ BoolParam use_knot_distance;
+ BoolParam hide_knots;
+ BoolParam apply_no_radius;
+ BoolParam apply_with_radius;
ScalarParam helper_size;
+ bool _degenerate_hide;
+ PathVectorSatellites *_pathvector_satellites;
+ Geom::PathVector _hp;
LPEFilletChamfer(const LPEFilletChamfer &);
LPEFilletChamfer &operator=(const LPEFilletChamfer &);
diff --git a/src/live_effects/lpe-gears.cpp b/src/live_effects/lpe-gears.cpp
index d4d695542..dad520041 100644
--- a/src/live_effects/lpe-gears.cpp
+++ b/src/live_effects/lpe-gears.cpp
@@ -7,15 +7,9 @@
*/
#include "live_effects/lpe-gears.h"
-
-#include <vector>
-
-#include <glibmm/i18n.h>
-
-#include <2geom/d2.h>
-#include <2geom/sbasis.h>
#include <2geom/bezier-to-sbasis.h>
-#include <2geom/path.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using std::vector;
using namespace Geom;
@@ -212,7 +206,8 @@ namespace LivePathEffect {
LPEGears::LPEGears(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
teeth(_("_Teeth:"), _("The number of teeth"), "teeth", &wr, this, 10),
- phi(_("_Phi:"), _("Tooth pressure angle (typically 20-25 deg). The ratio of teeth not in contact."), "phi", &wr, this, 5)
+ phi(_("_Phi:"), _("Tooth pressure angle (typically 20-25 deg). The ratio of teeth not in contact."), "phi", &wr, this, 5),
+ min_radius(_("Min Radius:"), _("Minimum radius, low values can be slow"), "min_radius", &wr, this, 5.0)
{
/* Tooth pressure angle: The angle between the tooth profile and a perpendicular to the pitch
* circle, usually at the point where the pitch circle meets the tooth profile. Standard angles
@@ -223,8 +218,10 @@ LPEGears::LPEGears(LivePathEffectObject *lpeobject) :
teeth.param_make_integer();
teeth.param_set_range(3, 1e10);
- registerParameter( dynamic_cast<Parameter *>(&teeth) );
- registerParameter( dynamic_cast<Parameter *>(&phi) );
+ min_radius.param_set_range(0.01, 9999.0);
+ registerParameter(&teeth);
+ registerParameter(&phi);
+ registerParameter(&min_radius);
}
LPEGears::~LPEGears()
@@ -247,12 +244,17 @@ LPEGears::doEffect_path (Geom::PathVector const &path_in)
gear->angle(atan2((*it).initialPoint() - gear_centre));
++it;
- if ( it == gearpath.end() ) return path_out;
- gear->pitch_radius(Geom::distance(gear_centre, (*it).finalPoint()));
+ if ( it == gearpath.end() ) return path_out;
+ double radius = Geom::distance(gear_centre, (*it).finalPoint());
+ radius = radius < min_radius?min_radius:radius;
+ gear->pitch_radius(radius);
path_out.push_back( gear->path());
-
+
for (++it; it != gearpath.end() ; ++it) {
+ if (are_near((*it).initialPoint(), (*it).finalPoint())) {
+ continue;
+ }
// iterate through Geom::Curve in path_in
Gear* gearnew = new Gear(gear->spawn( (*it).finalPoint() ));
path_out.push_back( gearnew->path() );
diff --git a/src/live_effects/lpe-gears.h b/src/live_effects/lpe-gears.h
index 5dd6dd239..57b49d2b5 100644
--- a/src/live_effects/lpe-gears.h
+++ b/src/live_effects/lpe-gears.h
@@ -27,6 +27,7 @@ public:
private:
ScalarParam teeth;
ScalarParam phi;
+ ScalarParam min_radius;
LPEGears(const LPEGears&);
LPEGears& operator=(const LPEGears&);
diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp
index 74c7efd90..db3faa307 100644
--- a/src/live_effects/lpe-interpolate.cpp
+++ b/src/live_effects/lpe-interpolate.cpp
@@ -9,18 +9,15 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-interpolate.h"
-#include <2geom/path.h>
#include <2geom/sbasis-to-bezier.h>
-#include <2geom/piecewise.h>
-#include <2geom/sbasis-geometric.h>
#include "sp-path.h"
#include "display/curve.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -33,9 +30,9 @@ LPEInterpolate::LPEInterpolate(LivePathEffectObject *lpeobject) :
{
show_orig_path = true;
- registerParameter( dynamic_cast<Parameter *>(&trajectory_path) );
- registerParameter( dynamic_cast<Parameter *>(&equidistant_spacing) );
- registerParameter( dynamic_cast<Parameter *>(&number_of_steps) );
+ registerParameter(&trajectory_path);
+ registerParameter(&equidistant_spacing);
+ registerParameter(&number_of_steps);
number_of_steps.param_make_integer();
number_of_steps.param_set_range(2, Geom::infinity());
diff --git a/src/live_effects/lpe-interpolate_points.cpp b/src/live_effects/lpe-interpolate_points.cpp
index cf70832ee..0a0bcea14 100644
--- a/src/live_effects/lpe-interpolate_points.cpp
+++ b/src/live_effects/lpe-interpolate_points.cpp
@@ -12,10 +12,9 @@
*/
#include "live_effects/lpe-interpolate_points.h"
-
-#include <2geom/path.h>
-
#include "live_effects/lpe-powerstroke-interpolators.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp
index fe42932be..0e1e46a94 100644
--- a/src/live_effects/lpe-jointype.cpp
+++ b/src/live_effects/lpe-jointype.cpp
@@ -10,19 +10,17 @@
#include "live_effects/parameter/enum.h"
#include "helper/geom-pathstroke.h"
-#include "sp-shape.h"
#include "style.h"
-#include "xml/repr.h"
-#include "sp-paint-server.h"
#include "svg/svg-color.h"
#include "desktop-style.h"
#include "svg/css-ostringstream.h"
#include "display/curve.h"
-#include <2geom/path.h>
#include <2geom/elliptical-arc.h>
#include "lpe-jointype.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -85,6 +83,7 @@ LPEJoinType::~LPEJoinType()
void LPEJoinType::doOnApply(SPLPEItem const* lpeitem)
{
if (SP_IS_SHAPE(lpeitem)) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem);
double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.;
@@ -111,8 +110,14 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem)
sp_desktop_apply_css_recursive(item, css, true);
sp_repr_css_attr_unref (css);
-
- line_width.param_set_value(width);
+ Glib::ustring pref_path = (Glib::ustring)"/live_effects/" +
+ (Glib::ustring)LPETypeConverter.get_key(effectType()).c_str() +
+ (Glib::ustring)"/" +
+ (Glib::ustring)"line_width";
+ bool valid = prefs->getEntry(pref_path).isValid();
+ if(!valid){
+ line_width.param_set_value(width);
+ }
line_width.write_to_SVG();
}
}
diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp
index a033a6c4a..261612fdb 100644
--- a/src/live_effects/lpe-knot.cpp
+++ b/src/live_effects/lpe-knot.cpp
@@ -16,28 +16,24 @@
#include "sp-path.h"
#include "display/curve.h"
#include "live_effects/lpe-knot.h"
-#include "svg/svg.h"
#include "style.h"
#include "knot-holder-entity.h"
#include "knotholder.h"
-#include <glibmm/i18n.h>
#include <gdk/gdk.h>
#include <2geom/sbasis-to-bezier.h>
-#include <2geom/sbasis.h>
-#include <2geom/d2.h>
-#include <2geom/path.h>
#include <2geom/bezier-to-sbasis.h>
#include <2geom/basic-intersection.h>
-#include <2geom/exception.h>
+#include "helper/geom.h"
// for change crossing undo
#include "verbs.h"
#include "document.h"
#include "document-undo.h"
-#include <exception>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -101,7 +97,7 @@ findShadowedTime(Geom::Path const &patha, std::vector<Geom::Point> const &pt_and
Affine mat = from_basis( T, N, pt_and_dir[0] );
mat = mat.inverse();
- Path p = patha * mat;
+ Geom::Path p = patha * mat;
std::vector<double> times;
@@ -360,12 +356,12 @@ LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) :
switcher(0.,0.)
{
// register all your parameters here, so Inkscape knows which parameters this effect has:
- registerParameter( dynamic_cast<Parameter *>(&interruption_width) );
- registerParameter( dynamic_cast<Parameter *>(&prop_to_stroke_width) );
- registerParameter( dynamic_cast<Parameter *>(&add_stroke_width) );
- registerParameter( dynamic_cast<Parameter *>(&add_other_stroke_width) );
- registerParameter( dynamic_cast<Parameter *>(&switcher_size) );
- registerParameter( dynamic_cast<Parameter *>(&crossing_points_vector) );
+ registerParameter(&interruption_width);
+ registerParameter(&prop_to_stroke_width);
+ registerParameter(&add_stroke_width);
+ registerParameter(&add_other_stroke_width);
+ registerParameter(&switcher_size);
+ registerParameter(&crossing_points_vector);
_provides_knotholder_entities = true;
}
@@ -399,14 +395,14 @@ LPEKnot::doEffect_path (Geom::PathVector const &path_in)
if (gpaths.size()==0){
return path_in;
}
-
- for (unsigned comp=0; comp<path_in.size(); comp++){
+ Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in);
+ for (unsigned comp=0; comp<original_pathv.size(); comp++){
//find the relevant path component in gpaths (required to allow groups!)
//Q: do we always receive the group members in the same order? can we rest on that?
unsigned i0 = 0;
for (i0=0; i0<gpaths.size(); i0++){
- if (path_in[comp]==gpaths[i0]) break;
+ if (original_pathv[comp]==gpaths[i0]) break;
}
if (i0 == gpaths.size() ) {THROW_EXCEPTION("lpe-knot error: group member not recognized");}// this should not happen...
@@ -484,7 +480,7 @@ LPEKnot::doEffect_path (Geom::PathVector const &path_in)
// std::cout<<"fusing first and last component\n";
++beg_comp;
--end_comp;
- Path first = gpaths[i0].portion(dom.back());
+ Geom::Path first = gpaths[i0].portion(dom.back());
//FIXME: stitching should not be necessary (?!?)
first.setStitching(true);
first.append(gpaths[i0].portion(dom.front()));
@@ -521,7 +517,7 @@ collectPathsAndWidths (SPLPEItem const *lpeitem, Geom::PathVector &paths, std::v
c = SP_SHAPE(lpeitem)->getCurve();
}
if (c) {
- Geom::PathVector subpaths = c->get_pathvector();
+ Geom::PathVector subpaths = pathv_to_linear_and_cubic_beziers(c->get_pathvector());
for (unsigned i=0; i<subpaths.size(); i++){
paths.push_back(subpaths[i]);
//FIXME: do we have to be more carefull when trying to access stroke width?
@@ -619,10 +615,10 @@ LPEKnot::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::Pat
hp_vec.push_back(pathv);
}
-void LPEKnot::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+void LPEKnot::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
KnotHolderEntity *e = new KnotHolderEntityCrossingSwitcher(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Drag to select a crossing, click to flip it") );
knotholder->add(e);
};
diff --git a/src/live_effects/lpe-knot.h b/src/live_effects/lpe-knot.h
index 95bfaf6e1..ac518b97c 100644
--- a/src/live_effects/lpe-knot.h
+++ b/src/live_effects/lpe-knot.h
@@ -61,7 +61,7 @@ public:
/* the knotholder entity classes must be declared friends */
friend class KnotHolderEntityCrossingSwitcher;
- void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
protected:
virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp
index 3c23e349e..124a7a9c6 100644
--- a/src/live_effects/lpe-lattice.cpp
+++ b/src/live_effects/lpe-lattice.cpp
@@ -6,7 +6,7 @@
* Authors:
* Johan Engelen <j.b.c.engelen@utwente.nl>
* Steren Giannini
- * Noé Falzon
+ * No� Falzon
* Victor Navez
*
* Copyright (C) 2007-2008 Authors
@@ -16,23 +16,12 @@
#include "live_effects/lpe-lattice.h"
-#include "sp-shape.h"
-#include "sp-item.h"
-#include "sp-path.h"
#include "display/curve.h"
-#include "svg/svg.h"
-#include <2geom/sbasis.h>
#include <2geom/sbasis-2d.h>
-#include <2geom/sbasis-geometric.h>
#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/piecewise.h>
-#include <2geom/transforms.h>
-
-#include "desktop.h" // TODO: should be factored out (see below)
-
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using namespace Geom;
namespace Inkscape {
@@ -61,22 +50,22 @@ LPELattice::LPELattice(LivePathEffectObject *lpeobject) :
{
// register all your parameters here, so Inkscape knows which parameters this effect has:
- registerParameter( dynamic_cast<Parameter *>(&grid_point0) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point1) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point2) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point3) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point4) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point5) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point6) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point7) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point8) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point9) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point10) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point11) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point12) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point13) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point14) );
- registerParameter( dynamic_cast<Parameter *>(&grid_point15) );
+ registerParameter(&grid_point0);
+ registerParameter(&grid_point1);
+ registerParameter(&grid_point2);
+ registerParameter(&grid_point3);
+ registerParameter(&grid_point4);
+ registerParameter(&grid_point5);
+ registerParameter(&grid_point6);
+ registerParameter(&grid_point7);
+ registerParameter(&grid_point8);
+ registerParameter(&grid_point9);
+ registerParameter(&grid_point10);
+ registerParameter(&grid_point11);
+ registerParameter(&grid_point12);
+ registerParameter(&grid_point13);
+ registerParameter(&grid_point14);
+ registerParameter(&grid_point15);
apply_to_clippath_and_mask = true;
}
diff --git a/src/live_effects/lpe-lattice.h b/src/live_effects/lpe-lattice.h
index 5eb48909b..8720af138 100644
--- a/src/live_effects/lpe-lattice.h
+++ b/src/live_effects/lpe-lattice.h
@@ -9,7 +9,7 @@
* Authors:
* Johan Engelen
* Steren Giannini
- * Noé Falzon
+ * Noé Falzon
* Victor Navez
*
* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp
index 0c403daec..e827491c0 100644
--- a/src/live_effects/lpe-lattice2.cpp
+++ b/src/live_effects/lpe-lattice2.cpp
@@ -6,7 +6,7 @@
* Authors:
* Johan Engelen <j.b.c.engelen@utwente.nl>
* Steren Giannini
- * Noé Falzon
+ * No� Falzon
* Victor Navez
* ~suv
* Jabiertxo Arraiza
@@ -16,26 +16,15 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <gtkmm.h>
#include "live_effects/lpe-lattice2.h"
-
-#include <gtkmm/expander.h>
-
-#include "sp-shape.h"
-#include "sp-item.h"
-#include "sp-path.h"
#include "display/curve.h"
-#include "svg/svg.h"
#include "helper/geom.h"
-#include <2geom/path.h>
-#include <2geom/sbasis.h>
#include <2geom/sbasis-2d.h>
-#include "helper/geom-curves.h"
-#include <2geom/sbasis-geometric.h>
#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/piecewise.h>
-#include <2geom/transforms.h>
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using namespace Geom;
@@ -280,7 +269,7 @@ void
LPELattice2::onExpanderChanged()
{
expanded = expander->get_expanded();
- if(expander->get_expanded()) {
+ if(expanded) {
expander->set_label (Glib::ustring(_("Hide Points")));
} else {
expander->set_label (Glib::ustring(_("Show Points")));
diff --git a/src/live_effects/lpe-lattice2.h b/src/live_effects/lpe-lattice2.h
index 8d0c18a3a..95c5285fb 100644
--- a/src/live_effects/lpe-lattice2.h
+++ b/src/live_effects/lpe-lattice2.h
@@ -9,7 +9,7 @@
* Authors:
* Johan Engelen
* Steren Giannini
- * Noé Falzon
+ * Noé Falzon
* Victor Navez
* ~suv
* Jabiertxo Arraiza
@@ -18,9 +18,9 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "live_effects/parameter/enum.h"
-#include <gtkmm/widget.h>
+
#include "live_effects/effect.h"
+#include "live_effects/parameter/enum.h"
#include "live_effects/parameter/point.h"
#include "live_effects/lpegroupbbox.h"
diff --git a/src/live_effects/lpe-line_segment.cpp b/src/live_effects/lpe-line_segment.cpp
index dfd8aea8f..fd23da804 100644
--- a/src/live_effects/lpe-line_segment.cpp
+++ b/src/live_effects/lpe-line_segment.cpp
@@ -13,10 +13,8 @@
#include "live_effects/lpe-line_segment.h"
#include "ui/tools/lpe-tool.h"
-
-#include <2geom/pathvector.h>
-#include <2geom/geom.h>
-#include <2geom/bezier-curve.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -34,7 +32,7 @@ LPELineSegment::LPELineSegment(LivePathEffectObject *lpeobject) :
end_type(_("End type:"), _("Determines on which side the line or line segment is infinite."), "end_type", EndTypeConverter, &wr, this, END_OPEN_BOTH)
{
/* register all your parameters here, so Inkscape knows which parameters this effect has: */
- registerParameter( dynamic_cast<Parameter *>(&end_type) );
+ registerParameter(&end_type);
}
LPELineSegment::~LPELineSegment()
diff --git a/src/live_effects/lpe-measure-line.cpp b/src/live_effects/lpe-measure-line.cpp
new file mode 100644
index 000000000..99828aef8
--- /dev/null
+++ b/src/live_effects/lpe-measure-line.cpp
@@ -0,0 +1,763 @@
+/*
+ * Author(s):
+ * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ * Some code and ideas migrated from dimensioning.py by
+ * Johannes B. Rutzmoser, johannes.rutzmoser (at) googlemail (dot) com
+ * https://github.com/Rutzmoser/inkscape_dimensioning
+ * Copyright (C) 2014 Author(s)
+
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+#include "live_effects/lpe-measure-line.h"
+#include <pangomm/fontdescription.h>
+#include "ui/dialog/livepatheffect-editor.h"
+#include <libnrtype/font-lister.h>
+#include "inkscape.h"
+#include "xml/node.h"
+#include "xml/sp-css-attr.h"
+#include "preferences.h"
+#include "util/units.h"
+#include "svg/svg-length.h"
+#include "svg/svg-color.h"
+#include "svg/svg.h"
+#include "display/curve.h"
+#include "helper/geom.h"
+#include "2geom/affine.h"
+#include "path-chemistry.h"
+#include "style.h"
+#include "sp-root.h"
+#include "sp-defs.h"
+#include "sp-item.h"
+#include "sp-shape.h"
+#include "sp-path.h"
+#include "document.h"
+#include <iomanip>
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
+using namespace Geom;
+namespace Inkscape {
+namespace LivePathEffect {
+
+static const Util::EnumData<OrientationMethod> OrientationMethodData[] = {
+ { OM_HORIZONTAL, N_("Horizontal"), "horizontal" },
+ { OM_VERTICAL, N_("Vertical"), "vertical" },
+ { OM_PARALLEL, N_("Parallel"), "parallel" }
+};
+static const Util::EnumDataConverter<OrientationMethod> OMConverter(OrientationMethodData, OM_END);
+
+LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) :
+ Effect(lpeobject),
+ unit(_("Unit"), _("Unit"), "unit", &wr, this, "px"),
+ fontbutton(_("Font"), _("Font Selector"), "fontbutton", &wr, this),
+ orientation(_("Orientation"), _("Orientation method"), "orientation", OMConverter, &wr, this, OM_PARALLEL, false),
+ curve_linked(_("Curve on origin"), _("Curve on origin, set 0 to start/end"), "curve_linked", &wr, this, 1),
+ precision(_("Precision"), _("Precision"), "precision", &wr, this, 2),
+ position(_("Position"), _("Position"), "position", &wr, this, 5),
+ text_top_bottom(_("Text top/bottom"), _("Text top/bottom"), "text_top_bottom", &wr, this, 0),
+ text_right_left(_("Text right/left"), _("Text right/left"), "text_right_left", &wr, this, 0),
+ helpline_distance(_("Helpline distance"), _("Helpline distance"), "helpline_distance", &wr, this, 0.0),
+ helpline_overlap(_("Helpline overlap"), _("Helpline overlap"), "helpline_overlap", &wr, this, 2.0),
+ scale(_("Scale"), _("Scaling factor"), "scale", &wr, this, 1.0),
+ format(_("Format"), _("Format the number ex:{measure} {unit}, return to save"), "format", &wr, this,"{measure}{unit}"),
+ id_origin("id_origin", "id_origin", "id_origin", &wr, this,""),
+ arrows_outside(_("Arrows outside"), _("Arrows outside"), "arrows_outside", &wr, this, false),
+ flip_side(_("Flip side"), _("Flip side"), "flip_side", &wr, this, false),
+ scale_sensitive(_("Scale sensitive"), _("Costrained scale sensitive to transformed containers"), "scale_sensitive", &wr, this, true),
+ local_locale(_("Local Number Format"), _("Local number format"), "local_locale", &wr, this, true),
+ line_group_05(_("Line Group 0.5"), _("Line Group 0.5, from 0.7"), "line_group_05", &wr, this, true),
+ rotate_anotation(_("Rotate Anotation"), _("Rotate Anotation"), "rotate_anotation", &wr, this, true),
+ hide_back(_("Hide if label over"), _("Hide DIN line if label over"), "hide_back", &wr, this, true),
+ dimline_format(_("CSS DIN line"), _("Override CSS to DIN line, return to save, empty to reset to DIM"), "dimline_format", &wr, this,""),
+ helperlines_format(_("CSS helpers"), _("Override CSS to helper lines, return to save, empty to reset to DIM"), "helperlines_format", &wr, this,""),
+ anotation_format(_("CSS anotation"), _("Override CSS to anotation text, return to save, empty to reset to DIM"), "anotation_format", &wr, this,""),
+ arrows_format(_("CSS arrows"), _("Override CSS to arrows, return to save, empty to reset DIM"), "arrows_format", &wr, this,""),
+ expanded(false)
+{
+ //set to true the parameters you want to be changed his default values
+ registerParameter(&unit);
+ registerParameter(&fontbutton);
+ registerParameter(&orientation);
+ registerParameter(&curve_linked);
+ registerParameter(&precision);
+ registerParameter(&position);
+ registerParameter(&text_top_bottom);
+ registerParameter(&text_right_left);
+ registerParameter(&helpline_distance);
+ registerParameter(&helpline_overlap);
+ registerParameter(&scale);
+ registerParameter(&format);
+ registerParameter(&arrows_outside);
+ registerParameter(&flip_side);
+ registerParameter(&scale_sensitive);
+ registerParameter(&local_locale);
+ registerParameter(&line_group_05);
+ registerParameter(&rotate_anotation);
+ registerParameter(&hide_back);
+ registerParameter(&dimline_format);
+ registerParameter(&helperlines_format);
+ registerParameter(&anotation_format);
+ registerParameter(&arrows_format);
+ registerParameter(&id_origin);
+
+ id_origin.param_hide_canvas_text();
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ Glib::ustring format_value = prefs->getString("/live_effects/measure-line/format");
+ if(format_value.empty()){
+ format_value = "{measure}{unit}";
+ }
+ format.param_update_default(format_value.c_str());
+
+ format.param_hide_canvas_text();
+ dimline_format.param_hide_canvas_text();
+ helperlines_format.param_hide_canvas_text();
+ anotation_format.param_hide_canvas_text();
+ arrows_format.param_hide_canvas_text();
+ precision.param_set_range(0, 100);
+ precision.param_set_increments(1, 1);
+ precision.param_set_digits(0);
+ precision.param_make_integer(true);
+ curve_linked.param_set_range(0, 999);
+ curve_linked.param_set_increments(1, 1);
+ curve_linked.param_set_digits(0);
+ curve_linked.param_make_integer(true);
+ precision.param_make_integer(true);
+ position.param_set_range(-999999.0, 999999.0);
+ position.param_set_increments(1, 1);
+ position.param_set_digits(2);
+ text_top_bottom.param_set_range(-999999.0, 999999.0);
+ text_top_bottom.param_set_increments(1, 1);
+ text_top_bottom.param_set_digits(2);
+ text_right_left.param_set_range(-999999.0, 999999.0);
+ text_right_left.param_set_increments(1, 1);
+ text_right_left.param_set_digits(2);
+ helpline_distance.param_set_range(-999999.0, 999999.0);
+ helpline_distance.param_set_increments(1, 1);
+ helpline_distance.param_set_digits(2);
+ helpline_overlap.param_set_range(-999999.0, 999999.0);
+ helpline_overlap.param_set_increments(1, 1);
+ helpline_overlap.param_set_digits(2);
+ start_stored = Geom::Point(0,0);
+ end_stored = Geom::Point(0,0);
+ id_origin.param_widget_is_visible(false);
+}
+
+LPEMeasureLine::~LPEMeasureLine() {}
+
+void
+LPEMeasureLine::createArrowMarker(const char * mode)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ SPObject *elemref = NULL;
+ Inkscape::XML::Node *arrow = NULL;
+ if ((elemref = document->getObjectById(mode))) {
+ Inkscape::XML::Node *arrow= elemref->getRepr();
+ if (arrow) {
+ arrow->setAttribute("sodipodi:insensitive", "true");
+ arrow->setAttribute("transform", NULL);
+ Inkscape::XML::Node *arrow_data = arrow->firstChild();
+ if (arrow_data) {
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property (css, "fill","#000000");
+ sp_repr_css_set_property (css, "stroke","none");
+ arrow_data->setAttribute("transform", NULL);
+ sp_repr_css_attr_add_from_string(css, arrows_format.param_getSVGValue());
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ arrow_data->setAttribute("style", css_str.c_str());
+ }
+ }
+ } else {
+ arrow = xml_doc->createElement("svg:marker");
+ arrow->setAttribute("id", mode);
+ arrow->setAttribute("inkscape:stockid", mode);
+ arrow->setAttribute("orient", "auto");
+ arrow->setAttribute("refX", "0.0");
+ arrow->setAttribute("refY", "0.0");
+ arrow->setAttribute("style", "overflow:visible");
+ arrow->setAttribute("sodipodi:insensitive", "true");
+ /* Create <path> */
+ Inkscape::XML::Node *arrow_path = xml_doc->createElement("svg:path");
+ if (std::strcmp(mode, "ArrowDIN-start") == 0) {
+ arrow_path->setAttribute("d", "M -8,0 8,-2.11 8,2.11 z");
+ } else if (std::strcmp(mode, "ArrowDIN-end") == 0) {
+ arrow_path->setAttribute("d", "M 8,0 -8,2.11 -8,-2.11 z");
+ } else if (std::strcmp(mode, "ArrowDINout-start") == 0) {
+ arrow_path->setAttribute("d", "M 0,0 -16,2.11 -16,0.5 -26,0.5 -26,-0.5 -16,-0.5 -16,-2.11 z");
+ } else {
+ arrow_path->setAttribute("d", "M 0,0 16,2.11 16,0.5 26,0.5 26,-0.5 16,-0.5 16,-2.11 z");
+ }
+
+ arrow_path->setAttribute("id", Glib::ustring(mode).append("_path").c_str());
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property (css, "fill","#000000");
+ sp_repr_css_set_property (css, "stroke","none");
+ sp_repr_css_attr_add_from_string(css, arrows_format.param_getSVGValue());
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ arrow_path->setAttribute("style", css_str.c_str());
+ arrow->addChild(arrow_path, NULL);
+ Inkscape::GC::release(arrow_path);
+ elemref = SP_OBJECT(document->getDefs()->appendChildRepr(arrow));
+ Inkscape::GC::release(arrow);
+ }
+ items.push_back(mode);
+}
+
+void
+LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove, bool valid)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ Inkscape::XML::Node *rtext = NULL;
+ double doc_w = document->getRoot()->width.value;
+ Geom::Scale scale = document->getDocumentScale();
+ SPNamedView *nv = sp_document_namedview(document, NULL);
+ Glib::ustring display_unit = nv->display_units->abbr;
+ if (display_unit.empty()) {
+ display_unit = "px";
+ }
+ //only check constrain viewbox on X
+ doc_scale = Inkscape::Util::Quantity::convert( scale[Geom::X], "px", nv->display_units );
+ if( doc_scale > 0 ) {
+ doc_scale= 1.0/doc_scale;
+ } else {
+ doc_scale = 1.0;
+ }
+ const char * id = g_strdup(Glib::ustring("text-on-").append(this->getRepr()->attribute("id")).c_str());
+ SPObject *elemref = NULL;
+ Inkscape::XML::Node *rtspan = NULL;
+ if ((elemref = document->getObjectById(id))) {
+ if (remove) {
+ elemref->deleteObject();
+ return;
+ }
+ pos = pos - Point::polar(angle, text_right_left);
+ rtext = elemref->getRepr();
+ sp_repr_set_svg_double(rtext, "x", pos[Geom::X]);
+ sp_repr_set_svg_double(rtext, "y", pos[Geom::Y]);
+ rtext->setAttribute("sodipodi:insensitive", "true");
+ rtext->setAttribute("transform", NULL);
+ } else {
+ if (remove) {
+ return;
+ }
+ rtext = xml_doc->createElement("svg:text");
+ rtext->setAttribute("xml:space", "preserve");
+ rtext->setAttribute("id", id);
+ rtext->setAttribute("sodipodi:insensitive", "true");
+ pos = pos - Point::polar(angle, text_right_left);
+ sp_repr_set_svg_double(rtext, "x", pos[Geom::X]);
+ sp_repr_set_svg_double(rtext, "y", pos[Geom::Y]);
+ rtspan = xml_doc->createElement("svg:tspan");
+ rtspan->setAttribute("sodipodi:role", "line");
+ }
+ gchar * transform;
+ Geom::Affine affine = Geom::Affine(Geom::Translate(pos).inverse());
+ angle = std::fmod(angle, 2*M_PI);
+ if (angle < 0) angle += 2*M_PI;
+ if (angle >= rad_from_deg(90) && angle < rad_from_deg(270)) {
+ angle = std::fmod(angle + rad_from_deg(180), 2*M_PI);
+ if (angle < 0) angle += 2*M_PI;
+ }
+ affine *= Geom::Rotate(angle);
+ affine *= Geom::Translate(pos);
+ if (rotate_anotation) {
+ transform = sp_svg_transform_write(affine);
+ } else {
+ transform = NULL;
+ }
+ rtext->setAttribute("transform", transform);
+ g_free(transform);
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css, anotation_format.param_getSVGValue());
+ Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance();
+ fontlister->fill_css(css, Glib::ustring(fontbutton.param_getSVGValue()));
+ std::stringstream font_size;
+ font_size.imbue(std::locale::classic());
+ font_size << fontsize << "pt";
+ sp_repr_css_set_property (css, "font-size",font_size.str().c_str());
+ sp_repr_css_set_property (css, "line-height","125%");
+ sp_repr_css_set_property (css, "letter-spacing","0");
+ sp_repr_css_set_property (css, "word-spacing", "0");
+ sp_repr_css_set_property (css, "text-align", "center");
+ sp_repr_css_set_property (css, "text-anchor", "middle");
+ sp_repr_css_set_property (css, "fill", "#000000");
+ sp_repr_css_set_property (css, "fill-opacity", "1");
+ sp_repr_css_set_property (css, "stroke", "none");
+ sp_repr_css_attr_add_from_string(css, anotation_format.param_getSVGValue());
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ if (!rtspan) {
+ rtspan = rtext->firstChild();
+ }
+ rtext->setAttribute("style", css_str.c_str());
+ rtspan->setAttribute("style", NULL);
+ rtspan->setAttribute("transform", NULL);
+ sp_repr_css_attr_unref (css);
+ if (!elemref) {
+ rtext->addChild(rtspan, NULL);
+ Inkscape::GC::release(rtspan);
+ }
+ length = Inkscape::Util::Quantity::convert(length / doc_scale, display_unit.c_str(), unit.get_abbreviation());
+ char *oldlocale = g_strdup (setlocale(LC_NUMERIC, NULL));
+ if (local_locale) {
+ setlocale (LC_NUMERIC, "");
+ } else {
+ setlocale (LC_NUMERIC, "C");
+ }
+ gchar length_str[64];
+ g_snprintf(length_str, 64, "%.*f", (int)precision, length);
+ setlocale (LC_NUMERIC, oldlocale);
+ g_free (oldlocale);
+ Glib::ustring label_value(format.param_getSVGValue());
+ size_t s = label_value.find(Glib::ustring("{measure}"),0);
+ if(s < label_value.length()) {
+ label_value.replace(s,s+9,length_str);
+ }
+ s = label_value.find(Glib::ustring("{unit}"),0);
+ if(s < label_value.length()) {
+ label_value.replace(s,s+6,unit.get_abbreviation());
+ }
+ if ( !valid ) {
+ label_value = Glib::ustring(_("Non Uniform Scale"));
+ }
+ Inkscape::XML::Node *rstring = NULL;
+ if (!elemref) {
+ rstring = xml_doc->createTextNode(label_value.c_str());
+ rtspan->addChild(rstring, NULL);
+ Inkscape::GC::release(rstring);
+ } else {
+ rstring = rtspan->firstChild();
+ rstring->setContent(label_value.c_str());
+ }
+ if (!elemref) {
+ elemref = sp_lpe_item->parent->appendChildRepr(rtext);
+ Inkscape::GC::release(rtext);
+ } else if (elemref->parent != sp_lpe_item->parent) {
+ Inkscape::XML::Node *old_repr = elemref->getRepr();
+ Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
+ SPObject * elemref_copy = sp_lpe_item->parent->appendChildRepr(copy);
+ Inkscape::GC::release(copy);
+ elemref->deleteObject();
+ copy->setAttribute("id", id);
+ elemref = elemref_copy;
+ }
+ items.push_back(id);
+ Geom::OptRect bounds = SP_ITEM(elemref)->bounds(SPItem::GEOMETRIC_BBOX);
+ if (bounds) {
+ anotation_width = bounds->width() * 1.15;
+ }
+}
+
+void
+LPEMeasureLine::createLine(Geom::Point start,Geom::Point end, const char * id, bool main, bool overflow, bool remove, bool arrows)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ SPObject *elemref = NULL;
+ Inkscape::XML::Node *line = NULL;
+ if (!main) {
+ Geom::Ray ray(start, end);
+ Geom::Coord angle = ray.angle();
+ start = start + Point::polar(angle, helpline_distance );
+ end = end + Point::polar(angle, helpline_overlap );
+ }
+ Geom::PathVector line_pathv;
+ if (main && std::abs(text_top_bottom) < fontsize/1.5 && hide_back && !overflow){
+ Geom::Path line_path;
+ double k = 0;
+ if (flip_side) {
+ k = (Geom::distance(start,end)/2.0) + arrow_gap - (anotation_width/2.0);
+ } else {
+ k = (Geom::distance(start,end)/2.0) - arrow_gap - (anotation_width/2.0);
+ }
+ if (Geom::distance(start,end) < anotation_width){
+ if ((elemref = document->getObjectById(id))) {
+ if (remove) {
+ elemref->deleteObject();
+ }
+ return;
+ }
+ }
+ //k = std::max(k , arrow_gap -1);
+ Geom::Ray ray(end, start);
+ Geom::Coord angle = ray.angle();
+ line_path.start(start);
+ line_path.appendNew<Geom::LineSegment>(start - Point::polar(angle, k));
+ line_pathv.push_back(line_path);
+ line_path.clear();
+ line_path.start(end + Point::polar(angle, k));
+ line_path.appendNew<Geom::LineSegment>(end);
+ line_pathv.push_back(line_path);
+ } else {
+ Geom::Path line_path;
+ line_path.start(start);
+ line_path.appendNew<Geom::LineSegment>(end);
+ line_pathv.push_back(line_path);
+ }
+ if ((elemref = document->getObjectById(id))) {
+ if (remove) {
+ elemref->deleteObject();
+ return;
+ }
+ line = elemref->getRepr();
+
+ gchar * line_str = sp_svg_write_path( line_pathv );
+ line->setAttribute("d" , line_str);
+ line->setAttribute("transform", NULL);
+ g_free(line_str);
+ } else {
+ if (remove) {
+ return;
+ }
+ line = xml_doc->createElement("svg:path");
+ line->setAttribute("id", id);
+ gchar * line_str = sp_svg_write_path( line_pathv );
+ line->setAttribute("d" , line_str);
+ g_free(line_str);
+ }
+ line->setAttribute("sodipodi:insensitive", "true");
+ line_pathv.clear();
+
+ Glib::ustring style = Glib::ustring("stroke:#000000;fill:none;");
+ if (overflow && !arrows) {
+ line->setAttribute("inkscape:label", "downline");
+ } else if (main) {
+ line->setAttribute("inkscape:label", "dinline");
+ if (arrows_outside) {
+ style = style + Glib::ustring("marker-start:url(#ArrowDINout-start);marker-end:url(#ArrowDINout-end);");
+ } else {
+ style = style + Glib::ustring("marker-start:url(#ArrowDIN-start);marker-end:url(#ArrowDIN-end);");
+ }
+ } else {
+ line->setAttribute("inkscape:label", "dinhelpline");
+ }
+ std::stringstream stroke_w;
+ stroke_w.imbue(std::locale::classic());
+ if (line_group_05) {
+ double stroke_width = Inkscape::Util::Quantity::convert(0.25 / doc_scale, "mm", display_unit.c_str());
+ stroke_w << stroke_width;
+ style = style + Glib::ustring("stroke-width:" + stroke_w.str());
+ } else {
+ double stroke_width = Inkscape::Util::Quantity::convert(0.35 / doc_scale, "mm", display_unit.c_str());
+ stroke_w << stroke_width;
+ style = style + Glib::ustring("stroke-width:" + stroke_w.str());
+ }
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css, style.c_str());
+ if (main) {
+ sp_repr_css_attr_add_from_string(css, dimline_format.param_getSVGValue());
+ } else {
+ sp_repr_css_attr_add_from_string(css, helperlines_format.param_getSVGValue());
+ }
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ line->setAttribute("style", css_str.c_str());
+ if (!elemref) {
+ elemref = sp_lpe_item->parent->appendChildRepr(line);
+ Inkscape::GC::release(line);
+ } else if (elemref->parent != sp_lpe_item->parent) {
+ Inkscape::XML::Node *old_repr = elemref->getRepr();
+ Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
+ SPObject * elemref_copy = sp_lpe_item->parent->appendChildRepr(copy);
+ Inkscape::GC::release(copy);
+ elemref->deleteObject();
+ copy->setAttribute("id", id);
+ }
+ items.push_back(id);
+}
+
+void
+LPEMeasureLine::doOnApply(SPLPEItem const* lpeitem)
+{
+ if (!SP_IS_SHAPE(lpeitem)) {
+ g_warning("LPE measure line can only be applied to shapes (not groups).");
+ SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
+ item->removeCurrentPathEffect(false);
+ }
+ id_origin.param_setValue(Glib::ustring(lpeitem->getId()));
+ id_origin.write_to_SVG();
+}
+
+void
+LPEMeasureLine::doBeforeEffect (SPLPEItem const* lpeitem)
+{
+ SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem);
+ sp_lpe_item->parent = dynamic_cast<SPObject *>(splpeitem->parent);
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Node *root = splpeitem->document->getReprRoot();
+ Inkscape::XML::Node *root_origin = document->getReprRoot();
+ if (root_origin != root) {
+ return;
+ }
+ SPPath *sp_path = dynamic_cast<SPPath *>(splpeitem);
+ if (sp_path) {
+ Geom::Affine affinetransform = i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(document->getRoot()));
+ Geom::PathVector pathvector = sp_path->get_original_curve()->get_pathvector();
+ Geom::Affine writed_transform = Geom::identity();
+ sp_svg_transform_read(splpeitem->getAttribute("transform"), &writed_transform );
+ pathvector *= writed_transform;
+ if ((Glib::ustring(format.param_getSVGValue()).empty())) {
+ format.param_setValue(Glib::ustring("{measure}{unit}"));
+ }
+ size_t ncurves = pathvector.curveCount();
+ if (ncurves != (size_t)curve_linked.param_get_max()) {
+ curve_linked.param_set_range(0, ncurves);
+ }
+ Geom::Point start = pathvector.initialPoint();
+ Geom::Point end = pathvector.finalPoint();
+ if (curve_linked) { //!0
+ start = pathvector.pointAt(curve_linked -1);
+ end = pathvector.pointAt(curve_linked);
+ }
+ if (Geom::are_near(start, start_stored, 0.01) &&
+ Geom::are_near(end, end_stored, 0.01) &&
+ sp_lpe_item->getCurrentLPE() != this){
+ return;
+ }
+ items.clear();
+ start_stored = start;
+ end_stored = end;
+ Geom::Point hstart = start;
+ Geom::Point hend = end;
+ bool remove = false;
+ if (Geom::are_near(hstart, hend)) {
+ remove = true;
+ }
+ if (orientation == OM_VERTICAL) {
+ Coord xpos = std::max(hstart[Geom::X],hend[Geom::X]);
+ if (flip_side) {
+ xpos = std::min(hstart[Geom::X],hend[Geom::X]);
+ }
+ hstart[Geom::X] = xpos;
+ hend[Geom::X] = xpos;
+ if (hstart[Geom::Y] > hend[Geom::Y]) {
+ swap(hstart,hend);
+ swap(start,end);
+ }
+ if (Geom::are_near(hstart[Geom::Y], hend[Geom::Y])) {
+ remove = true;
+ }
+ }
+ if (orientation == OM_HORIZONTAL) {
+ Coord ypos = std::max(hstart[Geom::Y],hend[Geom::Y]);
+ if (flip_side) {
+ ypos = std::min(hstart[Geom::Y],hend[Geom::Y]);
+ }
+ hstart[Geom::Y] = ypos;
+ hend[Geom::Y] = ypos;
+ if (hstart[Geom::X] < hend[Geom::X]) {
+ swap(hstart,hend);
+ swap(start,end);
+ }
+ if (Geom::are_near(hstart[Geom::X], hend[Geom::X])) {
+ remove = true;
+ }
+ }
+ double length = Geom::distance(hstart,hend) * scale;
+ Geom::Point pos = Geom::middle_point(hstart,hend);
+ Geom::Ray ray(hstart,hend);
+ Geom::Coord angle = ray.angle();
+ if (flip_side) {
+ angle = std::fmod(angle + rad_from_deg(180), 2*M_PI);
+ if (angle < 0) angle += 2*M_PI;
+ }
+ if (arrows_outside) {
+ createArrowMarker("ArrowDINout-start");
+ createArrowMarker("ArrowDINout-end");
+ } else {
+ createArrowMarker("ArrowDIN-start");
+ createArrowMarker("ArrowDIN-end");
+ }
+ //We get the font size to offset the text to the middle
+ Pango::FontDescription fontdesc(Glib::ustring(fontbutton.param_getSVGValue()));
+ fontsize = fontdesc.get_size()/(double)Pango::SCALE;
+ fontsize *= document->getRoot()->c2p.inverse().expansionX();
+ Geom::Coord angle_cross = std::fmod(angle + rad_from_deg(90), 2*M_PI);
+ if (angle_cross < 0) angle_cross += 2*M_PI;
+ angle = std::fmod(angle, 2*M_PI);
+ if (angle < 0) angle += 2*M_PI;
+ if (angle >= rad_from_deg(90) && angle < rad_from_deg(270)) {
+ pos = pos - Point::polar(angle_cross, (position - text_top_bottom) + fontsize/2.5);
+ } else {
+ pos = pos - Point::polar(angle_cross, (position + text_top_bottom) - fontsize/2.5);
+ }
+ double parents_scale = (affinetransform.expansionX() + affinetransform.expansionY()) / 2.0;
+ if (scale_sensitive) {
+ length *= parents_scale;
+ }
+ if (scale_sensitive && !affinetransform.preservesAngles()) {
+ createTextLabel(pos, length, angle, remove, false);
+ } else {
+ createTextLabel(pos, length, angle, remove, true);
+ }
+ bool overflow = false;
+ const char * downline = g_strdup(Glib::ustring("downline-").append(this->getRepr()->attribute("id")).c_str());
+ //delete residual lines if exist
+ createLine(Geom::Point(),Geom::Point(), downline, true, overflow, true, false);
+ //Create it
+ if ((anotation_width/2) + std::abs(text_right_left) > Geom::distance(start,end)/2.0) {
+ Geom::Point sstart = end - Point::polar(angle_cross, position);
+ Geom::Point send = end - Point::polar(angle_cross, position);
+ if ((text_right_left < 0 && flip_side) || (text_right_left > 0 && !flip_side)) {
+ sstart = start - Point::polar(angle_cross, position);
+ send = start - Point::polar(angle_cross, position);
+ }
+ Geom::Point prog_end = Geom::Point();
+ if (std::abs(text_top_bottom) < fontsize/1.5 && hide_back) {
+ if (text_right_left > 0 ) {
+ prog_end = sstart - Point::polar(angle, std::abs(text_right_left) - (anotation_width/1.9) - (Geom::distance(start,end)/2.0));
+ } else {
+ prog_end = sstart + Point::polar(angle, std::abs(text_right_left) - (anotation_width/1.9) - (Geom::distance(start,end)/2.0));
+ }
+ } else {
+ if (text_right_left > 0 ) {
+ prog_end = sstart - Point::polar(angle,(anotation_width/2) + std::abs(text_right_left) - (Geom::distance(start,end)/2.0));
+ } else {
+ prog_end = sstart + Point::polar(angle,(anotation_width/2) + std::abs(text_right_left) - (Geom::distance(start,end)/2.0));
+ }
+ }
+ overflow = true;
+ createLine(sstart, prog_end, downline, true, overflow, false, false);
+ }
+ //LINE
+ arrow_gap = 8 * Inkscape::Util::Quantity::convert(0.35 / doc_scale, "mm", display_unit.c_str());
+ if (line_group_05) {
+ arrow_gap = 8 * Inkscape::Util::Quantity::convert(0.25 / doc_scale, "mm", display_unit.c_str());
+ }
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css, dimline_format.param_getSVGValue());
+ char *oldlocale = g_strdup (setlocale(LC_NUMERIC, NULL));
+ setlocale (LC_NUMERIC, "C");
+ double width_line = atof(sp_repr_css_property(css,"stroke-width","-1"));
+ setlocale (LC_NUMERIC, oldlocale);
+ g_free (oldlocale);
+ if (width_line > -0.0001) {
+ arrow_gap = 8 * Inkscape::Util::Quantity::convert(width_line/ doc_scale, "mm", display_unit.c_str());
+ }
+ if (flip_side) {
+ arrow_gap *= -1;
+ }
+ hstart = hstart - Point::polar(angle_cross, position);
+ createLine(start, hstart, g_strdup(Glib::ustring("infoline-on-start-").append(this->getRepr()->attribute("id")).c_str()), false, false, remove);
+ hend = hend - Point::polar(angle_cross, position);
+ createLine(end, hend, g_strdup(Glib::ustring("infoline-on-end-").append(this->getRepr()->attribute("id")).c_str()), false, false, remove);
+ if (!arrows_outside) {
+ hstart = hstart + Point::polar(angle, arrow_gap);
+ hend = hend - Point::polar(angle, arrow_gap );
+ }
+ createLine(hstart, hend, g_strdup(Glib::ustring("infoline-").append(this->getRepr()->attribute("id")).c_str()), true, overflow, remove, true);
+ }
+}
+
+void
+LPEMeasureLine::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
+{
+ processObjects(LPE_VISIBILITY);
+}
+
+void
+LPEMeasureLine::doOnRemove (SPLPEItem const* /*lpeitem*/)
+{
+ //set "keep paths" hook on sp-lpe-item.cpp
+ if (keep_paths) {
+ processObjects(LPE_TO_OBJECTS);
+ items.clear();
+ return;
+ }
+ processObjects(LPE_ERASE);
+}
+
+Gtk::Widget *LPEMeasureLine::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might
+ // still be pointing to this widget.
+ Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
+
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(2);
+
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) );
+ vbox_expander->set_border_width(0);
+ vbox_expander->set_spacing(2);
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter *param = *it;
+ Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
+ Glib::ustring *tip = param->param_getTooltip();
+ if (widg) {
+ if (param->param_key != "dimline_format" &&
+ param->param_key != "helperlines_format" &&
+ param->param_key != "arrows_format" &&
+ param->param_key != "anotation_format") {
+ vbox->pack_start(*widg, true, true, 2);
+ } else {
+ vbox_expander->pack_start(*widg, true, true, 2);
+ }
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+
+ ++it;
+ }
+ expander = Gtk::manage(new Gtk::Expander(Glib::ustring(_("Show DIM CSS style override"))));
+ expander->add(*vbox_expander);
+ expander->set_expanded(expanded);
+ expander->property_expanded().signal_changed().connect(sigc::mem_fun(*this, &LPEMeasureLine::onExpanderChanged) );
+ vbox->pack_start(*expander, true, true, 2);
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+void
+LPEMeasureLine::onExpanderChanged()
+{
+ expanded = expander->get_expanded();
+ if(expanded) {
+ expander->set_label (Glib::ustring(_("Hide DIM CSS style override")));
+ } else {
+ expander->set_label (Glib::ustring(_("Show DIM CSS style override")));
+ }
+}
+
+Geom::PathVector
+LPEMeasureLine::doEffect_path(Geom::PathVector const &path_in)
+{
+ return path_in;
+}
+
+}; //namespace LivePathEffect
+}; /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offset:((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 :
diff --git a/src/live_effects/lpe-measure-line.h b/src/live_effects/lpe-measure-line.h
new file mode 100644
index 000000000..b42f7cfd5
--- /dev/null
+++ b/src/live_effects/lpe-measure-line.h
@@ -0,0 +1,107 @@
+#ifndef INKSCAPE_LPE_MEASURE_LINE_H
+#define INKSCAPE_LPE_MEASURE_LINE_H
+
+/*
+ * Author(s):
+ * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ *
+ * Copyright (C) 2014 Author(s)
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/effect.h"
+
+#include <gtkmm/expander.h>
+
+#include "live_effects/parameter/enum.h"
+#include "live_effects/parameter/fontbutton.h"
+#include "live_effects/parameter/text.h"
+#include "live_effects/parameter/unit.h"
+#include "live_effects/parameter/bool.h"
+#include "live_effects/parameter/originalpath.h"
+#include <libnrtype/font-lister.h>
+#include <2geom/angle.h>
+#include <2geom/ray.h>
+#include <2geom/point.h>
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+enum OrientationMethod {
+ OM_HORIZONTAL,
+ OM_VERTICAL,
+ OM_PARALLEL,
+ OM_END
+};
+
+class LPEMeasureLine : public Effect {
+public:
+ LPEMeasureLine(LivePathEffectObject *lpeobject);
+ virtual ~LPEMeasureLine();
+ virtual void doBeforeEffect (SPLPEItem const* lpeitem);
+ virtual void doOnApply(SPLPEItem const* lpeitem);
+ virtual void doOnRemove (SPLPEItem const* /*lpeitem*/);
+ virtual void doEffect (SPCurve * curve){}; //stop the chain
+ virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/);
+ virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in);
+ void createLine(Geom::Point start,Geom::Point end, const char * id, bool main, bool overflow, bool remove, bool arrows = false);
+ void createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove, bool valid);
+ void onExpanderChanged();
+ void createArrowMarker(const char * mode);
+ virtual Gtk::Widget *newWidget();
+private:
+ UnitParam unit;
+ FontButtonParam fontbutton;
+ EnumParam<OrientationMethod> orientation;
+ ScalarParam curve_linked;
+ ScalarParam precision;
+ ScalarParam position;
+ ScalarParam text_top_bottom;
+ ScalarParam text_right_left;
+ ScalarParam helpline_distance;
+ ScalarParam helpline_overlap;
+ ScalarParam scale;
+ TextParam format;
+ TextParam id_origin;
+ BoolParam arrows_outside;
+ BoolParam flip_side;
+ BoolParam scale_sensitive;
+ BoolParam local_locale;
+ BoolParam line_group_05;
+ BoolParam rotate_anotation;
+ BoolParam hide_back;
+ TextParam dimline_format;
+ TextParam helperlines_format;
+ TextParam anotation_format;
+ TextParam arrows_format;
+ Glib::ustring display_unit;
+ bool expanded;
+ Gtk::Expander * expander;
+ double doc_scale;
+ double fontsize;
+ double anotation_width;
+ double arrow_gap;
+ Geom::Point start_stored;
+ Geom::Point end_stored;
+/* Geom::Affine affine_over;*/
+ LPEMeasureLine(const LPEMeasureLine &);
+ LPEMeasureLine &operator=(const LPEMeasureLine &);
+
+};
+
+} //namespace LivePathEffect
+} //namespace Inkscape
+
+#endif
+
+/*
+ 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 :
diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp
index 9f3070ff4..5d80d65fe 100644
--- a/src/live_effects/lpe-mirror_symmetry.cpp
+++ b/src/live_effects/lpe-mirror_symmetry.cpp
@@ -13,77 +13,73 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <gtkmm.h>
-#include <glibmm/i18n.h>
+#include <gtkmm.h>
+#include "live_effects/lpeobject.h"
+#include "live_effects/lpeobject-reference.h"
#include "live_effects/lpe-mirror_symmetry.h"
-#include <sp-path.h>
-#include <display/curve.h>
-#include <svg/path-string.h>
+#include "display/curve.h"
+#include "svg/path-string.h"
+#include "svg/svg.h"
+#include "sp-defs.h"
+#include "helper/geom.h"
+#include "2geom/intersection-graph.h"
+#include "2geom/path-intersection.h"
+#include "2geom/affine.h"
#include "helper/geom.h"
-#include <2geom/path.h>
-#include <2geom/path-intersection.h>
-#include <2geom/transforms.h>
-#include <2geom/affine.h>
-#include "knot-holder-entity.h"
-#include "knotholder.h"
-#include "inkscape.h"
+#include "sp-lpe-item.h"
+#include "path-chemistry.h"
+#include "style.h"
+#include "xml/sp-css-attr.h"
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
static const Util::EnumData<ModeType> ModeTypeData[MT_END] = {
- { MT_V, N_("Vertical Page Center"), "Vertical Page Center, use select tool to move item instead line" },
- { MT_H, N_("Horizontal Page Center"), "Horizontal Page Center, use select tool to move item instead line" },
- { MT_FREE, N_("Free from reflection line"), "Free from path" },
- { MT_X, N_("X from middle knot"), "X from middle knot" },
- { MT_Y, N_("Y from middle knot"), "Y from middle knot" }
+ { MT_V, N_("Vertical Page Center"), "vertical" },
+ { MT_H, N_("Horizontal Page Center"), "horizontal" },
+ { MT_FREE, N_("Free from reflection line"), "free" },
+ { MT_X, N_("X from middle knot"), "X" },
+ { MT_Y, N_("Y from middle knot"), "Y" }
};
static const Util::EnumDataConverter<ModeType>
MTConverter(ModeTypeData, MT_END);
-namespace MS {
-
-class KnotHolderEntityCenterMirrorSymmetry : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityCenterMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
-};
-
-class KnotHolderEntityStartMirrorSymmetry : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityStartMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
-};
-
-class KnotHolderEntityEndMirrorSymmetry : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityEndMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
-};
-
-} // namespace MS
-
LPEMirrorSymmetry::LPEMirrorSymmetry(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
mode(_("Mode"), _("Symmetry move mode"), "mode", MTConverter, &wr, this, MT_FREE),
- discard_orig_path(_("Discard original path?"), _("Check this to only keep the mirrored part of the path"), "discard_orig_path", &wr, this, false),
+ split_gap(_("Gap on split"), _("Gap on split"), "split_gap", &wr, this, -0.001),
+ discard_orig_path(_("Discard original path"), _("Check this to only keep the mirrored part of the path"), "discard_orig_path", &wr, this, false),
fuse_paths(_("Fuse paths"), _("Fuse original and the reflection into a single path"), "fuse_paths", &wr, this, false),
oposite_fuse(_("Opposite fuse"), _("Picks the other side of the mirror as the original"), "oposite_fuse", &wr, this, false),
- start_point(_("Start mirror line"), _("Start mirror line"), "start_point", &wr, this, "Adjust the start of mirroring"),
- end_point(_("End mirror line"), _("End mirror line"), "end_point", &wr, this, "Adjust end of mirroring")
+ split_items(_("Split elements"), _("Split elements, this allow gradients and other paints."), "split_items", &wr, this, false),
+ start_point(_("Start mirror line"), _("Start mirror line"), "start_point", &wr, this, _("Adjust start of mirroring")),
+ end_point(_("End mirror line"), _("End mirror line"), "end_point", &wr, this, _("Adjust end of mirroring")),
+ center_point(_("Center mirror line"), _("Center mirror line"), "center_point", &wr, this, _("Adjust center of mirroring")),
+ id_origin("id origin", "store the id of the first LPEItem", "id_origin", &wr, this,"")
{
show_orig_path = true;
registerParameter(&mode);
- registerParameter( &discard_orig_path);
- registerParameter( &fuse_paths);
- registerParameter( &oposite_fuse);
- registerParameter( &start_point);
- registerParameter( &end_point);
+ registerParameter(&split_gap);
+ registerParameter(&discard_orig_path);
+ registerParameter(&fuse_paths);
+ registerParameter(&oposite_fuse);
+ registerParameter(&split_items);
+ registerParameter(&start_point);
+ registerParameter(&end_point);
+ registerParameter(&center_point);
+ registerParameter(&id_origin);
+ id_origin.param_hide_canvas_text();
+ split_gap.param_set_range(-999999.0, 999999.0);
+ split_gap.param_set_increments(0.1, 0.1);
+ split_gap.param_set_digits(5);
apply_to_clippath_and_mask = true;
+ previous_center = Geom::Point(0,0);
+ id_origin.param_widget_is_visible(false);
+ center_point.param_widget_is_visible(false);
}
LPEMirrorSymmetry::~LPEMirrorSymmetry()
@@ -91,14 +87,39 @@ LPEMirrorSymmetry::~LPEMirrorSymmetry()
}
void
+LPEMirrorSymmetry::doAfterEffect (SPLPEItem const* lpeitem)
+{
+ is_load = false;
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ if (split_items && !discard_orig_path) {
+ container = dynamic_cast<SPObject *>(sp_lpe_item->parent);
+ Inkscape::XML::Node *root = sp_lpe_item->document->getReprRoot();
+ Inkscape::XML::Node *root_origin = document->getReprRoot();
+ if (root_origin != root) {
+ return;
+ }
+ Geom::Line ls((Geom::Point)start_point, (Geom::Point)end_point);
+ Geom::Affine m = Geom::reflection (ls.vector(), (Geom::Point)start_point);
+ m = m * sp_lpe_item->transform;
+ toMirror(m);
+ } else {
+ processObjects(LPE_ERASE);
+ items.clear();
+ }
+}
+void
LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem)
{
- using namespace Geom;
+ using namespace Geom;
+ original_bbox(lpeitem);
+ //center_point->param_set_liveupdate(false);
Point point_a(boundingbox_X.max(), boundingbox_Y.min());
Point point_b(boundingbox_X.max(), boundingbox_Y.max());
- Point point_c(boundingbox_X.max(), boundingbox_Y.middle());
if (mode == MT_Y) {
point_a = Geom::Point(boundingbox_X.min(),center_point[Y]);
point_b = Geom::Point(boundingbox_X.max(),center_point[Y]);
@@ -107,52 +128,216 @@ LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem)
point_a = Geom::Point(center_point[X],boundingbox_Y.min());
point_b = Geom::Point(center_point[X],boundingbox_Y.max());
}
- line_separation.setPoints(point_a, point_b);
- if ( mode == MT_X || mode == MT_Y ) {
+ if ((Geom::Point)start_point == (Geom::Point)end_point) {
start_point.param_setValue(point_a);
end_point.param_setValue(point_b);
- center_point = Geom::middle_point(point_a, point_b);
+ previous_center = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
+ center_point.param_setValue(previous_center);
+ return;
+ }
+ if ( mode == MT_X || mode == MT_Y ) {
+ if (!are_near(previous_center, (Geom::Point)center_point, 0.01)) {
+ center_point.param_setValue(Geom::middle_point(point_a, point_b), true);
+ end_point.param_setValue(point_b);
+ start_point.param_setValue(point_a);
+ } else {
+ if ( mode == MT_X ) {
+ if (!are_near(start_point[X], point_a[X], 0.01)) {
+ start_point.param_setValue(point_a);
+ }
+ if (!are_near(end_point[X], point_b[X], 0.01)) {
+ end_point.param_setValue(point_b);
+ }
+ } else { //MT_Y
+ if (!are_near(start_point[Y], point_a[Y], 0.01)) {
+ start_point.param_setValue(point_a);
+ }
+ if (!are_near(end_point[Y], point_b[Y], 0.01)) {
+ end_point.param_setValue(point_b);
+ }
+ }
+ }
} else if ( mode == MT_FREE) {
- if(!are_near(previous_center,center_point, 0.01)) {
- Geom::Point trans = center_point - previous_center;
+ if (are_near(previous_center, (Geom::Point)center_point, 0.01)) {
+ center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point));
+ } else {
+ Geom::Point trans = center_point - Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
start_point.param_setValue(start_point * trans);
end_point.param_setValue(end_point * trans);
- line_separation.setPoints(start_point, end_point);
- } else {
- center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
- line_separation.setPoints(start_point, end_point);
}
} else if ( mode == MT_V){
- if(SP_ACTIVE_DESKTOP){
- SPDocument * doc = SP_ACTIVE_DESKTOP->getDocument();
- Geom::Rect view_box_rect = doc->getViewBox();
- Geom::Point sp = Geom::Point(view_box_rect.width()/2.0, 0);
- sp *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse();
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (document) {
+ Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), NULL).inverse();
+ Geom::Point sp = Geom::Point(document->getWidth().value("px")/2.0, 0) * transform;
start_point.param_setValue(sp);
- Geom::Point ep = Geom::Point(view_box_rect.width()/2.0, view_box_rect.height());
- ep *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse();
+ Geom::Point ep = Geom::Point(document->getWidth().value("px")/2.0, document->getHeight().value("px")) * transform;
end_point.param_setValue(ep);
- center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
- line_separation.setPoints(start_point, end_point);
+ center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point));
}
} else { //horizontal page
- if(SP_ACTIVE_DESKTOP){
- SPDocument * doc = SP_ACTIVE_DESKTOP->getDocument();
- Geom::Rect view_box_rect = doc->getViewBox();
- Geom::Point sp = Geom::Point(0, view_box_rect.height()/2.0);
- sp *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse();
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (document) {
+ Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), NULL).inverse();
+ Geom::Point sp = Geom::Point(0, document->getHeight().value("px")/2.0) * transform;
start_point.param_setValue(sp);
- Geom::Point ep = Geom::Point(view_box_rect.width(), view_box_rect.height()/2.0);
- ep *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse();
+ Geom::Point ep = Geom::Point(document->getWidth().value("px"), document->getHeight().value("px")/2.0) * transform;
end_point.param_setValue(ep);
- center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
- line_separation.setPoints(start_point, end_point);
+ center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point));
}
}
previous_center = center_point;
}
void
+LPEMirrorSymmetry::cloneD(SPObject *orig, SPObject *dest, bool live, bool root)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ if ( SP_IS_GROUP(orig) && SP_IS_GROUP(dest) && SP_GROUP(orig)->getItemCount() == SP_GROUP(dest)->getItemCount() ) {
+ std::vector< SPObject * > childs = orig->childList(true);
+ size_t index = 0;
+ for (std::vector<SPObject * >::iterator obj_it = childs.begin();
+ obj_it != childs.end(); ++obj_it) {
+ SPObject *dest_child = dest->nthChild(index);
+ cloneD(*obj_it, dest_child, live, false);
+ index++;
+ }
+ }
+ SPShape * shape = SP_SHAPE(orig);
+ SPPath * path = SP_PATH(dest);
+ if (shape && !path) {
+ Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0);
+ dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL);
+ path = SP_PATH(dest);
+ }
+ if (path && shape) {
+ if ( live) {
+ SPCurve *c = NULL;
+ if (root) {
+ c = new SPCurve();
+ c->set_pathvector(pathvector_after_effect);
+ } else {
+ c = shape->getCurve();
+ }
+ if (c) {
+ path->setCurve(c, TRUE);
+ c->unref();
+ } else {
+ dest->getRepr()->setAttribute("d", NULL);
+ }
+ } else {
+ dest->getRepr()->setAttribute("d", orig->getRepr()->attribute("d"));
+ }
+ }
+}
+
+void
+LPEMirrorSymmetry::toMirror(Geom::Affine transform)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (document) {
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ const char * id_origin_char = id_origin.param_getSVGValue();
+ const char * elemref_id = g_strdup(Glib::ustring("mirror-").append(id_origin_char).c_str());
+ items.clear();
+ items.push_back(elemref_id);
+ SPObject *elemref= NULL;
+ Inkscape::XML::Node *phantom = NULL;
+ if ((elemref = document->getObjectById(elemref_id))) {
+ phantom = elemref->getRepr();
+ } else {
+ phantom = sp_lpe_item->getRepr()->duplicate(xml_doc);
+ std::vector<const char *> attrs;
+ attrs.push_back("inkscape:path-effect");
+ attrs.push_back("inkscape:original-d");
+ attrs.push_back("sodipodi:type");
+ attrs.push_back("sodipodi:rx");
+ attrs.push_back("sodipodi:ry");
+ attrs.push_back("sodipodi:cx");
+ attrs.push_back("sodipodi:cy");
+ attrs.push_back("sodipodi:end");
+ attrs.push_back("sodipodi:start");
+ attrs.push_back("inkscape:flatsided");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:rounded");
+ attrs.push_back("sodipodi:arg1");
+ attrs.push_back("sodipodi:arg2");
+ attrs.push_back("sodipodi:r1");
+ attrs.push_back("sodipodi:r2");
+ attrs.push_back("sodipodi:sides");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("sodipodi:argument");
+ attrs.push_back("sodipodi:expansion");
+ attrs.push_back("sodipodi:radius");
+ attrs.push_back("sodipodi:revolution");
+ attrs.push_back("sodipodi:t0");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("x");
+ attrs.push_back("y");
+ attrs.push_back("rx");
+ attrs.push_back("ry");
+ attrs.push_back("width");
+ attrs.push_back("height");
+ for(const char * attr : attrs) {
+ phantom->setAttribute(attr, NULL);
+ }
+ }
+ phantom->setAttribute("id", elemref_id);
+ if (!elemref) {
+ elemref = container->appendChildRepr(phantom);
+ Inkscape::GC::release(phantom);
+ }
+ cloneD(SP_OBJECT(sp_lpe_item), elemref, true, true);
+ gchar *str = sp_svg_transform_write(transform);
+ elemref->getRepr()->setAttribute("transform" , str);
+ g_free(str);
+ if (elemref->parent != container) {
+ Inkscape::XML::Node *copy = phantom->duplicate(xml_doc);
+ copy->setAttribute("id", elemref_id);
+ container->appendChildRepr(copy);
+ Inkscape::GC::release(copy);
+ elemref->deleteObject();
+ }
+ }
+}
+
+//TODO: Migrate the tree next function to effect.cpp/h to avoid duplication
+void
+LPEMirrorSymmetry::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
+{
+ processObjects(LPE_VISIBILITY);
+}
+
+void
+LPEMirrorSymmetry::doOnRemove (SPLPEItem const* /*lpeitem*/)
+{
+ //set "keep paths" hook on sp-lpe-item.cpp
+ if (keep_paths) {
+ processObjects(LPE_TO_OBJECTS);
+ items.clear();
+ return;
+ }
+ processObjects(LPE_ERASE);
+}
+
+void
+LPEMirrorSymmetry::transform_multiply(Geom::Affine const& postmul, bool set)
+{
+ // cycle through all parameters. Most parameters will not need transformation, but path and point params do.
+ for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) {
+ Parameter * param = *it;
+ param->param_transform_multiply(postmul, set);
+ }
+ previous_center = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
+}
+
+void
LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem)
{
using namespace Geom;
@@ -166,14 +351,22 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem)
start_point.param_update_default(point_a);
end_point.param_setValue(point_b);
end_point.param_update_default(point_b);
- center_point = point_c;
+ center_point.param_setValue(point_c);
previous_center = center_point;
+ SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem);
+ if (!lpeitem->hasPathEffectOfType(this->effectType(), false) ){ //first applied not ready yet
+ id_origin.param_setValue(lpeitem->getRepr()->attribute("id"));
+ id_origin.write_to_SVG();
+ }
}
Geom::PathVector
LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
{
+ if (split_items && !fuse_paths) {
+ return path_in;
+ }
Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in);
Geom::PathVector path_out;
@@ -181,30 +374,53 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
path_out = pathv_to_linear_and_cubic_beziers(path_in);
}
- Geom::Point point_a(line_separation.initialPoint());
- Geom::Point point_b(line_separation.finalPoint());
-
- Geom::Translate m1(point_a[0], point_a[1]);
- double hyp = Geom::distance(point_a, point_b);
- double c = (point_b[0] - point_a[0]) / hyp; // cos(alpha)
- double s = (point_b[1] - point_a[1]) / hyp; // sin(alpha)
-
- Geom::Affine m2(c, -s, s, c, 0.0, 0.0);
- Geom::Scale sca(1.0, -1.0);
-
- Geom::Affine m = m1.inverse() * m2;
- m = m * sca;
- m = m * m2.inverse();
- m = m * m1;
-
- if (fuse_paths && !discard_orig_path) {
+ Geom::Line line_separation((Geom::Point)start_point, (Geom::Point)end_point);
+ Geom::Affine m = Geom::reflection (line_separation.vector(), (Geom::Point)start_point);
+ if (split_items && fuse_paths) {
+ Geom::OptRect bbox = sp_lpe_item->geometricBounds();
+ Geom::Path p(Geom::Point(bbox->left(), bbox->top()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->top()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->bottom()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->bottom()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->top()));
+ p.close();
+ p *= Geom::Translate(bbox->midpoint()).inverse();
+ p *= Geom::Scale(1.2);
+ p *= Geom::Rotate(line_separation.angle());
+ p *= Geom::Translate(bbox->midpoint());
+ bbox = p.boundsFast();
+ p.clear();
+ p.start(Geom::Point(bbox->left(), bbox->top()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->top()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->bottom()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->bottom()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->top()));
+ p.close();
+ p *= Geom::Translate(bbox->midpoint()).inverse();
+ p *= Geom::Rotate(line_separation.angle());
+ p *= Geom::Translate(bbox->midpoint());
+ Geom::Point base(p.pointAt(3));
+ if (oposite_fuse) {
+ base = p.pointAt(0);
+ }
+ p *= Geom::Translate(line_separation.pointAt(line_separation.nearestTime(base)) - base);
+ Geom::PathVector pv_bbox;
+ pv_bbox.push_back(p);
+ Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(pv_bbox, original_pathv);
+ if (pig && !original_pathv.empty() && !pv_bbox.empty()) {
+ path_out = pig->getBminusA();
+ }
+ Geom::Point dir = rot90(unit_vector((Geom::Point)end_point - (Geom::Point)start_point));
+ Geom::Point gap = dir * split_gap;
+ path_out *= Geom::Translate(gap);
+ } else if (fuse_paths && !discard_orig_path) {
for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
path_it != original_pathv.end(); ++path_it)
{
if (path_it->empty()) {
continue;
}
- Geom::PathVector tmp_path;
+ Geom::PathVector tmp_pathvector;
double time_start = 0.0;
int position = 0;
bool end_open = false;
@@ -250,11 +466,11 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
Geom::Path mirror = portion.reversed() * m;
mirror.setInitial(portion.finalPoint());
portion.append(mirror);
- if(i!=0) {
+ if(i != 0) {
portion.setFinal(portion.initialPoint());
portion.close();
}
- tmp_path.push_back(portion);
+ tmp_pathvector.push_back(portion);
}
portion.clear();
}
@@ -275,36 +491,33 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
portion.append(mirror);
portion = portion.reversed();
if (!original.closed()) {
- tmp_path.push_back(portion);
+ tmp_pathvector.push_back(portion);
} else {
- if (cs.size() > 1 && tmp_path.size() > 0 && tmp_path[0].size() > 0 ) {
- portion.setFinal(tmp_path[0].initialPoint());
- portion.setInitial(tmp_path[0].finalPoint());
- tmp_path[0].append(portion);
+ if (cs.size() > 1 && tmp_pathvector.size() > 0 && tmp_pathvector[0].size() > 0 ) {
+ portion.setFinal(tmp_pathvector[0].initialPoint());
+ portion.setInitial(tmp_pathvector[0].finalPoint());
+ tmp_pathvector[0].append(portion);
} else {
- tmp_path.push_back(portion);
+ tmp_pathvector.push_back(portion);
}
- tmp_path[0].close();
+ tmp_pathvector[0].close();
}
portion.clear();
}
}
}
if (cs.size() == 0 && position == 1) {
- tmp_path.push_back(original);
- tmp_path.push_back(original * m);
+ tmp_pathvector.push_back(original);
+ tmp_pathvector.push_back(original * m);
}
- path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end());
- tmp_path.clear();
+ path_out.insert(path_out.end(), tmp_pathvector.begin(), tmp_pathvector.end());
+ tmp_pathvector.clear();
}
- }
-
- if (!fuse_paths || discard_orig_path) {
- for (int i = 0; i < static_cast<int>(path_in.size()); ++i) {
- path_out.push_back(path_in[i] * m);
+ } else if (!fuse_paths || discard_orig_path) {
+ for (size_t i = 0; i < original_pathv.size(); ++i) {
+ path_out.push_back(original_pathv[i] * m);
}
}
-
return path_out;
}
@@ -323,44 +536,6 @@ LPEMirrorSymmetry::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector
hp_vec.push_back(helper);
}
-void
-LPEMirrorSymmetry::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
-{
- SPKnotShapeType knot_shape = SP_KNOT_SHAPE_CIRCLE;
- SPKnotModeType knot_mode = SP_KNOT_MODE_XOR;
- guint32 knot_color = 0x0000ff00;
- {
- KnotHolderEntity *c = new MS::KnotHolderEntityCenterMirrorSymmetry(this);
- c->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
- _("Adjust the center"), knot_shape, knot_mode, knot_color );
- knotholder->add(c);
- }
-};
-
-namespace MS {
-
-using namespace Geom;
-
-void
-KnotHolderEntityCenterMirrorSymmetry::knot_set(Geom::Point const &p, Geom::Point const &origin, guint state)
-{
- LPEMirrorSymmetry* lpe = dynamic_cast<LPEMirrorSymmetry *>(_effect);
- Geom::Point const s = snap_knot_position(p, state);
- lpe->center_point = s;
-
- // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
- sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
-}
-
-Geom::Point
-KnotHolderEntityCenterMirrorSymmetry::knot_get() const
-{
- LPEMirrorSymmetry const *lpe = dynamic_cast<LPEMirrorSymmetry const*>(_effect);
- return lpe->center_point;
-}
-
-} // namespace CR
-
} //namespace LivePathEffect
} /* namespace Inkscape */
diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h
index 3a244cb7e..e98c83f2b 100644
--- a/src/live_effects/lpe-mirror_symmetry.h
+++ b/src/live_effects/lpe-mirror_symmetry.h
@@ -18,19 +18,14 @@
#include "live_effects/effect.h"
#include "live_effects/parameter/parameter.h"
+#include "live_effects/parameter/text.h"
#include "live_effects/parameter/point.h"
-#include "live_effects/parameter/path.h"
#include "live_effects/parameter/enum.h"
#include "live_effects/lpegroupbbox.h"
namespace Inkscape {
namespace LivePathEffect {
-namespace MS {
-// we need a separate namespace to avoid clashes with LPEPerpBisector
-class KnotHolderEntityCenterMirrorSymmetry;
-}
-
enum ModeType {
MT_V,
MT_H,
@@ -46,25 +41,31 @@ public:
virtual ~LPEMirrorSymmetry();
virtual void doOnApply (SPLPEItem const* lpeitem);
virtual void doBeforeEffect (SPLPEItem const* lpeitem);
+ virtual void doAfterEffect (SPLPEItem const* lpeitem);
+ virtual void transform_multiply(Geom::Affine const& postmul, bool set);
virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in);
- /* the knotholder entity classes must be declared friends */
- friend class MS::KnotHolderEntityCenterMirrorSymmetry;
- void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ virtual void doOnRemove (SPLPEItem const* /*lpeitem*/);
+ virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/);
+ void toMirror(Geom::Affine transform);
+ // void cloneAttrbutes(Inkscape::XML::Node * origin, Inkscape::XML::Node * dest, const char * first_attribute, ...);
+ void cloneD(SPObject *orig, SPObject *dest, bool live, bool root);
protected:
virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
private:
EnumParam<ModeType> mode;
+ ScalarParam split_gap;
BoolParam discard_orig_path;
BoolParam fuse_paths;
BoolParam oposite_fuse;
+ BoolParam split_items;
PointParam start_point;
PointParam end_point;
- Geom::Line line_separation;
+ PointParam center_point;
+ TextParam id_origin;
Geom::Point previous_center;
- Geom::Point center_point;
-
+ SPObject * container;
LPEMirrorSymmetry(const LPEMirrorSymmetry&);
LPEMirrorSymmetry& operator=(const LPEMirrorSymmetry&);
};
diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp
index d611b88a1..a5d1d23c8 100644
--- a/src/live_effects/lpe-offset.cpp
+++ b/src/live_effects/lpe-offset.cpp
@@ -11,17 +11,12 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-offset.h"
#include "sp-shape.h"
#include "display/curve.h"
-
-#include <2geom/path.h>
-#include <2geom/piecewise.h>
-#include <2geom/sbasis-geometric.h>
#include <2geom/elliptical-arc.h>
-#include <2geom/transforms.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -32,7 +27,7 @@ LPEOffset::LPEOffset(LivePathEffectObject *lpeobject) :
{
show_orig_path = true;
apply_to_clippath_and_mask = true;
- registerParameter(dynamic_cast<Parameter *>(&offset_pt));
+ registerParameter(&offset_pt);
}
LPEOffset::~LPEOffset()
@@ -44,7 +39,7 @@ LPEOffset::doOnApply(SPLPEItem const* lpeitem)
{
Geom::Point offset = *(SP_SHAPE(lpeitem)->_curve->first_point());
offset_pt.param_update_default(offset);
- offset_pt.param_setValue(offset,true);
+ offset_pt.param_setValue(offset);
}
static void append_half_circle(Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2,
diff --git a/src/live_effects/lpe-parallel.cpp b/src/live_effects/lpe-parallel.cpp
index 23cd5e2e7..271442c7d 100644
--- a/src/live_effects/lpe-parallel.cpp
+++ b/src/live_effects/lpe-parallel.cpp
@@ -11,18 +11,15 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-parallel.h"
#include "sp-shape.h"
#include "display/curve.h"
-#include <2geom/path.h>
-#include <2geom/transforms.h>
-
-#include "knot-holder-entity.h"
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -54,9 +51,9 @@ LPEParallel::LPEParallel(LivePathEffectObject *lpeobject) :
show_orig_path = true;
_provides_knotholder_entities = true;
- registerParameter(dynamic_cast<Parameter *>(&offset_pt));
- registerParameter( dynamic_cast<Parameter *>(&length_left) );
- registerParameter( dynamic_cast<Parameter *>(&length_right) );
+ registerParameter(&offset_pt);
+ registerParameter(&length_left);
+ registerParameter(&length_right);
}
LPEParallel::~LPEParallel()
diff --git a/src/live_effects/lpe-path_length.cpp b/src/live_effects/lpe-path_length.cpp
index 4ca380c15..61818a73b 100644
--- a/src/live_effects/lpe-path_length.cpp
+++ b/src/live_effects/lpe-path_length.cpp
@@ -11,12 +11,10 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-path_length.h"
#include "util/units.h"
-
-#include "2geom/sbasis-geometric.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -28,10 +26,10 @@ LPEPathLength::LPEPathLength(LivePathEffectObject *lpeobject) :
unit(_("Unit:"), _("Unit"), "unit", &wr, this),
display_unit(_("Display unit"), _("Print unit after path length"), "display_unit", &wr, this, true)
{
- registerParameter(dynamic_cast<Parameter *>(&scale));
- registerParameter(dynamic_cast<Parameter *>(&info_text));
- registerParameter(dynamic_cast<Parameter *>(&unit));
- registerParameter(dynamic_cast<Parameter *>(&display_unit));
+ registerParameter(&scale);
+ registerParameter(&info_text);
+ registerParameter(&unit);
+ registerParameter(&display_unit);
}
LPEPathLength::~LPEPathLength()
@@ -39,12 +37,6 @@ LPEPathLength::~LPEPathLength()
}
-void
-LPEPathLength::hideCanvasText() {
- // this is only used in sp-lpe-item.cpp to hide the canvas text when the effect is invisible
- info_text.param_setValue("");
-}
-
Geom::Piecewise<Geom::D2<Geom::SBasis> >
LPEPathLength::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
{
@@ -71,7 +63,9 @@ LPEPathLength::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p
//g_print ("Area is zero\n");
}
//g_print ("Area: %f\n", area);
-
+ if (!this->isVisible()) {
+ info_text.param_setValue("");
+ }
return pwd2_in;
}
diff --git a/src/live_effects/lpe-path_length.h b/src/live_effects/lpe-path_length.h
index e108e770a..14d093c09 100644
--- a/src/live_effects/lpe-path_length.h
+++ b/src/live_effects/lpe-path_length.h
@@ -29,8 +29,6 @@ public:
virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
- void hideCanvasText();
-
private:
LPEPathLength(const LPEPathLength&);
LPEPathLength& operator=(const LPEPathLength&);
diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp
index 911c410f9..b026bbc22 100644
--- a/src/live_effects/lpe-patternalongpath.cpp
+++ b/src/live_effects/lpe-patternalongpath.cpp
@@ -6,22 +6,16 @@
#include "live_effects/lpe-patternalongpath.h"
#include "live_effects/lpeobject.h"
-#include "sp-shape.h"
#include "display/curve.h"
-#include "svg/svg.h"
-#include "ui/widget/scalar.h"
-#include <2geom/sbasis.h>
-#include <2geom/sbasis-geometric.h>
#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/piecewise.h>
-#include "knot-holder-entity.h"
#include "knotholder.h"
-
+#include <cmath>
#include <algorithm>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
using std::vector;
@@ -70,7 +64,7 @@ static const Util::EnumDataConverter<PAPCopyType> PAPCopyTypeConverter(PAPCopyTy
LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
pattern(_("Pattern source:"), _("Path to put along the skeleton path"), "pattern", &wr, this, "M0,0 L1,0"),
- original_height(0),
+ original_height(0.0),
prop_scale(_("_Width:"), _("Width of the pattern"), "prop_scale", &wr, this, 1.0),
copytype(_("Pattern copies:"), _("How many pattern copies to place along the skeleton path"),
"copytype", PAPCopyTypeConverter, &wr, this, PAPCT_SINGLE_STRETCHED),
@@ -91,16 +85,16 @@ LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) :
fuse_tolerance(_("_Fuse nearby ends:"), _("Fuse ends closer than this number. 0 means don't fuse."),
"fuse_tolerance", &wr, this, 0)
{
- registerParameter( dynamic_cast<Parameter *>(&pattern) );
- registerParameter( dynamic_cast<Parameter *>(&copytype) );
- registerParameter( dynamic_cast<Parameter *>(&prop_scale) );
- registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) );
- registerParameter( dynamic_cast<Parameter *>(&spacing) );
- registerParameter( dynamic_cast<Parameter *>(&normal_offset) );
- registerParameter( dynamic_cast<Parameter *>(&tang_offset) );
- registerParameter( dynamic_cast<Parameter *>(&prop_units) );
- registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) );
- registerParameter( dynamic_cast<Parameter *>(&fuse_tolerance) );
+ registerParameter(&pattern);
+ registerParameter(&copytype);
+ registerParameter(&prop_scale);
+ registerParameter(&scale_y_rel);
+ registerParameter(&spacing);
+ registerParameter(&normal_offset);
+ registerParameter(&tang_offset);
+ registerParameter(&prop_units);
+ registerParameter(&vertical_pattern);
+ registerParameter(&fuse_tolerance);
prop_scale.param_set_digits(3);
prop_scale.param_set_increments(0.01, 0.10);
@@ -151,15 +145,15 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
double xspace = spacing;
double noffset = normal_offset;
double toffset = tang_offset;
- if (prop_units.get_value() && pattBndsY){
+ if (prop_units.get_value()){
xspace *= pattBndsX->extent();
noffset *= pattBndsY->extent();
toffset *= pattBndsX->extent();
}
//Prevent more than 90% overlap...
- if (xspace < -pattBndsX->extent()*.9) {
- xspace = -pattBndsX->extent()*.9;
+ if (xspace < -pattBndsX->extent() * 0.9) {
+ xspace = -pattBndsX->extent() * 0.9;
}
//TODO: dynamical update of parameter ranges?
//if (prop_units.get_value()){
@@ -168,7 +162,7 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
// spacing.param_set_range(-pattBndsX.extent()*.9, Geom::infinity());
// }
- y0+=noffset;
+ y0 += noffset;
std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > paths_in;
paths_in = split_at_discontinuities(pwd2_in);
@@ -177,11 +171,14 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
Geom::Piecewise<Geom::D2<Geom::SBasis> > path_i = paths_in[idx];
Piecewise<SBasis> x = x0;
Piecewise<SBasis> y = y0;
- Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(path_i,2,.1);
- uskeleton = remove_short_cuts(uskeleton,.01);
+ Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(path_i,2, 0.1);
+ uskeleton = remove_short_cuts(uskeleton, 0.01);
Piecewise<D2<SBasis> > n = rot90(derivative(uskeleton));
- n = force_continuity(remove_short_cuts(n,.1));
-
+ if (Geom::are_near(pwd2_in[0].at0(),pwd2_in[pwd2_in.size()-1].at1(), 0.01)) {
+ n = force_continuity(remove_short_cuts(n, 0.1), 0.01);
+ } else {
+ n = force_continuity(remove_short_cuts(n, 0.1));
+ }
int nbCopies = 0;
double scaling = 1;
switch(type) {
@@ -201,13 +198,13 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
case PAPCT_REPEATED_STRETCHED:
// if uskeleton is closed:
- if(path_i.segs.front().at0() == path_i.segs.back().at1()){
- nbCopies = static_cast<int>(std::floor((uskeleton.domain().extent() - toffset)/(pattBndsX->extent()+xspace)));
+ if (are_near(path_i.segs.front().at0(), path_i.segs.back().at1())){
+ nbCopies = std::max(1, static_cast<int>(std::floor((uskeleton.domain().extent() - toffset)/(pattBndsX->extent()+xspace))));
pattBndsX = Interval(pattBndsX->min(),pattBndsX->max()+xspace);
scaling = (uskeleton.domain().extent() - toffset)/(((double)nbCopies)*pattBndsX->extent());
// if not closed: no space at the end
}else{
- nbCopies = static_cast<int>(std::floor((uskeleton.domain().extent() - toffset + xspace)/(pattBndsX->extent()+xspace)));
+ nbCopies = std::max(1, static_cast<int>(std::floor((uskeleton.domain().extent() - toffset + xspace)/(pattBndsX->extent()+xspace))));
pattBndsX = Interval(pattBndsX->min(),pattBndsX->max()+xspace);
scaling = (uskeleton.domain().extent() - toffset)/(((double)nbCopies)*pattBndsX->extent() - xspace);
}
@@ -217,18 +214,18 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
return pwd2_in;
};
+ //Ceil to 6 decimals
+ scaling = ceil(scaling * 1000000) / 1000000;
double pattWidth = pattBndsX->extent() * scaling;
- if (scaling != 1.0) {
- x*=scaling;
- }
+ x *= scaling;
if ( scale_y_rel.get_value() ) {
- y*=(scaling*prop_scale);
+ y *= prop_scale * scaling;
} else {
- if (prop_scale != 1.0) y *= prop_scale;
+ y *= prop_scale;
}
x += toffset;
-
+
double offs = 0;
for (int i=0; i<nbCopies; i++){
if (fuse_tolerance > 0){
@@ -241,7 +238,7 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
offs+=pattWidth;
}
}
- if (fuse_tolerance > 0){
+ if (fuse_tolerance > 0){
pre_output = fuse_nearby_ends(pre_output, fuse_tolerance);
for (unsigned i=0; i<pre_output.size(); i++){
output.concat(pre_output[i]);
@@ -264,11 +261,12 @@ LPEPatternAlongPath::transform_multiply(Geom::Affine const& postmul, bool set)
bool transform_stroke = prefs ? prefs->getBool("/options/transform/stroke", true) : true;
if (transform_stroke && !scale_y_rel) {
prop_scale.param_set_value(prop_scale * ((postmul.expansionX() + postmul.expansionY()) / 2));
- }
+ prop_scale.write_to_SVG();
+ }
if (postmul.isTranslation()) {
pattern.param_transform_multiply(postmul, set);
+ pattern.write_to_SVG();
}
- sp_lpe_item_update_patheffect (sp_lpe_item, false, true);
}
void
@@ -279,10 +277,10 @@ LPEPatternAlongPath::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vect
void
-LPEPatternAlongPath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+LPEPatternAlongPath::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
KnotHolderEntity *e = new WPAP::KnotHolderEntityWidthPatternAlongPath(this);
- e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Change the width"), SP_KNOT_SHAPE_CIRCLE);
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Change the width"), SP_KNOT_SHAPE_CIRCLE);
knotholder->add(e);
}
diff --git a/src/live_effects/lpe-patternalongpath.h b/src/live_effects/lpe-patternalongpath.h
index 3d7fc02bc..c34a9a15d 100644
--- a/src/live_effects/lpe-patternalongpath.h
+++ b/src/live_effects/lpe-patternalongpath.h
@@ -43,7 +43,7 @@ public:
void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
- virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item);
+ virtual void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item);
PathParam pattern;
diff --git a/src/live_effects/lpe-perp_bisector.cpp b/src/live_effects/lpe-perp_bisector.cpp
index 660318c57..dab169cfe 100644
--- a/src/live_effects/lpe-perp_bisector.cpp
+++ b/src/live_effects/lpe-perp_bisector.cpp
@@ -11,19 +11,16 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-perp_bisector.h"
#include "display/curve.h"
#include "sp-path.h"
#include "line-geometry.h"
-#include "sp-lpe-item.h"
-#include <2geom/path.h>
-#include "knot-holder-entity.h"
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
namespace PB {
@@ -102,8 +99,8 @@ LPEPerpBisector::LPEPerpBisector(LivePathEffectObject *lpeobject) :
_provides_knotholder_entities = true;
// register all your parameters here, so Inkscape knows which parameters this effect has:
- registerParameter( dynamic_cast<Parameter *>(&length_left) );
- registerParameter( dynamic_cast<Parameter *>(&length_right) );
+ registerParameter(&length_left);
+ registerParameter(&length_right);
}
LPEPerpBisector::~LPEPerpBisector()
diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp
index 5b29df4a7..3cff83fed 100644
--- a/src/live_effects/lpe-perspective-envelope.cpp
+++ b/src/live_effects/lpe-perspective-envelope.cpp
@@ -18,9 +18,11 @@
#include "live_effects/lpe-perspective-envelope.h"
#include "helper/geom.h"
#include "display/curve.h"
-#include "svg/svg.h"
#include <gsl/gsl_linalg.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
using namespace Geom;
namespace Inkscape {
@@ -32,8 +34,8 @@ enum DeformationType {
};
static const Util::EnumData<unsigned> DeformationTypeData[] = {
- {DEFORMATION_PERSPECTIVE , N_("Perspective"), "Perspective"},
- {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "Envelope deformation"}
+ {DEFORMATION_PERSPECTIVE , N_("Perspective"), "perspective"},
+ {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "envelope_deformation"}
};
static const Util::EnumDataConverter<unsigned> DeformationTypeConverter(DeformationTypeData, sizeof(DeformationTypeData)/sizeof(*DeformationTypeData));
@@ -42,6 +44,7 @@ LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject)
Effect(lpeobject),
horizontal_mirror(_("Mirror movements in horizontal"), _("Mirror movements in horizontal"), "horizontal_mirror", &wr, this, false),
vertical_mirror(_("Mirror movements in vertical"), _("Mirror movements in vertical"), "vertical_mirror", &wr, this, false),
+ overflow_perspective(_("Overflow perspective"), _("Overflow perspective"), "overflow_perspective", &wr, this, false),
deform_type(_("Type"), _("Select the type of deformation"), "deform_type", DeformationTypeConverter, &wr, this, DEFORMATION_PERSPECTIVE),
up_left_point(_("Top Left"), _("Top Left - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "up_left_point", &wr, this),
up_right_point(_("Top Right"), _("Top Right - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "up_right_point", &wr, this),
@@ -52,6 +55,7 @@ LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject)
registerParameter(&deform_type);
registerParameter(&horizontal_mirror);
registerParameter(&vertical_mirror);
+ registerParameter(&overflow_perspective);
registerParameter(&up_left_point);
registerParameter(&up_right_point);
registerParameter(&down_left_point);
@@ -76,11 +80,107 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve)
}
double projmatrix[3][3];
if(deform_type == DEFORMATION_PERSPECTIVE) {
- std::vector<Geom::Point> handles(4);
- handles[0] = down_left_point;
- handles[1] = up_left_point;
- handles[2] = up_right_point;
- handles[3] = down_right_point;
+ if (!overflow_perspective && handles.size() == 4) {
+ bool move0 = false;
+ if (handles[0] != down_left_point) {
+ move0 = true;
+ }
+ bool move1 = false;
+ if (handles[1] != up_left_point) {
+ move1 = true;
+ }
+ bool move2 = false;
+ if (handles[2] != up_right_point) {
+ move2 = true;
+ }
+ bool move3 = false;
+ if (handles[3] != down_right_point) {
+ move3 = true;
+ }
+ handles.resize(4);
+ handles[0] = down_left_point;
+ handles[1] = up_left_point;
+ handles[2] = up_right_point;
+ handles[3] = down_right_point;
+ Geom::Line line_a(handles[3],handles[1]);
+ Geom::Line line_b(handles[1],handles[2]);
+ Geom::Line line_c(handles[2],handles[3]);
+ int position_a = Geom::sgn(Geom::cross(handles[3] - handles[1], handles[0] - handles[1]));
+ int position_b = Geom::sgn(Geom::cross(handles[1] - handles[2], handles[0] - handles[2]));
+ int position_c = Geom::sgn(Geom::cross(handles[2] - handles[3], handles[0] - handles[3]));
+ if (position_a != 1 && move0) {
+ Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[0]));
+ down_left_point.param_setValue(point_a);
+ }
+ if (position_b == 1 && move0) {
+ Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[0]));
+ down_left_point.param_setValue(point_b);
+ }
+ if (position_c == 1 && move0) {
+ Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[0]));
+ down_left_point.param_setValue(point_c);
+ }
+ line_a.setPoints(handles[0],handles[2]);
+ line_b.setPoints(handles[2],handles[3]);
+ line_c.setPoints(handles[3],handles[0]);
+ position_a = Geom::sgn(Geom::cross(handles[0] - handles[2], handles[1] - handles[2]));
+ position_b = Geom::sgn(Geom::cross(handles[2] - handles[3], handles[1] - handles[3]));
+ position_c = Geom::sgn(Geom::cross(handles[3] - handles[0], handles[1] - handles[0]));
+ if (position_a != 1 && move1) {
+ Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[1]));
+ up_left_point.param_setValue(point_a);
+ }
+ if (position_b == 1 && move1) {
+ Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[1]));
+ up_left_point.param_setValue(point_b);
+ }
+ if (position_c == 1 && move1) {
+ Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[1]));
+ up_left_point.param_setValue(point_c);
+ }
+ line_a.setPoints(handles[1],handles[3]);
+ line_b.setPoints(handles[3],handles[0]);
+ line_c.setPoints(handles[0],handles[1]);
+ position_a = Geom::sgn(Geom::cross(handles[1] - handles[3], handles[2] - handles[3]));
+ position_b = Geom::sgn(Geom::cross(handles[3] - handles[0], handles[2] - handles[0]));
+ position_c = Geom::sgn(Geom::cross(handles[0] - handles[1], handles[2] - handles[1]));
+ if (position_a != 1 && move2) {
+ Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[2]));
+ up_right_point.param_setValue(point_a);
+ }
+ if (position_b == 1 && move2) {
+ Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[2]));
+ up_right_point.param_setValue(point_b);
+ }
+ if (position_c == 1 && move2) {
+ Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[2]));
+ up_right_point.param_setValue(point_c);
+ }
+ line_a.setPoints(handles[2],handles[0]);
+ line_b.setPoints(handles[0],handles[1]);
+ line_c.setPoints(handles[1],handles[2]);
+ position_a = Geom::sgn(Geom::cross(handles[2] - handles[0], handles[3] - handles[0]));
+ position_b = Geom::sgn(Geom::cross(handles[0] - handles[1], handles[3] - handles[1]));
+ position_c = Geom::sgn(Geom::cross(handles[1] - handles[2], handles[3] - handles[2]));
+ if (position_a != 1 && move3) {
+ Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[3]));
+ down_right_point.param_setValue(point_a);
+ }
+ if (position_b == 1 && move3) {
+ Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[3]));
+ down_right_point.param_setValue(point_b);
+ }
+ if (position_c == 1 && move3) {
+ Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[3]));
+ down_right_point.param_setValue(point_c);
+ }
+ } else {
+ handles.resize(4);
+ handles[0] = down_left_point;
+ handles[1] = up_left_point;
+ handles[2] = up_right_point;
+ handles[3] = down_right_point;
+ }
std::vector<Geom::Point> source_handles(4);
source_handles[0] = Geom::Point(boundingbox_X.min(), boundingbox_Y.max());
source_handles[1] = Geom::Point(boundingbox_X.min(), boundingbox_Y.min());
@@ -206,14 +306,14 @@ LPEPerspectiveEnvelope::projectPoint(Geom::Point p)
double delta_y = boundingbox_Y.max() - p[Y];
Geom::Coord x_ratio = (delta_x * -1) / width;
Geom::Coord y_ratio = delta_y / height;
- Geom::Line* horiz = new Geom::Line();
- Geom::Line* vert = new Geom::Line();
- vert->setPoints (pointAtRatio(y_ratio,down_left_point,up_left_point),pointAtRatio(y_ratio,down_right_point,up_right_point));
- horiz->setPoints (pointAtRatio(x_ratio,down_left_point,down_right_point),pointAtRatio(x_ratio,up_left_point,up_right_point));
+ Geom::Line horiz;
+ Geom::Line vert;
+ vert.setPoints (pointAtRatio(y_ratio,down_left_point,up_left_point),pointAtRatio(y_ratio,down_right_point,up_right_point));
+ horiz.setPoints (pointAtRatio(x_ratio,down_left_point,down_right_point),pointAtRatio(x_ratio,up_left_point,up_right_point));
- OptCrossing crossPoint = intersection(*horiz,*vert);
+ OptCrossing crossPoint = intersection(horiz,vert);
if(crossPoint) {
- return horiz->pointAt(Geom::Coord(crossPoint->ta));
+ return horiz.pointAt(Geom::Coord(crossPoint->ta));
} else {
return p;
}
@@ -269,17 +369,17 @@ LPEPerspectiveEnvelope::newWidget()
Gtk::Label* handles = Gtk::manage(new Gtk::Label(Glib::ustring(_("Handles:")),Gtk::ALIGN_START));
vbox->pack_start(*handles, false, false, 2);
hbox_up_handles->pack_start(*widg, true, true, 2);
- hbox_up_handles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET);
+ hbox_up_handles->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), Gtk::PACK_EXPAND_WIDGET);
} else if(param->param_key == "up_right_point") {
hbox_up_handles->pack_start(*widg, true, true, 2);
} else if(param->param_key == "down_left_point") {
hbox_down_handles->pack_start(*widg, true, true, 2);
- hbox_down_handles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET);
+ hbox_down_handles->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), Gtk::PACK_EXPAND_WIDGET);
} else {
hbox_down_handles->pack_start(*widg, true, true, 2);
}
if (tip) {
- widg->set_tooltip_text(*tip);
+ widg->set_tooltip_markup(*tip);
} else {
widg->set_tooltip_text("");
widg->set_has_tooltip(false);
@@ -303,12 +403,13 @@ LPEPerspectiveEnvelope::newWidget()
}
vbox->pack_start(*hbox_up_handles,true, true, 2);
Gtk::HBox * hbox_middle = Gtk::manage(new Gtk::HBox(true,2));
- hbox_middle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET);
- hbox_middle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET);
+ hbox_middle->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_EXPAND_WIDGET);
+ hbox_middle->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_EXPAND_WIDGET);
vbox->pack_start(*hbox_middle, false, true, 2);
vbox->pack_start(*hbox_down_handles, true, true, 2);
Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0));
- Gtk::Button* reset_button = Gtk::manage(new Gtk::Button(Gtk::Stock::CLEAR));
+ Gtk::Button* reset_button = Gtk::manage(new Gtk::Button(_("_Clear"), true));
+ reset_button->set_image_from_icon_name("edit-clear");
reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEPerspectiveEnvelope::resetGrid));
reset_button->set_size_request(140,30);
vbox->pack_start(*hbox, true,true,2);
@@ -333,8 +434,8 @@ LPEPerspectiveEnvelope::vertical(PointParam &param_one, PointParam &param_two, G
}
A[Geom::X] = nearest[Geom::X] - distance_middle;
B[Geom::X] = nearest[Geom::X] + distance_middle;
- param_one.param_setValue(A, true);
- param_two.param_setValue(B, true);
+ param_one.param_setValue(A);
+ param_two.param_setValue(B);
}
void
@@ -354,8 +455,8 @@ LPEPerspectiveEnvelope::horizontal(PointParam &param_one, PointParam &param_two,
}
A[Geom::Y] = nearest[Geom::Y] - distance_middle;
B[Geom::Y] = nearest[Geom::Y] + distance_middle;
- param_one.param_setValue(A, true);
- param_two.param_setValue(B, true);
+ param_one.param_setValue(A);
+ param_two.param_setValue(B);
}
void
@@ -440,4 +541,4 @@ LPEPerspectiveEnvelope::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::v
fill-column:99
End:
*/
-// vim: file_type=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/live_effects/lpe-perspective-envelope.h b/src/live_effects/lpe-perspective-envelope.h
index dd14dc212..727b7839d 100644
--- a/src/live_effects/lpe-perspective-envelope.h
+++ b/src/live_effects/lpe-perspective-envelope.h
@@ -60,12 +60,13 @@ private:
BoolParam horizontal_mirror;
BoolParam vertical_mirror;
+ BoolParam overflow_perspective;
EnumParam<unsigned> deform_type;
PointParam up_left_point;
PointParam up_right_point;
PointParam down_left_point;
PointParam down_right_point;
-
+ std::vector<Geom::Point> handles;
LPEPerspectiveEnvelope(const LPEPerspectiveEnvelope&);
LPEPerspectiveEnvelope& operator=(const LPEPerspectiveEnvelope&);
};
diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp
index c8cdd7912..435c91c2d 100644
--- a/src/live_effects/lpe-perspective_path.cpp
+++ b/src/live_effects/lpe-perspective_path.cpp
@@ -11,22 +11,17 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <gtkmm.h>
-#include <glibmm/i18n.h>
-
#include "persp3d.h"
//#include "transf_mat_3x4.h"
-#include "document.h"
#include "document-private.h"
#include "live_effects/lpe-perspective_path.h"
#include "live_effects/lpeobject.h"
-#include "sp-item-group.h"
#include "knot-holder-entity.h"
#include "knotholder.h"
-#include "desktop.h"
#include <util/units.h>
-#include "inkscape.h"
-#include <2geom/path.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -56,11 +51,11 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) :
uses_plane_xy(_("Uses XY plane?"), _("If true, put the path on the left side of an imaginary box, otherwise on the right side"), "uses_plane_xy", &wr, this, true)
{
// register all your parameters here, so Inkscape knows which parameters this effect has:
- registerParameter( dynamic_cast<Parameter *>(&scalex) );
- registerParameter( dynamic_cast<Parameter *>(&scaley) );
- registerParameter( dynamic_cast<Parameter *>(&offsetx) );
- registerParameter( dynamic_cast<Parameter *>(&offsety) );
- registerParameter( dynamic_cast<Parameter *>(&uses_plane_xy) );
+ registerParameter( &scalex);
+ registerParameter( &scaley);
+ registerParameter( &offsetx);
+ registerParameter( &offsety);
+ registerParameter( &uses_plane_xy);
concatenate_before_pwd2 = true; // don't split the path into its subpaths
_provides_knotholder_entities = true;
@@ -107,12 +102,12 @@ void LPEPerspectivePath::refresh(Gtk::Entry* perspective) {
perspectiveID = perspective->get_text();
Persp3D *first = 0;
Persp3D *persp = 0;
- for ( SPObject *child = this->lpeobj->document->getDefs()->firstChild(); child && !persp; child = child->getNext() ) {
- if (SP_IS_PERSP3D(child) && first == 0) {
- first = SP_PERSP3D(child);
+ for (auto& child: lpeobj->document->getDefs()->children) {
+ if (SP_IS_PERSP3D(&child) && first == 0) {
+ first = SP_PERSP3D(&child);
}
- if (SP_IS_PERSP3D(child) && strcmp(child->getId(), const_cast<const gchar *>(perspectiveID.c_str())) == 0) {
- persp = SP_PERSP3D(child);
+ if (SP_IS_PERSP3D(&child) && strcmp(child.getId(), const_cast<const gchar *>(perspectiveID.c_str())) == 0) {
+ persp = SP_PERSP3D(&child);
break;
}
}
@@ -231,15 +226,28 @@ LPEPerspectivePath::newWidget()
++it;
}
Gtk::HBox * perspectiveId = Gtk::manage(new Gtk::HBox(true,0));
+
+#if WITH_GTKMM_3_10
+ Gtk::Label* labelPerspective = Gtk::manage(new Gtk::Label("Perspective ID:", Gtk::ALIGN_START, Gtk::ALIGN_START));
+#else
Gtk::Label* labelPerspective = Gtk::manage(new Gtk::Label("Perspective ID:", 0., 0.));
+#endif
+
Gtk::Entry* perspective = Gtk::manage(new Gtk::Entry());
perspective->set_text(perspectiveID);
perspective->set_tooltip_text("Set the perspective ID to apply");
perspectiveId->pack_start(*labelPerspective, true, true, 2);
perspectiveId->pack_start(*perspective, true, true, 2);
vbox->pack_start(*perspectiveId, true, true, 2);
- Gtk::Button* apply3D = Gtk::manage(new Gtk::Button(Glib::ustring(_("Refresh perspective"))));
- apply3D->set_alignment(0.0, 0.5);
+ Gtk::Button* apply3D = Gtk::manage(new Gtk::Button());
+
+#if WITH_GTKMM_3_10
+ Gtk::Label *apply3DLabel = Gtk::manage(new Gtk::Label(_("Refresh perspective"), Gtk::ALIGN_START, Gtk::ALIGN_CENTER));
+#else
+ Gtk::Label *apply3DLabel = Gtk::manage(new Gtk::Label(_("Refresh perspective"), 0.0, 0.5));
+#endif
+
+ apply3D->add(*apply3DLabel);
apply3D->signal_clicked().connect(sigc::bind<Gtk::Entry*>(sigc::mem_fun(*this,&LPEPerspectivePath::refresh),perspective));
Gtk::Widget* apply3DWidget = dynamic_cast<Gtk::Widget *>(apply3D);
apply3DWidget->set_tooltip_text("Refresh perspective");
@@ -247,9 +255,9 @@ LPEPerspectivePath::newWidget()
return dynamic_cast<Gtk::Widget *>(vbox);
}
-void LPEPerspectivePath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
+void LPEPerspectivePath::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) {
KnotHolderEntity *e = new PP::KnotHolderEntityOffset(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Adjust the origin") );
knotholder->add(e);
};
diff --git a/src/live_effects/lpe-perspective_path.h b/src/live_effects/lpe-perspective_path.h
index c4ddf1853..87ee453ff 100644
--- a/src/live_effects/lpe-perspective_path.h
+++ b/src/live_effects/lpe-perspective_path.h
@@ -41,7 +41,7 @@ public:
virtual Gtk::Widget * newWidget();
/* the knotholder entity classes must be declared friends */
friend class PP::KnotHolderEntityOffset;
- void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
private:
// add the parameters for your effect here:
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index 03102a84a..d87f92fcc 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -13,31 +13,20 @@
#include "live_effects/lpe-powerstroke.h"
#include "live_effects/lpe-powerstroke-interpolators.h"
-#include "sp-shape.h"
#include "style.h"
-#include "xml/repr.h"
-#include "sp-paint-server.h"
#include "svg/svg-color.h"
#include "desktop-style.h"
#include "svg/css-ostringstream.h"
#include "display/curve.h"
-#include <2geom/path.h>
-#include <2geom/piecewise.h>
-#include <2geom/sbasis-geometric.h>
-#include <2geom/transforms.h>
-#include <2geom/bezier-utils.h>
#include <2geom/elliptical-arc.h>
-#include <2geom/sbasis-to-bezier.h>
#include <2geom/path-sink.h>
#include <2geom/path-intersection.h>
-#include <2geom/crossing.h>
-#include <2geom/ellipse.h>
#include <2geom/circle.h>
-#include <2geom/math-utils.h>
-#include <math.h>
+#include "helper/geom.h"
-#include "spiro.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Geom {
// should all be moved to 2geom at some point
@@ -190,14 +179,14 @@ LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) :
interpolator_beta.addSlider(true);
interpolator_beta.param_set_range(0.,1.);
- registerParameter( dynamic_cast<Parameter *>(&offset_points) );
- registerParameter( dynamic_cast<Parameter *>(&sort_points) );
- registerParameter( dynamic_cast<Parameter *>(&interpolator_type) );
- registerParameter( dynamic_cast<Parameter *>(&interpolator_beta) );
- registerParameter( dynamic_cast<Parameter *>(&start_linecap_type) );
- registerParameter( dynamic_cast<Parameter *>(&linejoin_type) );
- registerParameter( dynamic_cast<Parameter *>(&miter_limit) );
- registerParameter( dynamic_cast<Parameter *>(&end_linecap_type) );
+ registerParameter(&offset_points);
+ registerParameter(&sort_points);
+ registerParameter(&interpolator_type);
+ registerParameter(&interpolator_beta);
+ registerParameter(&start_linecap_type);
+ registerParameter(&linejoin_type);
+ registerParameter(&miter_limit);
+ registerParameter(&end_linecap_type);
}
LPEPowerStroke::~LPEPowerStroke()
@@ -205,14 +194,13 @@ LPEPowerStroke::~LPEPowerStroke()
}
-
void
LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem)
{
- if (SP_IS_SHAPE(lpeitem)) {
+ if (SP_IS_SHAPE(lpeitem) && offset_points.data().empty()) {
SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem);
std::vector<Geom::Point> points;
- Geom::PathVector const &pathv = SP_SHAPE(lpeitem)->_curve->get_pathvector();
+ Geom::PathVector const &pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeitem)->_curve->get_pathvector());
double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed / 2 : 1.;
SPCSSAttr *css = sp_repr_css_attr_new ();
@@ -565,12 +553,11 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
if (path_in.empty()) {
return path_out;
}
-
- // for now, only regard first subpath and ignore the rest
- Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[0].toPwSb();
-
+ Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers(path_in);
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = pathv[0].toPwSb();
Piecewise<D2<SBasis> > der = derivative(pwd2_in);
- Piecewise<D2<SBasis> > n = rot90(unitVector(der));
+ Piecewise<D2<SBasis> > n = unitVector(der,0.0001);
+ n = rot90(n);
offset_points.set_pwd2(pwd2_in, n);
LineCapType end_linecap = static_cast<LineCapType>(end_linecap_type.get_value());
@@ -583,7 +570,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
if (sort_points) {
sort(ts.begin(), ts.end(), compare_offsets);
}
- if (path_in[0].closed()) {
+ if (pathv[0].closed()) {
// add extra points for interpolation between first and last point
Point first_point = ts.front();
Point last_point = ts.back();
@@ -605,7 +592,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
for (std::size_t i = 0, e = ts.size(); i < e; ++i) {
ts[i][Geom::X] *= xcoord_scaling;
}
-
// create stroke path where points (x,y) := (t, offset)
Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value()));
if (Geom::Interpolate::CubicBezierJohan *johan = dynamic_cast<Geom::Interpolate::CubicBezierJohan*>(interpolator)) {
@@ -626,7 +612,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
// find time values for which x lies outside path domain
// and only take portion of x and y that lies within those time values
std::vector< double > rtsmin = roots (x - pwd2_in.domain().min());
- std::vector< double > rtsmax = roots (x - pwd2_in.domain().max());
+ std::vector< double > rtsmax = roots (x + pwd2_in.domain().max());
if ( !rtsmin.empty() && !rtsmax.empty() ) {
x = portion(x, rtsmin.at(0), rtsmax.at(0));
y = portion(y, rtsmin.at(0), rtsmax.at(0));
@@ -639,8 +625,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, y, jointype, miter_limit, LPE_CONVERSION_TOLERANCE);
Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, reverse(y), jointype, miter_limit, LPE_CONVERSION_TOLERANCE);
-
- if (path_in[0].closed()) {
+ if (pathv[0].closed()) {
fixed_path.close(true);
path_out.push_back(fixed_path);
fixed_mirrorpath.close(true);
@@ -684,7 +669,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
}
fixed_path.append(fixed_mirrorpath);
-
switch (start_linecap) {
case LINECAP_ZERO_WIDTH:
// do nothing
@@ -720,11 +704,9 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
break;
}
}
-
fixed_path.close(true);
path_out.push_back(fixed_path);
}
-
return path_out;
}
diff --git a/src/live_effects/lpe-recursiveskeleton.cpp b/src/live_effects/lpe-recursiveskeleton.cpp
index ac571d963..47613f58e 100644
--- a/src/live_effects/lpe-recursiveskeleton.cpp
+++ b/src/live_effects/lpe-recursiveskeleton.cpp
@@ -10,17 +10,12 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-recursiveskeleton.h"
-#include <2geom/path.h>
-#include <2geom/sbasis.h>
-#include <2geom/sbasis-geometric.h>
#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/piecewise.h>
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -33,7 +28,7 @@ LPERecursiveSkeleton::LPERecursiveSkeleton(LivePathEffectObject *lpeobject) :
concatenate_before_pwd2 = true;
iterations.param_make_integer(true);
iterations.param_set_range(1, 15);
- registerParameter( dynamic_cast<Parameter *>(&iterations) );
+ registerParameter(&iterations);
}
diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp
index 76421e0f0..d832b3615 100644
--- a/src/live_effects/lpe-rough-hatches.cpp
+++ b/src/live_effects/lpe-rough-hatches.cpp
@@ -13,24 +13,17 @@
*/
#include "ui/widget/scalar.h"
-#include <glibmm/i18n.h>
#include "live_effects/lpe-rough-hatches.h"
#include "sp-item.h"
#include "sp-path.h"
-#include "svg/svg.h"
#include "xml/repr.h"
-#include <2geom/path.h>
-#include <2geom/piecewise.h>
-#include <2geom/sbasis.h>
#include <2geom/sbasis-math.h>
-#include <2geom/sbasis-geometric.h>
#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/affine.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -248,26 +241,26 @@ LPERoughHatches::LPERoughHatches(LivePathEffectObject *lpeobject) :
//
bender(_("Global bending"), _("Relative position to a reference point defines global bending direction and amount"), "bender", &wr, this, Geom::Point(-5,0))
{
- registerParameter( dynamic_cast<Parameter *>(&direction) );
- registerParameter( dynamic_cast<Parameter *>(&dist_rdm) );
- registerParameter( dynamic_cast<Parameter *>(&growth) );
- registerParameter( dynamic_cast<Parameter *>(&do_bend) );
- registerParameter( dynamic_cast<Parameter *>(&bender) );
- registerParameter( dynamic_cast<Parameter *>(&top_edge_variation) );
- registerParameter( dynamic_cast<Parameter *>(&bot_edge_variation) );
- registerParameter( dynamic_cast<Parameter *>(&top_tgt_variation) );
- registerParameter( dynamic_cast<Parameter *>(&bot_tgt_variation) );
- registerParameter( dynamic_cast<Parameter *>(&scale_tf) );
- registerParameter( dynamic_cast<Parameter *>(&scale_tb) );
- registerParameter( dynamic_cast<Parameter *>(&scale_bf) );
- registerParameter( dynamic_cast<Parameter *>(&scale_bb) );
- registerParameter( dynamic_cast<Parameter *>(&top_smth_variation) );
- registerParameter( dynamic_cast<Parameter *>(&bot_smth_variation) );
- registerParameter( dynamic_cast<Parameter *>(&fat_output) );
- registerParameter( dynamic_cast<Parameter *>(&stroke_width_top) );
- registerParameter( dynamic_cast<Parameter *>(&stroke_width_bot) );
- registerParameter( dynamic_cast<Parameter *>(&front_thickness) );
- registerParameter( dynamic_cast<Parameter *>(&back_thickness) );
+ registerParameter(&direction);
+ registerParameter(&dist_rdm);
+ registerParameter(&growth);
+ registerParameter(&do_bend);
+ registerParameter(&bender);
+ registerParameter(&top_edge_variation);
+ registerParameter(&bot_edge_variation);
+ registerParameter(&top_tgt_variation);
+ registerParameter(&bot_tgt_variation);
+ registerParameter(&scale_tf);
+ registerParameter(&scale_tb);
+ registerParameter(&scale_bf);
+ registerParameter(&scale_bb);
+ registerParameter(&top_smth_variation);
+ registerParameter(&bot_smth_variation);
+ registerParameter(&fat_output);
+ registerParameter(&stroke_width_top);
+ registerParameter(&stroke_width_bot);
+ registerParameter(&front_thickness);
+ registerParameter(&back_thickness);
//hatch_dist.param_set_range(0.1, Geom::infinity());
growth.param_set_range(0, Geom::infinity());
diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp
index 105fe2fc4..e847494a2 100644
--- a/src/live_effects/lpe-roughen.cpp
+++ b/src/live_effects/lpe-roughen.cpp
@@ -14,15 +14,13 @@
*/
#include <gtkmm.h>
-#include "desktop.h"
#include "live_effects/lpe-roughen.h"
#include "display/curve.h"
-#include "live_effects/parameter/parameter.h"
#include <boost/functional/hash.hpp>
#include "helper/geom.h"
-#include "sp-item-group.h"
+
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
-#include <cmath>
namespace Inkscape {
namespace LivePathEffect {
@@ -122,7 +120,7 @@ Gtk::Widget *LPERoughen::newWidget()
Gtk::ALIGN_START));
method_label->set_use_markup(true);
vbox->pack_start(*method_label, false, false, 2);
- vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
+ vbox->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)),
Gtk::PACK_EXPAND_WIDGET);
}
if (param->param_key == "displace_x") {
@@ -131,7 +129,7 @@ Gtk::Widget *LPERoughen::newWidget()
Gtk::ALIGN_START));
displace_x_label->set_use_markup(true);
vbox->pack_start(*displace_x_label, false, false, 2);
- vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
+ vbox->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)),
Gtk::PACK_EXPAND_WIDGET);
}
if (param->param_key == "global_randomize") {
@@ -140,7 +138,7 @@ Gtk::Widget *LPERoughen::newWidget()
Gtk::ALIGN_START));
global_rand->set_use_markup(true);
vbox->pack_start(*global_rand, false, false, 2);
- vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
+ vbox->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)),
Gtk::PACK_EXPAND_WIDGET);
}
if (param->param_key == "handles") {
@@ -149,7 +147,7 @@ Gtk::Widget *LPERoughen::newWidget()
Gtk::ALIGN_START));
options->set_use_markup(true);
vbox->pack_start(*options, false, false, 2);
- vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
+ vbox->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)),
Gtk::PACK_EXPAND_WIDGET);
}
Glib::ustring *tip = param->param_getTooltip();
@@ -229,7 +227,7 @@ void LPERoughen::doEffect(SPCurve *curve)
nCurve->lineto(curve_it1->finalPoint());
}
last_move = Geom::Point(0, 0);
- double length = curve_it1->length(0.001);
+ double length = curve_it1->length(0.01);
std::size_t splits = 0;
if (method == DM_SEGMENTS) {
splits = segments;
@@ -354,9 +352,6 @@ SPCurve const * LPERoughen::addNodesAndJitter(Geom::Curve const * A, Geom::Point
point_a3 = seg1[3] + point_a3;
ray.setPoints(prev,A->initialPoint());
point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght);
- if(prev == Geom::Point(0,0)){
- point_a1 = randomize(max_lenght);
- }
if(last){
Geom::Path b2(point_b3);
b2.appendNew<Geom::LineSegment>(point_a3);
diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h
index 44a723c89..bab06022f 100644
--- a/src/live_effects/lpe-roughen.h
+++ b/src/live_effects/lpe-roughen.h
@@ -12,8 +12,8 @@
#ifndef INKSCAPE_LPE_ROUGHEN_H
#define INKSCAPE_LPE_ROUGHEN_H
-#include "live_effects/parameter/enum.h"
#include "live_effects/effect.h"
+#include "live_effects/parameter/enum.h"
#include "live_effects/parameter/parameter.h"
#include "live_effects/parameter/path.h"
#include "live_effects/parameter/bool.h"
diff --git a/src/live_effects/lpe-ruler.cpp b/src/live_effects/lpe-ruler.cpp
index 49b5faa2e..852592219 100644
--- a/src/live_effects/lpe-ruler.cpp
+++ b/src/live_effects/lpe-ruler.cpp
@@ -12,11 +12,8 @@
*/
#include "live_effects/lpe-ruler.h"
-#include <2geom/piecewise.h>
-#include <2geom/sbasis-geometric.h>
-#include "inkscape.h"
-#include "desktop.h"
-
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -48,15 +45,15 @@ LPERuler::LPERuler(LivePathEffectObject *lpeobject) :
offset(_("_Offset:"), _("Offset of first mark"), "offset", &wr, this, 0.0),
border_marks(_("Border marks:"), _("Choose whether to draw marks at the beginning and end of the path"), "border_marks", BorderMarkTypeConverter, &wr, this, BORDERMARK_BOTH)
{
- registerParameter(dynamic_cast<Parameter *>(&unit));
- registerParameter(dynamic_cast<Parameter *>(&mark_distance));
- registerParameter(dynamic_cast<Parameter *>(&mark_length));
- registerParameter(dynamic_cast<Parameter *>(&minor_mark_length));
- registerParameter(dynamic_cast<Parameter *>(&major_mark_steps));
- registerParameter(dynamic_cast<Parameter *>(&shift));
- registerParameter(dynamic_cast<Parameter *>(&offset));
- registerParameter(dynamic_cast<Parameter *>(&mark_dir));
- registerParameter(dynamic_cast<Parameter *>(&border_marks));
+ registerParameter(&unit);
+ registerParameter(&mark_distance);
+ registerParameter(&mark_length);
+ registerParameter(&minor_mark_length);
+ registerParameter(&major_mark_steps);
+ registerParameter(&shift);
+ registerParameter(&offset);
+ registerParameter(&mark_dir);
+ registerParameter(&border_marks);
major_mark_steps.param_make_integer();
major_mark_steps.param_set_range(1, 1000);
diff --git a/src/live_effects/lpe-show_handles.cpp b/src/live_effects/lpe-show_handles.cpp
index 0bc1c4f17..7c298d0e7 100644
--- a/src/live_effects/lpe-show_handles.cpp
+++ b/src/live_effects/lpe-show_handles.cpp
@@ -7,9 +7,7 @@
*/
#include <gtkmm.h>
-#include <glibmm/i18n.h>
#include "live_effects/lpe-show_handles.h"
-#include "live_effects/parameter/parameter.h"
#include <2geom/sbasis-to-bezier.h>
#include <2geom/svg-path-parser.h>
#include "helper/geom.h"
@@ -17,6 +15,9 @@
#include "style.h"
#include "svg/svg.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -25,20 +26,17 @@ LPEShowHandles::LPEShowHandles(LivePathEffectObject *lpeobject)
nodes(_("Show nodes"), _("Show nodes"), "nodes", &wr, this, true),
handles(_("Show handles"), _("Show handles"), "handles", &wr, this, true),
original_path(_("Show path"), _("Show path"), "original_path", &wr, this, true),
- scale_nodes_and_handles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scale_nodes_and_handles", &wr, this, 10),
- rotate_nodes(_("Rotate nodes"), _("Rotate nodes"), "rotate_nodes", &wr, this, 0)
+ show_center_node(_("Show center of node"), _("Show center of node"), "show_center_node", &wr, this, false),
+ scale_nodes_and_handles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scale_nodes_and_handles", &wr, this, 10)
{
registerParameter(&nodes);
registerParameter(&handles);
registerParameter(&original_path);
+ registerParameter(&show_center_node);
registerParameter(&scale_nodes_and_handles);
- registerParameter(&rotate_nodes);
scale_nodes_and_handles.param_set_range(0, 500.);
scale_nodes_and_handles.param_set_increments(1, 1);
scale_nodes_and_handles.param_set_digits(2);
- rotate_nodes.param_set_range(0, 365);
- rotate_nodes.param_set_increments(1, 1);
- rotate_nodes.param_set_digits(0);
stroke_width = 1.0;
}
@@ -130,7 +128,11 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result)
}
}
if(nodes) {
- drawNode(curve_it1->initialPoint());
+ Geom::NodeType nodetype = Geom::NODE_CUSP;
+ if(path_it->closed()) {
+ nodetype = Geom::get_nodetype(path_it->finalCurve(), *curve_it1);
+ }
+ drawNode(curve_it1->initialPoint(), nodetype);
}
while (curve_it1 != curve_endit) {
cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
@@ -146,8 +148,9 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result)
}
}
}
- if(nodes) {
- drawNode(curve_it1->finalPoint());
+ if(nodes && (curve_it2 != curve_endit || !path_it->closed())) {
+ Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
+ drawNode(curve_it1->finalPoint(), nodetype);
}
++curve_it1;
if(curve_it2 != curve_endit) {
@@ -158,16 +161,26 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result)
}
void
-LPEShowHandles::drawNode(Geom::Point p)
+LPEShowHandles::drawNode(Geom::Point p, Geom::NodeType nodetype)
{
if(stroke_width * scale_nodes_and_handles > 0.0) {
+ Geom::Rotate rotate = Geom::Rotate(0);
+ if ( nodetype == Geom::NODE_CUSP) {
+ rotate = Geom::Rotate::from_degrees(45);
+ }
double diameter = stroke_width * scale_nodes_and_handles;
char const * svgd;
- svgd = "M 0.05,0 A 0.05,0.05 0 0 1 0,0.05 0.05,0.05 0 0 1 -0.05,0 0.05,0.05 0 0 1 0,-0.05 0.05,0.05 0 0 1 0.05,0 Z M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z";
+ if (show_center_node) {
+ svgd = "M 0.05,0 A 0.05,0.05 0 0 1 0,0.05 0.05,0.05 0 0 1 -0.05,0 0.05,0.05 0 0 1 0,-0.05 0.05,0.05 0 0 1 0.05,0 Z M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z";
+ } else {
+ svgd = "M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z";
+ }
Geom::PathVector pathv = sp_svg_read_pathv(svgd);
- pathv *= Geom::Rotate::from_degrees(rotate_nodes) * Geom::Scale(diameter) * Geom::Translate(p);
+ pathv *= rotate * Geom::Scale(diameter) * Geom::Translate(p);
outline_path.push_back(pathv[0]);
- outline_path.push_back(pathv[1]);
+ if (show_center_node) {
+ outline_path.push_back(pathv[1]);
+ }
}
}
diff --git a/src/live_effects/lpe-show_handles.h b/src/live_effects/lpe-show_handles.h
index 34390dd32..c46abd2c2 100644
--- a/src/live_effects/lpe-show_handles.h
+++ b/src/live_effects/lpe-show_handles.h
@@ -8,7 +8,7 @@
* Copyright (C) Jabier Arraiza Cenoz 2014 <jabier.arraiza@marker.es>
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
+#include "helper/geom-nodetype.h"
#include "live_effects/effect.h"
#include "live_effects/lpegroupbbox.h"
#include "live_effects/parameter/bool.h"
@@ -28,7 +28,7 @@ public:
virtual void generateHelperPath(Geom::PathVector result);
- virtual void drawNode(Geom::Point p);
+ virtual void drawNode(Geom::Point p, Geom::NodeType nodetype);
virtual void drawHandle(Geom::Point p);
@@ -43,8 +43,8 @@ private:
BoolParam nodes;
BoolParam handles;
BoolParam original_path;
+ BoolParam show_center_node;
ScalarParam scale_nodes_and_handles;
- ScalarParam rotate_nodes;
double stroke_width;
static bool alerts_off;
diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp
index f807bdc8d..5de9816bb 100644
--- a/src/live_effects/lpe-simplify.cpp
+++ b/src/live_effects/lpe-simplify.cpp
@@ -3,24 +3,16 @@
*/
#include <gtkmm.h>
-
#include "live_effects/lpe-simplify.h"
#include "display/curve.h"
-#include "live_effects/parameter/parameter.h"
-#include <glibmm/i18n.h>
#include "helper/geom.h"
-#include "livarot/Path.h"
-#include "splivarot.h"
#include <2geom/svg-path-parser.h>
-#include "desktop.h"
-#include "inkscape.h"
#include "svg/svg.h"
#include "ui/tools/node-tool.h"
-#include <2geom/d2.h>
-#include <2geom/generic-rect.h>
-#include <2geom/interval.h>
#include "ui/icon-names.h"
-#include "util/units.h"
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -148,11 +140,7 @@ LPESimplify::doEffect(SPCurve *curve)
Geom::PathVector result = Geom::parse_svg_path(pathliv->svg_dump_path());
generateHelperPathAndSmooth(result);
curve->set_pathvector(result);
- SPDesktop* desktop = SP_ACTIVE_DESKTOP;
- if(desktop && INK_IS_NODE_TOOL(desktop->event_context)) {
- Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(desktop->event_context);
- nt->update_helperpath();
- }
+ Inkscape::UI::Tools::sp_update_helperpath();
}
void
diff --git a/src/live_effects/lpe-simplify.h b/src/live_effects/lpe-simplify.h
index 294d77b35..6c407f572 100644
--- a/src/live_effects/lpe-simplify.h
+++ b/src/live_effects/lpe-simplify.h
@@ -6,7 +6,6 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
#include "live_effects/effect.h"
#include "live_effects/parameter/togglebutton.h"
#include "live_effects/lpegroupbbox.h"
diff --git a/src/live_effects/lpe-skeleton.cpp b/src/live_effects/lpe-skeleton.cpp
index 6e4afbe9b..d3c94269a 100644
--- a/src/live_effects/lpe-skeleton.cpp
+++ b/src/live_effects/lpe-skeleton.cpp
@@ -20,14 +20,9 @@
#include "live_effects/lpe-skeleton.h"
-// You might need to include other 2geom files. You can add them here:
-#include <2geom/path.h>
-
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
-//#include "knot-holder-entity.h"
-//#include "knotholder.h"
-
namespace Inkscape {
namespace LivePathEffect {
@@ -42,7 +37,7 @@ LPESkeleton::LPESkeleton(LivePathEffectObject *lpeobject) :
//_provides_knotholder_entities
/* register all your parameters here, so Inkscape knows which parameters this effect has: */
- registerParameter( dynamic_cast<Parameter *>(&number) );
+ registerParameter(&number);
}
LPESkeleton::~LPESkeleton()
@@ -102,10 +97,10 @@ public:
} // namespace Skeleton
void
-LPESkeleton::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
+LPESkeleton::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) {
{
KnotHolderEntityMyHandle *e = new KnotHolderEntityMyHandle(this);
- e->create( desktop, item, knotholder,
+ e->create( NULL, item, knotholder,
_("Text describing what this handle does"),
//optional: knot_shape, knot_mode, knot_color);
knotholder->add(e);
diff --git a/src/live_effects/lpe-skeleton.h b/src/live_effects/lpe-skeleton.h
index 3b45b6978..e633ba5ab 100644
--- a/src/live_effects/lpe-skeleton.h
+++ b/src/live_effects/lpe-skeleton.h
@@ -41,7 +41,7 @@ public:
/* the knotholder entity classes (if any) can be declared friends */
//friend class Skeleton::KnotHolderEntityMyHandle;
- //virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ //virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
private:
// add the parameters for your effect here:
diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp
index 82d343f6e..e3376b7e5 100644
--- a/src/live_effects/lpe-sketch.cpp
+++ b/src/live_effects/lpe-sketch.cpp
@@ -13,21 +13,14 @@
#include "live_effects/lpe-sketch.h"
-#include <glibmm/i18n.h>
-
// You might need to include other 2geom files. You can add them here:
-#include <2geom/path.h>
-#include <2geom/sbasis.h>
-#include <2geom/sbasis-geometric.h>
#include <2geom/sbasis-math.h>
#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/sbasis-math.h>
-#include <2geom/piecewise.h>
-#include <2geom/crossing.h>
#include <2geom/path-intersection.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -69,25 +62,25 @@ LPESketch::LPESketch(LivePathEffectObject *lpeobject) :
// register all your parameters here, so Inkscape knows which parameters this effect has:
//Add some comment in the UI: *warning* the precise output of this effect might change in future releases!
//convert to path if you want to keep exact output unchanged in future releases...
- //registerParameter( dynamic_cast<Parameter *>(&testpointA) );
- registerParameter( dynamic_cast<Parameter *>(&nbiter_approxstrokes) );
- registerParameter( dynamic_cast<Parameter *>(&strokelength) );
- registerParameter( dynamic_cast<Parameter *>(&strokelength_rdm) );
- registerParameter( dynamic_cast<Parameter *>(&strokeoverlap) );
- registerParameter( dynamic_cast<Parameter *>(&strokeoverlap_rdm) );
- registerParameter( dynamic_cast<Parameter *>(&ends_tolerance) );
- registerParameter( dynamic_cast<Parameter *>(&parallel_offset) );
- registerParameter( dynamic_cast<Parameter *>(&tremble_size) );
- registerParameter( dynamic_cast<Parameter *>(&tremble_frequency) );
+ //registerParameter(&testpointA) );
+ registerParameter(&nbiter_approxstrokes);
+ registerParameter(&strokelength);
+ registerParameter(&strokelength_rdm);
+ registerParameter(&strokeoverlap);
+ registerParameter(&strokeoverlap_rdm);
+ registerParameter(&ends_tolerance);
+ registerParameter(&parallel_offset);
+ registerParameter(&tremble_size);
+ registerParameter(&tremble_frequency);
#ifdef LPE_SKETCH_USE_CONSTRUCTION_LINES
- registerParameter( dynamic_cast<Parameter *>(&nbtangents) );
- registerParameter( dynamic_cast<Parameter *>(&tgt_places_rdmness) );
- registerParameter( dynamic_cast<Parameter *>(&tgtscale) );
- registerParameter( dynamic_cast<Parameter *>(&tgtlength) );
- registerParameter( dynamic_cast<Parameter *>(&tgtlength_rdm) );
+ registerParameter(&nbtangents);
+ registerParameter(&tgt_places_rdmness);
+ registerParameter(&tgtscale);
+ registerParameter(&tgtlength);
+ registerParameter(&tgtlength_rdm);
#ifdef LPE_SKETCH_USE_CURVATURE
- registerParameter( dynamic_cast<Parameter *>(&min_curvature) );
- registerParameter( dynamic_cast<Parameter *>(&max_curvature) );
+ registerParameter(&min_curvature);
+ registerParameter(&max_curvature);
#endif
#endif
diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp
index 0d42596b2..8ea57bee4 100644
--- a/src/live_effects/lpe-spiro.cpp
+++ b/src/live_effects/lpe-spiro.cpp
@@ -7,9 +7,6 @@
#include "live_effects/lpe-spiro.h"
#include "display/curve.h"
-#include <typeinfo>
-#include <2geom/pathvector.h>
-#include <2geom/affine.h>
#include <2geom/curves.h>
#include "helper/geom-nodetype.h"
#include "helper/geom-curves.h"
@@ -19,8 +16,6 @@
// For handling un-continuous paths:
#include "message-stack.h"
#include "inkscape.h"
-#include "desktop.h"
-
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-tangent_to_curve.cpp b/src/live_effects/lpe-tangent_to_curve.cpp
index 978ab57fb..69a4dfad9 100644
--- a/src/live_effects/lpe-tangent_to_curve.cpp
+++ b/src/live_effects/lpe-tangent_to_curve.cpp
@@ -13,17 +13,13 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-tangent_to_curve.h"
#include "sp-path.h"
#include "display/curve.h"
-#include <2geom/path.h>
-#include <2geom/transforms.h>
-
-#include "knot-holder-entity.h"
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -64,10 +60,10 @@ LPETangentToCurve::LPETangentToCurve(LivePathEffectObject *lpeobject) :
show_orig_path = true;
_provides_knotholder_entities = true;
- registerParameter( dynamic_cast<Parameter *>(&angle) );
- registerParameter( dynamic_cast<Parameter *>(&t_attach) );
- registerParameter( dynamic_cast<Parameter *>(&length_left) );
- registerParameter( dynamic_cast<Parameter *>(&length_right) );
+ registerParameter(&angle);
+ registerParameter(&t_attach);
+ registerParameter(&length_left);
+ registerParameter(&length_right);
}
LPETangentToCurve::~LPETangentToCurve()
@@ -96,22 +92,22 @@ LPETangentToCurve::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const
}
void
-LPETangentToCurve::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
+LPETangentToCurve::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) {
{
KnotHolderEntity *e = new TtC::KnotHolderEntityAttachPt(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Adjust the point of attachment of the tangent") );
knotholder->add(e);
}
{
KnotHolderEntity *e = new TtC::KnotHolderEntityLeftEnd(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Adjust the <b>left</b> end of the tangent") );
knotholder->add(e);
}
{
KnotHolderEntity *e = new TtC::KnotHolderEntityRightEnd(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Adjust the <b>right</b> end of the tangent") );
knotholder->add(e);
}
diff --git a/src/live_effects/lpe-tangent_to_curve.h b/src/live_effects/lpe-tangent_to_curve.h
index 8e44c01d1..a6a3c17ca 100644
--- a/src/live_effects/lpe-tangent_to_curve.h
+++ b/src/live_effects/lpe-tangent_to_curve.h
@@ -41,7 +41,7 @@ public:
friend class TtC::KnotHolderEntityLeftEnd;
friend class TtC::KnotHolderEntityRightEnd;
friend class TtC::KnotHolderEntityAttachPt;
- virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item);
+ virtual void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item);
private:
ScalarParam angle;
diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp
index f2ddd4929..45394ae91 100644
--- a/src/live_effects/lpe-taperstroke.cpp
+++ b/src/live_effects/lpe-taperstroke.cpp
@@ -13,26 +13,20 @@
#include "live_effects/lpe-taperstroke.h"
-#include <2geom/path.h>
-#include <2geom/path.h>
#include <2geom/circle.h>
#include <2geom/sbasis-to-bezier.h>
#include "helper/geom-nodetype.h"
#include "helper/geom-pathstroke.h"
#include "display/curve.h"
-#include "sp-shape.h"
#include "style.h"
-#include "xml/repr.h"
-#include "sp-paint-server.h"
#include "svg/svg-color.h"
#include "desktop-style.h"
#include "svg/css-ostringstream.h"
#include "svg/svg.h"
-#include "knot-holder-entity.h"
#include "knotholder.h"
-
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
template<typename T>
@@ -97,6 +91,7 @@ LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) :
void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem)
{
if (SP_IS_SHAPE(lpeitem)) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem);
double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.;
@@ -123,8 +118,14 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem)
sp_desktop_apply_css_recursive(item, css, true);
sp_repr_css_attr_unref (css);
-
- line_width.param_set_value(width);
+ Glib::ustring pref_path = (Glib::ustring)"/live_effects/" +
+ (Glib::ustring)LPETypeConverter.get_key(effectType()).c_str() +
+ (Glib::ustring)"/" +
+ (Glib::ustring)"stroke_width";
+ bool valid = prefs->getEntry(pref_path).isValid();
+ if(!valid){
+ line_width.param_set_value(width);
+ }
line_width.write_to_SVG();
} else {
printf("WARNING: It only makes sense to apply Taper stroke to paths (not groups).\n");
@@ -441,14 +442,14 @@ Piecewise<D2<SBasis> > stretch_along(Piecewise<D2<SBasis> > pwd2_in, Geom::Path
}
}
-void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this);
- e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE);
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE);
knotholder->add(e);
KnotHolderEntity *f = new TpS::KnotHolderEntityAttachEnd(this);
- f->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE);
+ f->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE);
knotholder->add(f);
}
@@ -476,7 +477,6 @@ void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point con
// use that object.
Geom::PathVector pathv = lpe->pathvector_before_effect;
-
Piecewise<D2<SBasis> > pwd2;
Geom::Path p_in = return_at_first_cusp(pathv[0]);
pwd2.concat(p_in.toPwSb());
diff --git a/src/live_effects/lpe-taperstroke.h b/src/live_effects/lpe-taperstroke.h
index 88604486e..e3ecbb56c 100644
--- a/src/live_effects/lpe-taperstroke.h
+++ b/src/live_effects/lpe-taperstroke.h
@@ -36,7 +36,7 @@ public:
virtual Geom::PathVector doEffect_path (Geom::PathVector const& path_in);
Geom::PathVector doEffect_simplePath(Geom::PathVector const& path_in);
- virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item);
+ virtual void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item);
friend class TpS::KnotHolderEntityAttachBegin;
friend class TpS::KnotHolderEntityAttachEnd;
diff --git a/src/live_effects/lpe-test-doEffect-stack.cpp b/src/live_effects/lpe-test-doEffect-stack.cpp
index 2bcd4c136..c484c88a2 100644
--- a/src/live_effects/lpe-test-doEffect-stack.cpp
+++ b/src/live_effects/lpe-test-doEffect-stack.cpp
@@ -4,13 +4,11 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-test-doEffect-stack.h"
-#include <2geom/piecewise.h>
-#include <vector>
-#include <cstring>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
using std::memcpy;
namespace Inkscape {
@@ -23,12 +21,12 @@ LPEdoEffectStackTest::LPEdoEffectStackTest(LivePathEffectObject *lpeobject) :
point(_("Point param:"), "tooltip of point parameter", "point_param", &wr, this),
path(_("Path param:"), "tooltip of path parameter", "path_param", &wr, this,"M 0,100 100,0")
{
- registerParameter( dynamic_cast<Parameter *>(&step) );
- registerParameter( dynamic_cast<Parameter *>(&point) );
- registerParameter( dynamic_cast<Parameter *>(&path) );
+ registerParameter(&step);
+ registerParameter(&point);
+ registerParameter(&path);
point.set_oncanvas_looks(SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR, 0x00ff0000);
- point.param_setValue(point,true);
+ point.param_setValue(point);
}
LPEdoEffectStackTest::~LPEdoEffectStackTest()
diff --git a/src/live_effects/lpe-text_label.cpp b/src/live_effects/lpe-text_label.cpp
index 602a6897c..0c1db2f04 100644
--- a/src/live_effects/lpe-text_label.cpp
+++ b/src/live_effects/lpe-text_label.cpp
@@ -11,10 +11,11 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-text_label.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -22,7 +23,7 @@ LPETextLabel::LPETextLabel(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
label(_("Label:"), _("Text label attached to the path"), "label", &wr, this, "This is a label")
{
- registerParameter( dynamic_cast<Parameter *>(&label) );
+ registerParameter(&label);
}
LPETextLabel::~LPETextLabel()
diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp
index 1cd59b7fa..ab05b880c 100644
--- a/src/live_effects/lpe-transform_2pts.cpp
+++ b/src/live_effects/lpe-transform_2pts.cpp
@@ -14,15 +14,13 @@
#include "live_effects/lpe-transform_2pts.h"
#include "display/curve.h"
-#include <2geom/transforms.h>
-#include <2geom/pathvector.h>
-#include "sp-path.h"
#include "ui/icon-names.h"
#include "svg/svg.h"
#include "verbs.h"
// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -36,7 +34,7 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) :
flip_vertical(_("Flip vertical"), _("Flip vertical"), "flip_vertical", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
start(_("Start"), _("Start point"), "start", &wr, this, "Start point"),
end(_("End"), _("End point"), "end", &wr, this, "End point"),
- strech(_("Stretch"), _("Stretch the result"), "strech", &wr, this, 1),
+ stretch(_("Stretch"), _("Stretch the result"), "stretch", &wr, this, 1),
offset(_("Offset"), _("Offset from knots"), "offset", &wr, this, 0),
first_knot(_("First Knot"), _("First Knot"), "first_knot", &wr, this, 1),
last_knot(_("Last Knot"), _("Last Knot"), "last_knot", &wr, this, 1),
@@ -54,7 +52,7 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) :
registerParameter(&first_knot);
registerParameter(&last_knot);
registerParameter(&helper_size);
- registerParameter(&strech);
+ registerParameter(&stretch);
registerParameter(&offset);
registerParameter(&start);
registerParameter(&end);
@@ -66,18 +64,18 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) :
registerParameter(&lock_angle);
first_knot.param_make_integer(true);
- first_knot.param_overwrite_widget(true);
+ first_knot.param_set_undo(false);
last_knot.param_make_integer(true);
- last_knot.param_overwrite_widget(true);
+ last_knot.param_set_undo(false);
helper_size.param_set_range(0, 999);
helper_size.param_set_increments(1, 1);
helper_size.param_set_digits(0);
offset.param_set_range(-999999.0, 999999.0);
offset.param_set_increments(1, 1);
offset.param_set_digits(2);
- strech.param_set_range(0, 999.0);
- strech.param_set_increments(0.01, 0.01);
- strech.param_set_digits(4);
+ stretch.param_set_range(0, 999.0);
+ stretch.param_set_increments(0.01, 0.01);
+ stretch.param_set_digits(4);
apply_to_clippath_and_mask = true;
}
@@ -90,7 +88,6 @@ LPETransform2Pts::doOnApply(SPLPEItem const* lpeitem)
{
using namespace Geom;
original_bbox(lpeitem);
-
point_a = Point(boundingbox_X.min(), boundingbox_Y.middle());
point_b = Point(boundingbox_X.max(), boundingbox_Y.middle());
SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem);
@@ -141,14 +138,22 @@ LPETransform2Pts::doBeforeEffect (SPLPEItem const* lpeitem)
size_t nnodes = nodeCount(pathvector);
first_knot.param_set_range(1, last_knot-1);
last_knot.param_set_range(first_knot+1, nnodes);
- from_original_width.param_setValue(false);
+ if (from_original_width){
+ from_original_width.param_setValue(false);
+ }
} else {
- first_knot.param_set_value(1);
- last_knot.param_set_value(2);
+ if (first_knot != 1){
+ first_knot.param_set_value(1);
+ }
+ if (last_knot != 2){
+ last_knot.param_set_value(2);
+ }
first_knot.param_set_range(1,1);
last_knot.param_set_range(2,2);
- from_original_width.param_setValue(true);
append_path = false;
+ if (!from_original_width){
+ from_original_width.param_setValue(true);
+ }
}
if(lock_lenght && !lock_angle && previous_lenght != -1) {
Geom::Ray transformed((Geom::Point)start,(Geom::Point)end);
@@ -254,6 +259,8 @@ LPETransform2Pts::reset()
first_knot.param_set_value(1);
last_knot.param_set_value(2);
}
+ offset.param_set_value(0.0);
+ stretch.param_set_value(1.0);
Geom::Ray transformed(point_a, point_b);
previous_angle = transformed.angle();
previous_lenght = Geom::distance(point_a, point_b);
@@ -382,9 +389,9 @@ LPETransform2Pts::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const
m *= Geom::Scale(-1,1);
m *= Geom::Rotate(original_angle);
}
- if(strech != 1){
+ if(stretch != 1){
m *= Geom::Rotate(-original_angle);
- m *= Geom::Scale(1,strech);
+ m *= Geom::Scale(1,stretch);
m *= Geom::Rotate(original_angle);
}
if(elastic) {
@@ -434,7 +441,7 @@ LPETransform2Pts::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<
}
if(!lock_angle && lock_lenght) {
char const * svgd;
- svgd = "m 7.07,7.07 c -3.9,3.91 -10.24,3.91 -14.14,0 -3.91,-3.9 -3.91,-10.24 0,-14.14 3.9,-3.91 10.24,-3.91 14.14,0 l -2.83,-4.24 -0.7,2.12";
+ svgd = "M 0,9.94 C -2.56,9.91 -5.17,8.98 -7.07,7.07 c -3.91,-3.9 -3.91,-10.24 0,-14.14 1.97,-1.97 4.51,-3.02 7.07,-3.04 2.56,0.02 5.1,1.07 7.07,3.04 3.91,3.9 3.91,10.24 0,14.14 C 5.17,8.98 2.56,9.91 0,9.94 Z";
PathVector pathv_turn = sp_svg_read_pathv(svgd);
pathv_turn *= Geom::Rotate(previous_angle);
pathv_turn *= Affine(r,0,0,r,0,0) * Translate(Geom::Point(end));
diff --git a/src/live_effects/lpe-transform_2pts.h b/src/live_effects/lpe-transform_2pts.h
index c20d56206..0f88e6b00 100644
--- a/src/live_effects/lpe-transform_2pts.h
+++ b/src/live_effects/lpe-transform_2pts.h
@@ -57,7 +57,7 @@ private:
ToggleButtonParam flip_vertical;
PointParam start;
PointParam end;
- ScalarParam strech;
+ ScalarParam stretch;
ScalarParam offset;
ScalarParam first_knot;
ScalarParam last_knot;
diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp
index 7eda7446e..b9fd8908a 100644
--- a/src/live_effects/lpe-vonkoch.cpp
+++ b/src/live_effects/lpe-vonkoch.cpp
@@ -5,11 +5,9 @@
*/
#include "live_effects/lpe-vonkoch.h"
-
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
-#include <2geom/transforms.h>
-
//using std::vector;
namespace Inkscape {
namespace LivePathEffect {
@@ -55,15 +53,15 @@ LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) :
maxComplexity(_("_Max complexity:"), _("Disable effect if the output is too complex"), "maxComplexity", &wr, this, 1000)
{
//FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug.
- registerParameter( dynamic_cast<Parameter *>(&ref_path) );
- //registerParameter( dynamic_cast<Parameter *>(&refA) );
- //registerParameter( dynamic_cast<Parameter *>(&refB) );
- registerParameter( dynamic_cast<Parameter *>(&generator) );
- registerParameter( dynamic_cast<Parameter *>(&similar_only) );
- registerParameter( dynamic_cast<Parameter *>(&nbgenerations) );
- registerParameter( dynamic_cast<Parameter *>(&drawall) );
- registerParameter( dynamic_cast<Parameter *>(&maxComplexity) );
- //registerParameter( dynamic_cast<Parameter *>(&draw_boxes) );
+ registerParameter(&ref_path);
+ //registerParameter(&refA) );
+ //registerParameter(&refB) );
+ registerParameter(&generator);
+ registerParameter(&similar_only);
+ registerParameter(&nbgenerations);
+ registerParameter(&drawall);
+ registerParameter(&maxComplexity);
+ //registerParameter(&draw_boxes) );
apply_to_clippath_and_mask = true;
nbgenerations.param_make_integer();
nbgenerations.param_set_range(0, Geom::infinity());
diff --git a/src/live_effects/lpegroupbbox.cpp b/src/live_effects/lpegroupbbox.cpp
index 2a1b70a6a..3862ebcc8 100644
--- a/src/live_effects/lpegroupbbox.cpp
+++ b/src/live_effects/lpegroupbbox.cpp
@@ -7,8 +7,6 @@
#include "live_effects/lpegroupbbox.h"
-#include "sp-item.h"
-
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpeobject-reference.cpp b/src/live_effects/lpeobject-reference.cpp
index d9de6e77f..83cd6623c 100644
--- a/src/live_effects/lpeobject-reference.cpp
+++ b/src/live_effects/lpeobject-reference.cpp
@@ -6,10 +6,11 @@
* Released under GNU GPL, read the file 'COPYING' for more information.
*/
+#include "live_effects/lpeobject-reference.h"
+
#include <string.h>
-#include "enums.h"
-#include "live_effects/lpeobject-reference.h"
+#include "bad-uri-exception.h"
#include "live_effects/lpeobject.h"
#include "uri.h"
diff --git a/src/live_effects/lpeobject.cpp b/src/live_effects/lpeobject.cpp
index 8e5ae568f..ca3ae46e0 100644
--- a/src/live_effects/lpeobject.cpp
+++ b/src/live_effects/lpeobject.cpp
@@ -11,13 +11,10 @@
#include "xml/repr.h"
#include "xml/node-event-vector.h"
-#include "sp-object.h"
#include "attributes.h"
#include "document.h"
#include "document-private.h"
-#include <glibmm/i18n.h>
-
//#define LIVEPATHEFFECT_VERBOSE
static void livepatheffect_on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data);
@@ -115,6 +112,7 @@ void LivePathEffectObject::set(unsigned key, gchar const *value) {
this->effecttype_set = true;
} else {
this->effecttype = Inkscape::LivePathEffect::INVALID_LPE;
+ this->lpe = NULL;
this->effecttype_set = false;
}
diff --git a/src/live_effects/lpeobject.h b/src/live_effects/lpeobject.h
index 2e62707e3..e468b4080 100644
--- a/src/live_effects/lpeobject.h
+++ b/src/live_effects/lpeobject.h
@@ -38,8 +38,12 @@ public:
/* Note that the returned pointer can be NULL in a valid LivePathEffectObject contained in a valid list of lpeobjects in an lpeitem!
* So one should always check whether the returned value is NULL or not */
- Inkscape::LivePathEffect::Effect * get_lpe() { return lpe; };
- Inkscape::LivePathEffect::Effect const * get_lpe() const { return lpe; };
+ Inkscape::LivePathEffect::Effect * get_lpe() {
+ return lpe;
+ }
+ Inkscape::LivePathEffect::Effect const * get_lpe() const {
+ return lpe;
+ };
Inkscape::LivePathEffect::Effect *lpe; // this can be NULL in a valid LivePathEffectObject
diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert
deleted file mode 100644
index bd1c5b600..000000000
--- a/src/live_effects/parameter/Makefile_insert
+++ /dev/null
@@ -1,36 +0,0 @@
-## Makefile.am fragment sourced by src/Makefile.am.
-
-ink_common_sources += \
- live_effects/parameter/parameter.cpp \
- live_effects/parameter/parameter.h \
- live_effects/parameter/array.cpp \
- live_effects/parameter/array.h \
- live_effects/parameter/bool.cpp \
- live_effects/parameter/bool.h \
- live_effects/parameter/random.cpp \
- live_effects/parameter/random.h \
- live_effects/parameter/point.cpp \
- live_effects/parameter/point.h \
- live_effects/parameter/enum.h \
- live_effects/parameter/path-reference.cpp \
- live_effects/parameter/path-reference.h \
- live_effects/parameter/path.cpp \
- live_effects/parameter/path.h \
- live_effects/parameter/originalpath.cpp \
- live_effects/parameter/originalpath.h \
- live_effects/parameter/originalpatharray.cpp \
- live_effects/parameter/originalpatharray.h \
- live_effects/parameter/powerstrokepointarray.cpp \
- live_effects/parameter/powerstrokepointarray.h \
- live_effects/parameter/filletchamferpointarray.cpp \
- live_effects/parameter/filletchamferpointarray.h \
- live_effects/parameter/text.cpp \
- live_effects/parameter/text.h \
- live_effects/parameter/transformedpoint.cpp \
- live_effects/parameter/transformedpoint.h \
- live_effects/parameter/togglebutton.cpp \
- live_effects/parameter/togglebutton.h \
- live_effects/parameter/unit.cpp \
- live_effects/parameter/unit.h \
- live_effects/parameter/vector.cpp \
- live_effects/parameter/vector.h
diff --git a/src/live_effects/parameter/array.cpp b/src/live_effects/parameter/array.cpp
index 1b8f742da..7470f54cd 100644
--- a/src/live_effects/parameter/array.cpp
+++ b/src/live_effects/parameter/array.cpp
@@ -5,10 +5,7 @@
*/
#include "live_effects/parameter/array.h"
-
-#include "svg/svg.h"
-#include "svg/stringstream.h"
-
+#include "helper-fns.h"
#include <2geom/coord.h>
#include <2geom/point.h>
@@ -49,6 +46,45 @@ ArrayParam<Geom::Point>::readsvg(const gchar * str)
return Geom::Point(Geom::infinity(),Geom::infinity());
}
+
+template <>
+std::vector<Satellite>
+ArrayParam<std::vector<Satellite > >::readsvg(const gchar * str)
+{
+ std::vector<Satellite> subpath_satellites;
+ if (!str) {
+ return subpath_satellites;
+ }
+ gchar ** strarray = g_strsplit(str, "@", 0);
+ gchar ** iter = strarray;
+ while (*iter != NULL) {
+ gchar ** strsubarray = g_strsplit(*iter, ",", 8);
+ if (*strsubarray[7]) {//steps always > 0
+ Satellite *satellite = new Satellite();
+ satellite->setSatelliteType(g_strstrip(strsubarray[0]));
+ satellite->is_time = strncmp(strsubarray[1],"1",1) == 0;
+ satellite->selected = strncmp(strsubarray[2],"1",1) == 0;
+ satellite->has_mirror = strncmp(strsubarray[3],"1",1) == 0;
+ satellite->hidden = strncmp(strsubarray[4],"1",1) == 0;
+ double amount,angle;
+ float stepsTmp;
+ sp_svg_number_read_d(strsubarray[5], &amount);
+ sp_svg_number_read_d(strsubarray[6], &angle);
+ sp_svg_number_read_f(g_strstrip(strsubarray[7]), &stepsTmp);
+ unsigned int steps = (unsigned int)stepsTmp;
+ satellite->amount = amount;
+ satellite->angle = angle;
+ satellite->steps = steps;
+ subpath_satellites.push_back(*satellite);
+ }
+ g_strfreev (strsubarray);
+ iter++;
+ }
+ g_strfreev (strarray);
+ return subpath_satellites;
+}
+
+
} /* namespace LivePathEffect */
} /* namespace Inkscape */
diff --git a/src/live_effects/parameter/array.h b/src/live_effects/parameter/array.h
index a600f0257..e65d3b55c 100644
--- a/src/live_effects/parameter/array.h
+++ b/src/live_effects/parameter/array.h
@@ -15,6 +15,7 @@
#include "live_effects/parameter/parameter.h"
+#include "helper/geom-satellite.h"
#include "svg/svg.h"
#include "svg/stringstream.h"
@@ -59,7 +60,7 @@ public:
g_strfreev (strarray);
return true;
}
-
+ virtual void param_update_default(const gchar * default_value){};
virtual gchar * param_getSVGValue() const {
Inkscape::SVGOStringStream os;
writesvg(os, _vector);
@@ -93,7 +94,43 @@ protected:
// separate items with pipe symbol
str << " | ";
}
- str << vector[i];
+ writesvgData(str,vector[i]);
+ }
+ }
+
+ void writesvgData(SVGOStringStream &str, float const &vector_data) const {
+ str << vector_data;
+ }
+
+ void writesvgData(SVGOStringStream &str, double const &vector_data) const {
+ str << vector_data;
+ }
+
+ void writesvgData(SVGOStringStream &str, Geom::Point const &vector_data) const {
+ str << vector_data;
+ }
+
+ void writesvgData(SVGOStringStream &str, std::vector<Satellite> const &vector_data) const {
+ for (size_t i = 0; i < vector_data.size(); ++i) {
+ if (i != 0) {
+ // separate items with @ symbol ¿Any other?
+ str << " @ ";
+ }
+ str << vector_data[i].getSatelliteTypeGchar();
+ str << ",";
+ str << vector_data[i].is_time;
+ str << ",";
+ str << vector_data[i].selected;
+ str << ",";
+ str << vector_data[i].has_mirror;
+ str << ",";
+ str << vector_data[i].hidden;
+ str << ",";
+ str << vector_data[i].amount;
+ str << ",";
+ str << vector_data[i].angle;
+ str << ",";
+ str << static_cast<int>(vector_data[i].steps);
}
}
diff --git a/src/live_effects/parameter/bool.cpp b/src/live_effects/parameter/bool.cpp
index 9ecadbdeb..954947cf4 100644
--- a/src/live_effects/parameter/bool.cpp
+++ b/src/live_effects/parameter/bool.cpp
@@ -21,8 +21,8 @@ namespace LivePathEffect {
BoolParam::BoolParam( const Glib::ustring& label, const Glib::ustring& tip,
const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
- Effect* effect, bool default_value , bool no_widget)
- : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value), hide_widget(no_widget)
+ Effect* effect, bool default_value)
+ : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value)
{
}
@@ -36,6 +36,18 @@ BoolParam::param_set_default()
param_setValue(defvalue);
}
+void
+BoolParam::param_update_default(bool const default_value)
+{
+ defvalue = default_value;
+}
+
+void
+BoolParam::param_update_default(const gchar * default_value)
+{
+ param_update_default(helperfns_read_bool(default_value, defvalue));
+}
+
bool
BoolParam::param_readSVGValue(const gchar * strvalue)
{
@@ -53,7 +65,7 @@ BoolParam::param_getSVGValue() const
Gtk::Widget *
BoolParam::param_newWidget()
{
- if(!hide_widget){
+ if(widget_is_visible){
Inkscape::UI::Widget::RegisteredCheckButton * checkwdg = Gtk::manage(
new Inkscape::UI::Widget::RegisteredCheckButton( param_label,
param_tooltip,
@@ -66,7 +78,6 @@ BoolParam::param_newWidget()
checkwdg->setActive(value);
checkwdg->setProgrammatically = false;
checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change bool parameter"));
-
return dynamic_cast<Gtk::Widget *> (checkwdg);
} else {
return NULL;
@@ -76,6 +87,9 @@ BoolParam::param_newWidget()
void
BoolParam::param_setValue(bool newvalue)
{
+ if (value != newvalue) {
+ param_effect->upd_params = true;
+ }
value = newvalue;
}
diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h
index 403dd0b87..417752050 100644
--- a/src/live_effects/parameter/bool.h
+++ b/src/live_effects/parameter/bool.h
@@ -25,8 +25,7 @@ public:
const Glib::ustring& key,
Inkscape::UI::Widget::Registry* wr,
Effect* effect,
- bool default_value = false,
- bool no_widget = false);
+ bool default_value = false);
virtual ~BoolParam();
virtual Gtk::Widget * param_newWidget();
@@ -36,9 +35,9 @@ public:
void param_setValue(bool newvalue);
virtual void param_set_default();
-
+ void param_update_default(bool const default_value);
+ virtual void param_update_default(const gchar * default_value);
bool get_value() const { return value; };
-
inline operator bool() const { return value; };
private:
@@ -47,7 +46,6 @@ private:
bool value;
bool defvalue;
- bool hide_widget;
};
diff --git a/src/live_effects/parameter/enum.h b/src/live_effects/parameter/enum.h
index 2340663c3..78fa87a4f 100644
--- a/src/live_effects/parameter/enum.h
+++ b/src/live_effects/parameter/enum.h
@@ -27,12 +27,14 @@ public:
const Util::EnumDataConverter<E>& c,
Inkscape::UI::Widget::Registry* wr,
Effect* effect,
- E default_value)
+ E default_value,
+ bool sort = true)
: Parameter(label, tip, key, wr, effect)
{
enumdataconv = &c;
defvalue = default_value;
value = defvalue;
+ sorted = sort;
};
virtual ~EnumParam() { };
@@ -40,12 +42,11 @@ public:
virtual Gtk::Widget * param_newWidget() {
Inkscape::UI::Widget::RegisteredEnum<E> *regenum = Gtk::manage (
new Inkscape::UI::Widget::RegisteredEnum<E>( param_label, param_tooltip,
- param_key, *enumdataconv, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) );
+ param_key, *enumdataconv, *param_wr, param_effect->getRepr(), param_effect->getSPDoc(), sorted ) );
regenum->set_active_by_id(value);
regenum->combobox()->setProgrammatically = false;
regenum->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change enumeration parameter"));
-
return dynamic_cast<Gtk::Widget *> (regenum);
};
@@ -75,8 +76,19 @@ public:
void param_set_default() {
param_set_value(defvalue);
}
-
+
+ void param_update_default(E default_value) {
+ defvalue = default_value;
+ }
+
+ virtual void param_update_default(const gchar * default_value) {
+ param_update_default(enumdataconv->get_id_from_key(Glib::ustring(default_value)));
+ }
+
void param_set_value(E val) {
+ if (value != val) {
+ param_effect->upd_params = true;
+ }
value = val;
}
@@ -86,6 +98,7 @@ private:
E value;
E defvalue;
+ bool sorted;
const Util::EnumDataConverter<E> * enumdataconv;
};
diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp
deleted file mode 100644
index b321a5831..000000000
--- a/src/live_effects/parameter/filletchamferpointarray.cpp
+++ /dev/null
@@ -1,877 +0,0 @@
-/*
- * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
- * Special thanks to Johan Engelen for the base of the effect -powerstroke-
- * Also to ScislaC for point me to the idea
- * Also su_v for his construvtive feedback and time
- * and finaly to Liam P. White for his big help on coding, that save me a lot of
- * hours
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include <2geom/piecewise.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/sbasis-geometric.h>
-#include <2geom/line.h>
-#include <2geom/path-intersection.h>
-
-#include "ui/dialog/lpe-fillet-chamfer-properties.h"
-#include "live_effects/parameter/filletchamferpointarray.h"
-#include "live_effects/effect.h"
-#include "svg/svg.h"
-#include "svg/stringstream.h"
-#include "knotholder.h"
-#include "sp-lpe-item.h"
-#include "selection.h"
-
-// needed for on-canvas editting:
-#include "desktop.h"
-#include "live_effects/lpeobject.h"
-#include "helper/geom-nodetype.h"
-#include "helper/geom-curves.h"
-#include "ui/tools/node-tool.h"
-
-// TODO due to internal breakage in glibmm headers,
-// this has to be included last.
-#include <glibmm/i18n.h>
-
-
-using namespace Geom;
-
-namespace Inkscape {
-
-namespace LivePathEffect {
-
-FilletChamferPointArrayParam::FilletChamferPointArrayParam(
- const Glib::ustring &label, const Glib::ustring &tip,
- const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr,
- Effect *effect)
- : ArrayParam<Point>(label, tip, key, wr, effect, 0)
-{
- knot_shape = SP_KNOT_SHAPE_DIAMOND;
- knot_mode = SP_KNOT_MODE_XOR;
- knot_color = 0x00ff0000;
-}
-
-FilletChamferPointArrayParam::~FilletChamferPointArrayParam() {}
-
-Gtk::Widget *FilletChamferPointArrayParam::param_newWidget()
-{
- return NULL;
- /*
- Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg =
- Gtk::manage(
- new Inkscape::UI::Widget::RegisteredTransformedPoint(
- param_label,
- param_tooltip,
- param_key,
- *param_wr,
- param_effect->getRepr(),
- param_effect->getSPDoc()
- ) );
- // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP)
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
- Affine transf = desktop->doc2dt();
- pointwdg->setTransform(transf);
- pointwdg->setValue( *this );
- pointwdg->clearProgrammatically();
- pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT,
- _("Change point parameter"));
-
- Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() );
- static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true);
- static_cast<Gtk::HBox*>(hbox)->show_all_children();
-
- return dynamic_cast<Gtk::Widget *> (hbox);
- */
-}
-
-void
-FilletChamferPointArrayParam::param_transform_multiply(Affine const &postmul,
- bool /*set*/)
-{
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-
- if (prefs->getBool("/options/transform/rectcorners", true) &&
- _vector[1][X] <= 0) {
- std::vector<Geom::Point> result;
- for (std::vector<Point>::const_iterator point_it = _vector.begin();
- point_it != _vector.end(); ++point_it) {
- Coord A =
- (*point_it)[X] * ((postmul.expansionX() + postmul.expansionY()) / 2);
- result.push_back(Point(A, (*point_it)[Y]));
- }
- param_set_and_write_new_value(result);
- }
-
- // param_set_and_write_new_value( (*this) * postmul );
-}
-
-/** call this method to recalculate the controlpoints such that they stay at the
- * same location relative to the new path. Useful after adding/deleting nodes to
- * the path.*/
-void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2(
- Piecewise<D2<SBasis> > const &pwd2_in)
-{
- if (!last_pwd2.empty()) {
- PathVector const pathv =
- path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001);
- PathVector last_pathv =
- path_from_piecewise(remove_short_cuts(last_pwd2, 0.1), 0.001);
- std::vector<Point> result;
- unsigned long counter = 0;
- unsigned long counterPaths = 0;
- unsigned long counterCurves = 0;
- long offset = 0;
- long offsetPaths = 0;
- Geom::NodeType nodetype;
- for (PathVector::const_iterator path_it = pathv.begin();
- path_it != pathv.end(); ++path_it) {
- if (path_it->empty()) {
- counterPaths++;
- counter++;
- continue;
- }
- 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();
- if (path_it->closed() && path_it->back_closed().isDegenerate()) {
- const Curve &closingline = path_it->back_closed();
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- curve_endit = path_it->end_open();
- }
- }
- counterCurves = 0;
- while (curve_it1 != curve_endit) {
- //if start a path get node type
- if (counterCurves == 0) {
- if (path_it->closed()) {
- if (path_it->back_closed().isDegenerate()) {
- nodetype = get_nodetype(path_it->back_open(), *curve_it1);
- } else {
- nodetype = get_nodetype(path_it->back_closed(), *curve_it1);
- }
- } else {
- nodetype = NODE_NONE;
- }
- } else {
- //check node type also whith straight lines because get_nodetype
- //return non cusp node in a node inserted inside a straight line
- //todo: if the path remove some nodes whith the result of a straight
- //line but with handles, the node inserted into dont fire the knot
- // because is not handle as cusp node by get_nodetype function
- bool next_is_line = is_straight_curve(*curve_it1);
- bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
- nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
- if (this_is_line || next_is_line) {
- nodetype = NODE_CUSP;
- }
- }
- if (last_pathv.size() > pathv.size() ||
- (last_pathv.size() > counterPaths &&
- last_pathv[counterPaths].size() > counter - offset &&
- !are_near(curve_it1->initialPoint(),
- last_pathv[counterPaths][counter - offset].initialPoint(),
- 0.1))) {
- if ( curve_it2 == curve_endit) {
- if (last_pathv[counterPaths].size() != pathv[counterPaths].size()) {
- offset = (last_pathv[counterPaths].size() - pathv[counterPaths].size()) * -1;
- } else {
- offset = 0;
- }
- offsetPaths += offset;
- offset = offsetPaths;
- } else if (counterCurves == 0 && last_pathv.size() <= pathv.size() &&
- counter - offset <= last_pathv[counterPaths].size() &&
- are_near(curve_it1->initialPoint(),
- last_pathv[counterPaths].finalPoint(), 0.1) &&
- !last_pathv[counterPaths].closed()) {
- long e = counter - offset + 1;
- std::vector<Point> tmp = _vector;
- for (unsigned long i =
- last_pathv[counterPaths].size() + counter - offset;
- i > counterCurves - offset + 1; i--) {
-
- if (tmp[i - 1][X] > 0) {
- double fractpart, intpart;
- fractpart = modf(tmp[i - 1][X], &intpart);
- _vector[e] = Point(e + fractpart, tmp[i - 1][Y]);
- } else {
- _vector[e] = Point(tmp[i - 1][X], tmp[i - 1][Y]);
- }
- e++;
- }
- //delete temp vector
- std::vector<Point>().swap(tmp);
- if (last_pathv.size() > counterPaths) {
- last_pathv[counterPaths] = last_pathv[counterPaths].reversed();
- }
- } else {
- if (last_pathv.size() > counterPaths) {
- if (last_pathv[counterPaths].size() <
- pathv[counterPaths].size()) {
- offset++;
- } else if (last_pathv[counterPaths].size() >
- pathv[counterPaths].size()) {
- offset--;
- continue;
- }
- } else {
- offset++;
- }
- }
- double xPos = 0;
- if (_vector[1][X] > 0) {
- xPos = nearest_time(curve_it1->initialPoint(), pwd2_in);
- }
- if (nodetype == NODE_CUSP) {
- result.push_back(Point(xPos, 1));
- } else {
- result.push_back(Point(xPos, 0));
- }
- } else {
- double xPos = _vector[counter - offset][X];
- if (_vector.size() <= (unsigned)(counter - offset)) {
- if (_vector[1][X] > 0) {
- xPos = nearest_time(curve_it1->initialPoint(), pwd2_in);
- } else {
- xPos = 0;
- }
- }
- if (nodetype == NODE_CUSP) {
- double vectorY = _vector[counter - offset][Y];
- if (_vector.size() <= (unsigned)(counter - offset) || vectorY == 0) {
- vectorY = 1;
- }
- result.push_back(Point(xPos, vectorY));
- } else {
- if (_vector[1][X] < 0) {
- xPos = 0;
- }
- result.push_back(Point(floor(xPos), 0));
- }
- }
- ++curve_it1;
- if (curve_it2 != curve_endit) {
- ++curve_it2;
- }
- counter++;
- counterCurves++;
- }
- counterPaths++;
- }
- _vector = result;
- write_to_SVG();
- }
-}
-
-void FilletChamferPointArrayParam::recalculate_knots(
- Piecewise<D2<SBasis> > const &pwd2_in)
-{
- bool change = false;
- if(_vector.size() == 0){
- return;
- }
- PathVector pathv = path_from_piecewise(pwd2_in, 0.001);
- if (!pathv.empty()) {
- std::vector<Point> result;
- int counter = 0;
- int counterCurves = 0;
- Geom::NodeType nodetype;
- for (PathVector::const_iterator path_it = pathv.begin();
- path_it != pathv.end(); ++path_it) {
- if (path_it->empty()) {
- counter++;
- continue;
- }
- 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();
- if (path_it->closed() && path_it->back_closed().isDegenerate()) {
- const Curve &closingline = path_it->back_closed();
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- curve_endit = path_it->end_open();
- }
- }
- counterCurves = 0;
- while (curve_it1 != curve_endit) {
- //if start a path get node type
- if (counterCurves == 0) {
- if (path_it->closed()) {
- if (path_it->back_closed().isDegenerate()) {
- nodetype = get_nodetype(path_it->back_open(), *curve_it1);
- } else {
- nodetype = get_nodetype(path_it->back_closed(), *curve_it1);
- }
- } else {
- nodetype = NODE_NONE;
- }
- } else {
- bool next_is_line = is_straight_curve(*curve_it1);
- bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
- nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
- if (this_is_line || next_is_line) {
- nodetype = NODE_CUSP;
- }
- }
- if (nodetype == NODE_CUSP) {
- double vectorY = _vector[counter][Y];
- if (vectorY == 0) {
- vectorY = 1;
- change = true;
- }
- result.push_back(Point(_vector[counter][X], vectorY));
- } else {
- double xPos = floor(_vector[counter][X]);
- if (_vector[1][X] < 0) {
- xPos = 0;
- }
- double vectorY = _vector[counter][Y];
- if (vectorY != 0) {
- change = true;
- }
- result.push_back(Point(xPos, 0));
- }
- ++curve_it1;
- counter++;
- if (curve_it2 != curve_endit) {
- ++curve_it2;
- }
- counterCurves++;
- }
- }
- if (change) {
- _vector = result;
- write_to_SVG();
- }
- }
-}
-
-void FilletChamferPointArrayParam::set_pwd2(
- Piecewise<D2<SBasis> > const &pwd2_in,
- Piecewise<D2<SBasis> > const &pwd2_normal_in)
-{
- last_pwd2 = pwd2_in;
- last_pwd2_normal = pwd2_normal_in;
-}
-
-void FilletChamferPointArrayParam::set_helper_size(int hs)
-{
- helper_size = hs;
-}
-
-void FilletChamferPointArrayParam::set_chamfer_steps(int value_chamfer_steps)
-{
- chamfer_steps = value_chamfer_steps;
-}
-
-void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance )
-{
- use_distance = use_knot_distance;
-}
-
-void FilletChamferPointArrayParam::updateCanvasIndicators()
-{
- std::vector<Point> ts = data();
- hp.clear();
- unsigned int i = 0;
- for (std::vector<Point>::const_iterator point_it = ts.begin();
- point_it != ts.end(); ++point_it) {
- double Xvalue = to_time(i, (*point_it)[X]) -i;
- if (Xvalue == 0) {
- i++;
- continue;
- }
- Geom::Point ptA = last_pwd2[i].valueAt(Xvalue);
- Geom::Point derivA = unit_vector(derivative(last_pwd2[i]).valueAt(Xvalue));
- Geom::Rotate rot(Geom::Rotate::from_degrees(-90));
- derivA = derivA * rot;
- Geom::Point C = ptA - derivA * helper_size;
- Geom::Point D = ptA + derivA * helper_size;
- Geom::Ray ray1(C, D);
- char const * svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5";
- Geom::PathVector pathv = sp_svg_read_pathv(svgd);
- Geom::Affine aff = Geom::Affine();
- aff *= Geom::Scale(helper_size);
- aff *= Geom::Rotate(ray1.angle() - rad_from_deg(270));
- aff *= Geom::Translate(last_pwd2[i].valueAt(Xvalue));
- pathv *= aff;
- hp.push_back(pathv[0]);
- hp.push_back(pathv[1]);
- i++;
- }
-}
-
-void FilletChamferPointArrayParam::addCanvasIndicators(
- SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
-{
- hp_vec.push_back(hp);
-}
-
-double FilletChamferPointArrayParam::rad_to_len(int index, double rad)
-{
- double len = 0;
- Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1);
- std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
- D2<SBasis> A = last_pwd2[last_index(index, subpaths)];
- if(positions.second != 0){
- A = last_pwd2[index-1];
- }else{
- if(!subpaths[positions.first].closed()){
- return len;
- }
- }
- D2<SBasis> B = last_pwd2[index];
- Piecewise<D2<SBasis> > offset_curve0 = Piecewise<D2<SBasis> >(A)+rot90(unitVector(derivative(A)))*(rad);
- Piecewise<D2<SBasis> > offset_curve1 = Piecewise<D2<SBasis> >(B)+rot90(unitVector(derivative(B)))*(rad);
- Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0];
- Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0];
- Geom::Crossings cs = Geom::crossings(p0, p1);
- if(cs.size() > 0){
- Point cp =p0(cs[0].ta);
- double p0pt = nearest_time(cp, B);
- len = time_to_len(index,p0pt);
- } else {
- if(rad < 0){
- len = rad_to_len(index, rad * -1);
- }
- }
- return len;
-}
-
-double FilletChamferPointArrayParam::len_to_rad(int index, double len)
-{
- double rad = 0;
- double tmp_len = _vector[index][X];
- _vector[index] = Geom::Point(len,_vector[index][Y]);
- Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1);
- std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
- Piecewise<D2<SBasis> > u;
- u.push_cut(0);
- u.push(last_pwd2[last_index(index, subpaths)], 1);
- Geom::Curve * A = path_from_piecewise(u, 0.1)[0][0].duplicate();
- Geom::Curve * B = subpaths[positions.first][positions.second].duplicate();
- std::vector<double> times;
- if(positions.second != 0){
- A = subpaths[positions.first][positions.second-1].duplicate();
- times = get_times(index-1, subpaths, false);
- }else{
- if(!subpaths[positions.first].closed()){
- return rad;
- }
- times = get_times(last_index(index, subpaths), subpaths, true);
- }
- _vector[index] = Geom::Point(tmp_len,_vector[index][Y]);
- Geom::Point startArcPoint = A->toSBasis().valueAt(times[1]);
- Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]);
- Curve *knotCurve1 = A->portion(times[0], times[1]);
- Curve *knotCurve2 = B->portion(times[2], 1);
- Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(knotCurve1);
- Ray ray1(startArcPoint, A->finalPoint());
- if (cubic1) {
- ray1.setPoints((*cubic1)[2], startArcPoint);
- }
- Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(knotCurve2);
- Ray ray2(B->initialPoint(), endArcPoint);
- if (cubic2) {
- ray2.setPoints(endArcPoint, (*cubic2)[1]);
- }
- bool ccwToggle = cross(A->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0;
- double distanceArc = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint));
- double angleBetween = angle_between(ray1, ray2, ccwToggle);
- rad = distanceArc/sin(angleBetween/2.0);
- return rad * -1;
-}
-
-std::vector<double> FilletChamferPointArrayParam::get_times(int index, Geom::PathVector subpaths, bool last)
-{
- const double tolerance = 0.001;
- const double gapHelper = 0.00001;
- std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
- Curve *curve_it1;
- curve_it1 = subpaths[positions.first][positions.second].duplicate();
- Coord it1_length = (*curve_it1).length(tolerance);
- double time_it1, time_it2, time_it1_B, intpart;
- if (static_cast<int>(_vector.size()) <= index){
- std::vector<double> out;
- out.push_back(0);
- out.push_back(1);
- out.push_back(0);
- return out;
- }
- time_it1 = modf(to_time(index, _vector[index][X]), &intpart);
- if (_vector[index][Y] == 0) {
- time_it1 = 0;
- }
- double resultLenght = 0;
- if (subpaths[positions.first].closed() && last) {
- time_it2 = modf(to_time(index - positions.second , _vector[index - positions.second ][X]), &intpart);
- resultLenght = it1_length + to_len(index - positions.second, _vector[index - positions.second ][X]);
- } else if (!subpaths[positions.first].closed() && last){
- time_it2 = 0;
- resultLenght = 0;
- } else {
- time_it2 = modf(to_time(index + 1, _vector[index + 1][X]), &intpart);
- resultLenght = it1_length + to_len( index + 1, _vector[index + 1][X]);
- }
- if (resultLenght > 0 && time_it2 != 0) {
- time_it1_B = modf(to_time(index, -resultLenght), &intpart);
- } else {
- if (time_it2 == 0) {
- time_it1_B = 1;
- } else {
- time_it1_B = gapHelper;
- }
- }
-
- if ((subpaths[positions.first].closed() && last && _vector[index - positions.second][Y] == 0) || (subpaths[positions.first].size() > positions.second + 1 && _vector[index + 1][Y] == 0)) {
- time_it1_B = 1;
- time_it2 = 0;
- }
- if (time_it1_B < time_it1) {
- time_it1_B = time_it1 + gapHelper;
- }
- std::vector<double> out;
- out.push_back(time_it1);
- out.push_back(time_it1_B);
- out.push_back(time_it2);
- return out;
-}
-
-std::pair<std::size_t, std::size_t> FilletChamferPointArrayParam::get_positions(int index, Geom::PathVector subpaths)
-{
- int counter = -1;
- std::size_t first = 0;
- std::size_t second = 0;
- for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) {
- if (path_it->empty())
- continue;
- Geom::Path::const_iterator curve_it1 = path_it->begin();
- Geom::Path::const_iterator curve_endit = path_it->end_default();
- if (path_it->closed()) {
- const Geom::Curve &closingline = path_it->back_closed();
- // the closing line segment is always of type
- // Geom::LineSegment.
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- // closingline.isDegenerate() did not work, because it only checks for
- // *exact* zero length, which goes wrong for relative coordinates and
- // rounding errors...
- // the closing line segment has zero-length. So stop before that one!
- curve_endit = path_it->end_open();
- }
- }
- first++;
- second = 0;
- while (curve_it1 != curve_endit) {
- counter++;
- second++;
- if(counter == index){
- break;
- }
- ++curve_it1;
- }
- if(counter == index){
- break;
- }
- }
- first--;
- second--;
- std::pair<std::size_t, std::size_t> out(first, second);
- return out;
-}
-
-int FilletChamferPointArrayParam::last_index(int index, Geom::PathVector subpaths)
-{
- int counter = -1;
- bool inSubpath = false;
- for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) {
- if (path_it->empty())
- continue;
- Geom::Path::const_iterator curve_it1 = path_it->begin();
- Geom::Path::const_iterator curve_endit = path_it->end_default();
- if (path_it->closed()) {
- const Geom::Curve &closingline = path_it->back_closed();
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- curve_endit = path_it->end_open();
- }
- }
- while (curve_it1 != curve_endit) {
- counter++;
- if(counter == index){
- inSubpath = true;
- }
- ++curve_it1;
- }
- if(inSubpath){
- break;
- }
- }
- if(!inSubpath){
- counter = -1;
- }
- return counter;
-}
-
-
-double FilletChamferPointArrayParam::len_to_time(int index, double len)
-{
- double t = 0;
- if (last_pwd2.size() > (unsigned) index) {
- if (len != 0) {
- if (last_pwd2[index][0].degreesOfFreedom() != 2) {
- Piecewise<D2<SBasis> > u;
- u.push_cut(0);
- u.push(last_pwd2[index], 1);
- std::vector<double> t_roots = roots(arcLengthSb(u) - std::abs(len));
- if (t_roots.size() > 0) {
- t = t_roots[0];
- }
- } else {
- double lenghtPart = 0;
- if (last_pwd2.size() > (unsigned) index) {
- lenghtPart = length(last_pwd2[index], EPSILON);
- }
- if (std::abs(len) < lenghtPart && lenghtPart != 0) {
- t = std::abs(len) / lenghtPart;
- }
- }
- }
- t = double(index) + t;
- } else {
- t = double(last_pwd2.size() - 1);
- }
-
- return t;
-}
-
-double FilletChamferPointArrayParam::time_to_len(int index, double time)
-{
- double intpart;
- double len = 0;
- time = modf(time, &intpart);
- double lenghtPart = 0;
- if (last_pwd2.size() <= (unsigned) index || time == 0) {
- return len;
- }
- if (last_pwd2[index][0].degreesOfFreedom() != 2) {
- Piecewise<D2<SBasis> > u;
- u.push_cut(0);
- u.push(last_pwd2[index], 1);
- u = portion(u, 0, time);
- return length(u, 0.001) * -1;
- }
- lenghtPart = length(last_pwd2[index], EPSILON);
- return (time * lenghtPart) * -1;
-}
-
-double FilletChamferPointArrayParam::to_time(int index, double A)
-{
- if (A > 0) {
- return A;
- } else {
- return len_to_time(index, A);
- }
-}
-
-double FilletChamferPointArrayParam::to_len(int index, double A)
-{
- if (A > 0) {
- return time_to_len(index, A);
- } else {
- return A;
- }
-}
-
-void FilletChamferPointArrayParam::set_oncanvas_looks(SPKnotShapeType shape,
- SPKnotModeType mode,
- guint32 color)
-{
- knot_shape = shape;
- knot_mode = mode;
- knot_color = color;
-}
-
-FilletChamferPointArrayParamKnotHolderEntity::
-FilletChamferPointArrayParamKnotHolderEntity(
- FilletChamferPointArrayParam *p, unsigned int index)
- : _pparam(p), _index(index) {}
-
-void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p,
- Point const &/*origin*/,
- guint state)
-{
- using namespace Geom;
-
- if (!valid_index(_index)) {
- return;
- }
- Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2();
- double t = nearest_time(p, pwd2[_index]);
- Geom::Point const s = snap_knot_position(pwd2[_index].valueAt(t), state);
- t = nearest_time(s, pwd2[_index]);
- if (t == 1) {
- t = 0.9999;
- }
- t += _index;
-
- if (_pparam->_vector.at(_index)[X] <= 0) {
- _pparam->_vector.at(_index) =
- Point(_pparam->time_to_len(_index, t), _pparam->_vector.at(_index)[Y]);
- } else {
- _pparam->_vector.at(_index) = Point(t, _pparam->_vector.at(_index)[Y]);
- }
- sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
-}
-
-Point FilletChamferPointArrayParamKnotHolderEntity::knot_get() const
-{
- using namespace Geom;
-
- if (!valid_index(_index)) {
- return Point(infinity(), infinity());
- }
-
- Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2();
-
- double time_it = _pparam->to_time(_index, _pparam->_vector.at(_index)[X]);
- Point canvas_point = pwd2.valueAt(time_it);
-
- _pparam->updateCanvasIndicators();
- return canvas_point;
-
-}
-
-void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state)
-{
- if (state & GDK_CONTROL_MASK) {
- if (state & GDK_MOD1_MASK) {
- _pparam->_vector.at(_index) = Point(_index, _pparam->_vector.at(_index)[Y]);
- _pparam->param_set_and_write_new_value(_pparam->_vector);
- sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
- }else{
- using namespace Geom;
- int type = (int)_pparam->_vector.at(_index)[Y];
- if (type >=3000 && type < 4000){
- type = 3;
- }
- if (type >=4000 && type < 5000){
- type = 4;
- }
- switch(type){
- case 1:
- type = 2;
- break;
- case 2:
- type = _pparam->chamfer_steps + 3000;
- break;
- case 3:
- type = _pparam->chamfer_steps + 4000;
- break;
- default:
- type = 1;
- break;
- }
- _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], (double)type);
- _pparam->param_set_and_write_new_value(_pparam->_vector);
- sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
- const gchar *tip;
- if (type >=3000 && type < 4000){
- tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
- "<b>Shift+Click</b> open dialog, "
- "<b>Ctrl+Alt+Click</b> reset");
- } else if (type >=4000 && type < 5000) {
- tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
- "<b>Shift+Click</b> open dialog, "
- "<b>Ctrl+Alt+Click</b> reset");
- } else if (type == 2) {
- tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, "
- "<b>Shift+Click</b> open dialog, "
- "<b>Ctrl+Alt+Click</b> reset");
- } else {
- tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, "
- "<b>Shift+Click</b> open dialog, "
- "<b>Ctrl+Alt+Click</b> reset");
- }
- this->knot->tip = g_strdup(tip);
- this->knot->show();
- }
- } else if (state & GDK_SHIFT_MASK) {
- double xModified = _pparam->_vector.at(_index).x();
- if(xModified < 0 && !_pparam->use_distance){
- xModified = _pparam->len_to_rad(_index, _pparam->_vector.at(_index).x());
- }
- Geom::PathVector subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1);
- std::pair<std::size_t, std::size_t> positions = _pparam->get_positions(_index, subpaths);
- D2<SBasis> A = _pparam->last_pwd2[_pparam->last_index(_index, subpaths)];
- if(positions.second != 0){
- A = _pparam->last_pwd2[_index-1];
- }
- D2<SBasis> B = _pparam->last_pwd2[_index];
- bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false;
- Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y());
- Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog(
- this->desktop, offset, this, _pparam->use_distance, aprox);
- }
-
-}
-
-void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset(
- Geom::Point offset)
-{
- double xModified = offset.x();
- if(xModified < 0 && !_pparam->use_distance){
- xModified = _pparam->rad_to_len(_index, offset.x());
- }
- _pparam->_vector.at(_index) = Geom::Point(xModified, offset.y());
- this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
-}
-
-void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
- SPDesktop *desktop,
- SPItem *item)
-{
- recalculate_knots(get_pwd2());
- for (unsigned int i = 0; i < _vector.size(); ++i) {
- if (_vector[i][Y] <= 0) {
- continue;
- }
- const gchar *tip;
- if (_vector[i][Y] >=3000 && _vector[i][Y] < 4000){
- tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
- "<b>Shift+Click</b> open dialog, "
- "<b>Ctrl+Alt+Click</b> reset");
- } else if (_vector[i][Y] >=4000 && _vector[i][Y] < 5000) {
- tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
- "<b>Shift+Click</b> open dialog, "
- "<b>Ctrl+Alt+Click</b> reset");
- } else if (_vector[i][Y] == 2) {
- tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, "
- "<b>Shift+Click</b> open dialog, "
- "<b>Ctrl+Alt+Click</b> reset");
- } else {
- tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, "
- "<b>Shift+Click</b> open dialog, "
- "<b>Ctrl+Alt+Click</b> reset");
- }
- FilletChamferPointArrayParamKnotHolderEntity *e =
- new FilletChamferPointArrayParamKnotHolderEntity(this, i);
- e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),
- knot_shape, knot_mode, knot_color);
- knotholder->add(e);
- }
- updateCanvasIndicators();
-}
-
-} /* namespace LivePathEffect */
-
-} /* 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 :
diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h
deleted file mode 100644
index 48cd26d2d..000000000
--- a/src/live_effects/parameter/filletchamferpointarray.h
+++ /dev/null
@@ -1,123 +0,0 @@
-#ifndef INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
-#define INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
-
-/*
- * Inkscape::LivePathEffectParameters
- * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
- * Special thanks to Johan Engelen for the base of the effect -powerstroke-
- * Also to ScislaC for point me to the idea
- * Also su_v for his construvtive feedback and time
- * and finaly to Liam P. White for his big help on coding, that save me a lot of
- * hours
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include <glib.h>
-#include <2geom/point.h>
-
-#include "live_effects/parameter/array.h"
-
-#include "knot-holder-entity.h"
-
-namespace Inkscape {
-
-namespace LivePathEffect {
-
-class FilletChamferPointArrayParamKnotHolderEntity;
-
-class FilletChamferPointArrayParam : public ArrayParam<Geom::Point> {
-public:
- FilletChamferPointArrayParam(const Glib::ustring &label,
- const Glib::ustring &tip,
- const Glib::ustring &key,
- Inkscape::UI::Widget::Registry *wr,
- Effect *effect);
- virtual ~FilletChamferPointArrayParam();
-
- virtual Gtk::Widget *param_newWidget();
-
- virtual void param_transform_multiply(Geom::Affine const &postmul,
- bool /*set*/);
-
- void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode,
- guint32 color);
- virtual double to_time(int index, double A);
- virtual double to_len(int index, double A);
- virtual double rad_to_len(int index, double rad);
- virtual double len_to_rad(int index, double len);
- virtual double len_to_time(int index, double len);
- virtual double time_to_len(int index, double time);
- virtual std::pair<std::size_t, std::size_t> get_positions(int index, Geom::PathVector subpaths);
- virtual int last_index(int index, Geom::PathVector subpaths);
- std::vector<double> get_times(int index, Geom::PathVector subpaths, bool last);
- virtual void set_helper_size(int hs);
- virtual void set_use_distance(bool use_knot_distance);
- virtual void set_chamfer_steps(int value_chamfer_steps);
- virtual void addCanvasIndicators(SPLPEItem const *lpeitem,
- std::vector<Geom::PathVector> &hp_vec);
- virtual bool providesKnotHolderEntities() const {
- return true;
- }
- virtual void updateCanvasIndicators();
- virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop,
- SPItem *item);
-
- void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in,
- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_normal_in);
- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2() const {
- return last_pwd2;
- }
- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2_normal() const {
- return last_pwd2_normal;
- }
-
- void recalculate_controlpoints_for_new_pwd2(
- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in);
- void recalculate_knots(
- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in);
- friend class FilletChamferPointArrayParamKnotHolderEntity;
-
-private:
- FilletChamferPointArrayParam(const FilletChamferPointArrayParam &);
- FilletChamferPointArrayParam &operator=(const FilletChamferPointArrayParam &);
-
- SPKnotShapeType knot_shape;
- SPKnotModeType knot_mode;
- guint32 knot_color;
- int helper_size;
- int chamfer_steps;
- bool use_distance;
- Geom::PathVector hp;
-
- Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2;
- Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal;
-};
-
-class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity {
-public:
- FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam *p,
- unsigned int index);
- virtual ~FilletChamferPointArrayParamKnotHolderEntity() {}
-
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin,
- guint state);
- virtual Geom::Point knot_get() const;
- virtual void knot_click(guint state);
- virtual void knot_set_offset(Geom::Point offset);
-
- /*Checks whether the index falls within the size of the parameter's vector*/
- bool valid_index(unsigned int index) const {
- return (_pparam->_vector.size() > index);
- }
- ;
-
-private:
- FilletChamferPointArrayParam *_pparam;
- unsigned int _index;
-};
-
-} //namespace LivePathEffect
-
-} //namespace Inkscape
-
-#endif
diff --git a/src/live_effects/parameter/fontbutton.cpp b/src/live_effects/parameter/fontbutton.cpp
new file mode 100644
index 000000000..ca8908f0e
--- /dev/null
+++ b/src/live_effects/parameter/fontbutton.cpp
@@ -0,0 +1,97 @@
+/*
+ * Authors:
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gtkmm.h>
+#include "ui/widget/registered-widget.h"
+#include "live_effects/parameter/fontbutton.h"
+#include "live_effects/effect.h"
+#include "ui/widget/font-button.h"
+#include "svg/svg.h"
+#include "svg/stringstream.h"
+#include "verbs.h"
+
+#include <glibmm/i18n.h>
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+FontButtonParam::FontButtonParam( const Glib::ustring& label, const Glib::ustring& tip,
+ const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
+ Effect* effect, const Glib::ustring default_value )
+ : Parameter(label, tip, key, wr, effect),
+ value(default_value),
+ defvalue(default_value)
+{
+}
+
+void
+FontButtonParam::param_set_default()
+{
+ param_setValue(defvalue);
+}
+
+void
+FontButtonParam::param_update_default(const gchar * default_value)
+{
+ defvalue = (Glib::ustring)strdup(default_value);
+}
+
+bool
+FontButtonParam::param_readSVGValue(const gchar * strvalue)
+{
+ Inkscape::SVGOStringStream os;
+ os << strvalue;
+ param_setValue((Glib::ustring)os.str());
+ return true;
+}
+
+gchar *
+FontButtonParam::param_getSVGValue() const
+{
+ return g_strdup(value.c_str());
+}
+
+Gtk::Widget *
+FontButtonParam::param_newWidget()
+{
+ Inkscape::UI::Widget::RegisteredFontButton * fontbuttonwdg = Gtk::manage(
+ new Inkscape::UI::Widget::RegisteredFontButton( param_label,
+ param_tooltip,
+ param_key,
+ *param_wr,
+ param_effect->getRepr(),
+ param_effect->getSPDoc() ) );
+ Glib::ustring fontspec = param_getSVGValue();
+ fontbuttonwdg->setValue( fontspec);
+ fontbuttonwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change font button parameter"));
+ return dynamic_cast<Gtk::Widget *> (fontbuttonwdg);
+}
+
+void
+FontButtonParam::param_setValue(const Glib::ustring newvalue)
+{
+ if (value != newvalue) {
+ param_effect->upd_params = true;
+ }
+ value = newvalue;
+}
+
+
+} /* namespace LivePathEffect */
+
+} /* 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 :
diff --git a/src/live_effects/parameter/fontbutton.h b/src/live_effects/parameter/fontbutton.h
new file mode 100644
index 000000000..60e1aa46e
--- /dev/null
+++ b/src/live_effects/parameter/fontbutton.h
@@ -0,0 +1,61 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_FONT_H
+#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_FONT_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ *
+ * Authors:
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+#include <glib.h>
+#include "live_effects/parameter/parameter.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class FontButtonParam : public Parameter {
+public:
+ FontButtonParam( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect,
+ const Glib::ustring default_value = "Sans 10");
+ virtual ~FontButtonParam() {}
+
+ virtual Gtk::Widget * param_newWidget();
+ virtual bool param_readSVGValue(const gchar * strvalue);
+ void param_update_default(const gchar * default_value);
+ virtual gchar * param_getSVGValue() const;
+
+ void param_setValue(Glib::ustring newvalue);
+
+ virtual void param_set_default();
+
+ const Glib::ustring get_value() const { return defvalue; };
+
+private:
+ FontButtonParam(const FontButtonParam&);
+ FontButtonParam& operator=(const FontButtonParam&);
+ Glib::ustring value;
+ Glib::ustring defvalue;
+
+};
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
+
+/*
+ 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 :
diff --git a/src/live_effects/parameter/hidden.cpp b/src/live_effects/parameter/hidden.cpp
new file mode 100644
index 000000000..e8c55ebd3
--- /dev/null
+++ b/src/live_effects/parameter/hidden.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) jabiertxof 2017 <jabier.arraiza@marker.es>
+ * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com>
+ *
+ * Authors:
+ * Jabiertxof
+ * Maximilian Albert
+ * Johan Engelen
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+
+#include "live_effects/parameter/hidden.h"
+#include "live_effects/effect.h"
+#include "svg/svg.h"
+#include "svg/stringstream.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+HiddenParam::HiddenParam( const Glib::ustring& label, const Glib::ustring& tip,
+ const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
+ Effect* effect, const Glib::ustring default_value, bool is_visible)
+ : Parameter(label, tip, key, wr, effect),
+ value(default_value),
+ defvalue(default_value)
+{
+ param_widget_is_visible(is_visible);
+}
+
+void
+HiddenParam::param_set_default()
+{
+ param_setValue(defvalue);
+}
+
+void
+HiddenParam::param_update_default(const gchar * default_value)
+{
+ defvalue = (Glib::ustring)default_value;
+}
+
+
+bool
+HiddenParam::param_readSVGValue(const gchar * strvalue)
+{
+ param_setValue(strvalue);
+ return true;
+}
+
+gchar *
+HiddenParam::param_getSVGValue() const
+{
+ Inkscape::SVGOStringStream os;
+ os << value;
+ gchar * str = g_strdup(os.str().c_str());
+ return str;
+}
+
+Gtk::Widget *
+HiddenParam::param_newWidget()
+{
+ return NULL;
+}
+
+void
+HiddenParam::param_setValue(const Glib::ustring newvalue, bool write)
+{
+ value = newvalue;
+ if (write) {
+ param_write_to_repr(value.c_str());
+ }
+}
+
+} /* namespace LivePathEffect */
+
+} /* 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 :
diff --git a/src/live_effects/parameter/hidden.h b/src/live_effects/parameter/hidden.h
new file mode 100644
index 000000000..c3fba5575
--- /dev/null
+++ b/src/live_effects/parameter/hidden.h
@@ -0,0 +1,69 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_HIDDEN_H
+#define INKSCAPE_LIVEPATHEFFECT_HIDDEN_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ *
+ * Authors:
+ * Jabiertxof
+ * Maximilian Albert
+ * Johan Engelen
+ *
+ * Copyright (C) jabiertxof 2017 <jabier.arraiza@marker.es>
+ * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/parameter/parameter.h"
+
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class HiddenParam : public Parameter {
+public:
+ HiddenParam( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect,
+ const Glib::ustring default_value = "",
+ bool widget_is_visible = false);
+ virtual ~HiddenParam() {}
+
+ virtual Gtk::Widget * param_newWidget();
+
+ virtual bool param_readSVGValue(const gchar * strvalue);
+ virtual gchar * param_getSVGValue() const;
+
+ void param_setValue(Glib::ustring newvalue, bool write = false);
+ virtual void param_set_default();
+ virtual void param_update_default(const gchar * default_value);
+
+ const Glib::ustring get_value() const { return value; };
+
+private:
+ HiddenParam(const HiddenParam&);
+ HiddenParam& operator=(const HiddenParam&);
+ Glib::ustring value;
+ Glib::ustring defvalue;
+};
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
+
+/*
+ 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 :
diff --git a/src/live_effects/parameter/item-reference.cpp b/src/live_effects/parameter/item-reference.cpp
new file mode 100644
index 000000000..a775d93b7
--- /dev/null
+++ b/src/live_effects/parameter/item-reference.cpp
@@ -0,0 +1,44 @@
+/*
+ * The reference corresponding to href of LPE Item parameter.
+ *
+ * Copyright (C) 2008 Johan Engelen
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information.
+ */
+
+#include "live_effects/parameter/item-reference.h"
+
+#include "sp-shape.h"
+#include "sp-text.h"
+#include "sp-item-group.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+bool ItemReference::_acceptObject(SPObject * const obj) const
+{
+ if (SP_IS_SHAPE(obj) || SP_IS_TEXT(obj) || SP_IS_GROUP(obj)) {
+ /* Refuse references to lpeobject */
+ if (obj == getOwner()) {
+ return false;
+ }
+ // TODO: check whether the referred item has this LPE applied, if so: deny deny deny!
+ return URIReference::_acceptObject(obj);
+ } else {
+ return false;
+ }
+}
+
+} // namespace LivePathEffect
+} // 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 :
diff --git a/src/live_effects/parameter/item-reference.h b/src/live_effects/parameter/item-reference.h
new file mode 100644
index 000000000..91231455a
--- /dev/null
+++ b/src/live_effects/parameter/item-reference.h
@@ -0,0 +1,56 @@
+#ifndef SEEN_LPE_ITEM_REFERENCE_H
+#define SEEN_LPE_ITEM_REFERENCE_H
+
+/*
+ * Copyright (C) 2008-2012 Authors
+ * Authors: Johan Engelen
+ * Abhishek Sharma
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information.
+ */
+
+#include <uri-references.h>
+
+class SPItem;
+namespace Inkscape {
+namespace XML { class Node; }
+
+namespace LivePathEffect {
+
+/**
+ * The reference corresponding to href of LPE ItemParam.
+ */
+class ItemReference : public Inkscape::URIReference {
+public:
+ ItemReference(SPObject *owner) : URIReference(owner) {}
+
+ SPItem *getObject() const {
+ return (SPItem *)URIReference::getObject();
+ }
+
+protected:
+ virtual bool _acceptObject(SPObject * const obj) const;
+
+private:
+ ItemReference(const ItemReference&);
+ ItemReference& operator=(const ItemReference&);
+};
+
+} // namespace LivePathEffect
+
+} // namespace Inkscape
+
+
+
+#endif /* !SEEN_LPE_PATH_REFERENCE_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 :
diff --git a/src/live_effects/parameter/item.cpp b/src/live_effects/parameter/item.cpp
new file mode 100644
index 000000000..7b40f4540
--- /dev/null
+++ b/src/live_effects/parameter/item.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ * Abhishek Sharma
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/parameter/item.h"
+
+#include <glibmm/i18n.h>
+
+#include <gtkmm/button.h>
+#include <gtkmm/label.h>
+
+#include "bad-uri-exception.h"
+#include "ui/widget/point.h"
+
+#include "live_effects/effect.h"
+#include "svg/svg.h"
+
+#include "widgets/icon.h"
+#include "selection-chemistry.h"
+#include "xml/repr.h"
+#include "desktop.h"
+#include "inkscape.h"
+#include "message-stack.h"
+
+// clipboard support
+#include "ui/clipboard.h"
+// required for linking to other paths
+#include "uri.h"
+
+#include "ui/icon-names.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+ItemParam::ItemParam( const Glib::ustring& label, const Glib::ustring& tip,
+ const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
+ Effect* effect, const gchar * default_value)
+ : Parameter(label, tip, key, wr, effect),
+ changed(true),
+ href(NULL),
+ ref( (SPObject*)effect->getLPEObj() )
+{
+ defvalue = g_strdup(default_value);
+ ref_changed_connection = ref.changedSignal().connect(sigc::mem_fun(*this, &ItemParam::ref_changed));
+}
+
+ItemParam::~ItemParam()
+{
+ remove_link();
+ g_free(defvalue);
+}
+
+void
+ItemParam::param_set_default()
+{
+ param_readSVGValue(defvalue);
+}
+
+void
+ItemParam::param_update_default(const gchar * default_value){
+ defvalue = strdup(default_value);
+}
+
+void
+ItemParam::param_set_and_write_default()
+{
+ param_write_to_repr(defvalue);
+}
+
+bool
+ItemParam::param_readSVGValue(const gchar * strvalue)
+{
+ if (strvalue) {
+ remove_link();
+ if (strvalue[0] == '#') {
+ if (href)
+ g_free(href);
+ href = g_strdup(strvalue);
+ try {
+ ref.attach(Inkscape::URI(href));
+ //lp:1299948
+ SPItem* i = ref.getObject();
+ if (i) {
+ linked_modified_callback(i, SP_OBJECT_MODIFIED_FLAG);
+ } // else: document still processing new events. Repr of the linked object not created yet.
+ } catch (Inkscape::BadURIException &e) {
+ g_warning("%s", e.what());
+ ref.detach();
+ }
+ }
+ emit_changed();
+ return true;
+ }
+
+ return false;
+}
+
+gchar *
+ItemParam::param_getSVGValue() const
+{
+ return g_strdup(href);
+}
+
+Gtk::Widget *
+ItemParam::param_newWidget()
+{
+ Gtk::HBox * _widget = Gtk::manage(new Gtk::HBox());
+ Gtk::Widget* pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Button * pButton = Gtk::manage(new Gtk::Button());
+ Gtk::Label* pLabel = Gtk::manage(new Gtk::Label(param_label));
+ static_cast<Gtk::HBox*>(_widget)->pack_start(*pLabel, true, true);
+ pLabel->set_tooltip_text(param_tooltip);
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &ItemParam::on_link_button_click));
+ static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
+ pButton->set_tooltip_text(_("Link to item on clipboard"));
+
+ static_cast<Gtk::HBox*>(_widget)->show_all_children();
+
+ return dynamic_cast<Gtk::Widget *> (_widget);
+}
+
+void
+ItemParam::emit_changed()
+{
+ changed = true;
+ signal_item_changed.emit();
+}
+
+
+void
+ItemParam::addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+}
+
+
+void
+ItemParam::start_listening(SPObject * to)
+{
+ if ( to == NULL ) {
+ return;
+ }
+ linked_delete_connection = to->connectDelete(sigc::mem_fun(*this, &ItemParam::linked_delete));
+ linked_modified_connection = to->connectModified(sigc::mem_fun(*this, &ItemParam::linked_modified));
+ if (SP_IS_ITEM(to)) {
+ linked_transformed_connection = SP_ITEM(to)->connectTransformed(sigc::mem_fun(*this, &ItemParam::linked_transformed));
+ }
+ linked_modified(to, SP_OBJECT_MODIFIED_FLAG); // simulate linked_modified signal, so that path data is updated
+}
+
+void
+ItemParam::quit_listening(void)
+{
+ linked_modified_connection.disconnect();
+ linked_delete_connection.disconnect();
+ linked_transformed_connection.disconnect();
+}
+
+void
+ItemParam::ref_changed(SPObject */*old_ref*/, SPObject *new_ref)
+{
+ quit_listening();
+ if ( new_ref ) {
+ start_listening(new_ref);
+ }
+}
+
+void
+ItemParam::remove_link()
+{
+ if (href) {
+ ref.detach();
+ g_free(href);
+ href = NULL;
+ }
+}
+
+void
+ItemParam::linked_delete(SPObject */*deleted*/)
+{
+ quit_listening();
+ remove_link();
+}
+
+void ItemParam::linked_modified(SPObject *linked_obj, guint flags)
+{
+ linked_modified_callback(linked_obj, flags);
+}
+
+void ItemParam::linked_transformed(Geom::Affine const *rel_transf, SPItem *moved_item)
+{
+ linked_transformed_callback(rel_transf, moved_item);
+}
+
+void
+ItemParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*/)
+{
+ emit_changed();
+ SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void
+ItemParam::on_link_button_click()
+{
+ Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
+ const gchar * iid = cm->getFirstObjectID();
+ if (!iid) {
+ return;
+ }
+
+ Glib::ustring itemid(iid);
+
+ if (itemid.empty()) {
+ return;
+ }
+
+ // add '#' at start to make it an uri.
+ itemid.insert(itemid.begin(), '#');
+ if ( href && strcmp(itemid.c_str(), href) == 0 ) {
+ // no change, do nothing
+ return;
+ } else {
+ // TODO:
+ // check if id really exists in document, or only in clipboard document: if only in clipboard then invalid
+ // check if linking to object to which LPE is applied (maybe delegated to PathReference
+
+ param_write_to_repr(itemid.c_str());
+ DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ _("Link item parameter to path"));
+ }
+}
+
+} /* namespace LivePathEffect */
+
+} /* 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 :
diff --git a/src/live_effects/parameter/item.h b/src/live_effects/parameter/item.h
new file mode 100644
index 000000000..89c32f9bd
--- /dev/null
+++ b/src/live_effects/parameter/item.h
@@ -0,0 +1,80 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ITEM_H
+#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ITEM_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ *
+* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+
+
+#include "live_effects/parameter/parameter.h"
+#include "live_effects/parameter/item-reference.h"
+#include <stddef.h>
+#include <sigc++/sigc++.h>
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class ItemParam : public Parameter {
+public:
+ ItemParam ( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect,
+ const gchar * default_value = "");
+ virtual ~ItemParam();
+ virtual Gtk::Widget * param_newWidget();
+
+ virtual bool param_readSVGValue(const gchar * strvalue);
+ virtual gchar * param_getSVGValue() const;
+
+ virtual void param_set_default();
+ virtual void param_update_default(const gchar * default_value);
+ void param_set_and_write_default();
+ virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector<Geom::PathVector> &hp_vec);
+
+ sigc::signal <void> signal_item_pasted;
+ sigc::signal <void> signal_item_changed;
+ bool changed; /* this gets set whenever the path is changed (this is set to true, and then the signal_item_changed signal is emitted).
+ * the user must set it back to false if she wants to use it sensibly */
+protected:
+
+ gchar * href; // contains link to other object, e.g. "#path2428", NULL if ItemParam contains pathdata itself
+ ItemReference ref;
+ sigc::connection ref_changed_connection;
+ sigc::connection linked_delete_connection;
+ sigc::connection linked_modified_connection;
+ sigc::connection linked_transformed_connection;
+ void ref_changed(SPObject *old_ref, SPObject *new_ref);
+ void remove_link();
+ void start_listening(SPObject * to);
+ void quit_listening(void);
+ void linked_delete(SPObject *deleted);
+ void linked_modified(SPObject *linked_obj, guint flags);
+ void linked_transformed(Geom::Affine const *rel_transf, SPItem *moved_item);
+ virtual void linked_modified_callback(SPObject *linked_obj, guint flags);
+ virtual void linked_transformed_callback(Geom::Affine const * /*rel_transf*/, SPItem * /*moved_item*/) {};
+ void on_link_button_click();
+
+ void emit_changed();
+
+ gchar * defvalue;
+
+private:
+ ItemParam(const ItemParam&);
+ ItemParam& operator=(const ItemParam&);
+};
+
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
diff --git a/src/live_effects/parameter/originalitem.cpp b/src/live_effects/parameter/originalitem.cpp
new file mode 100644
index 000000000..053062128
--- /dev/null
+++ b/src/live_effects/parameter/originalitem.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) Johan Engelen 2012 <j.b.c.engelen@alumnus.utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gtkmm/box.h>
+#include "live_effects/parameter/originalitem.h"
+
+#include "widgets/icon.h"
+#include <glibmm/i18n.h>
+#include <gtkmm/button.h>
+#include <gtkmm/label.h>
+
+#include "uri.h"
+#include "sp-shape.h"
+#include "sp-text.h"
+#include "display/curve.h"
+#include "live_effects/effect.h"
+
+#include "inkscape.h"
+#include "desktop.h"
+#include "selection.h"
+#include "ui/icon-names.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+OriginalItemParam::OriginalItemParam( const Glib::ustring& label, const Glib::ustring& tip,
+ const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
+ Effect* effect)
+ : ItemParam(label, tip, key, wr, effect, "")
+{
+}
+
+OriginalItemParam::~OriginalItemParam()
+{
+
+}
+
+Gtk::Widget *
+OriginalItemParam::param_newWidget()
+{
+ Gtk::HBox *_widget = Gtk::manage(new Gtk::HBox());
+
+ { // Label
+ Gtk::Label *pLabel = Gtk::manage(new Gtk::Label(param_label));
+ static_cast<Gtk::HBox*>(_widget)->pack_start(*pLabel, true, true);
+ pLabel->set_tooltip_text(param_tooltip);
+ }
+
+ { // Paste item to link button
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalItemParam::on_link_button_click));
+ static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
+ pButton->set_tooltip_text(_("Link to item"));
+ }
+
+ { // Select original button
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("edit-select-original", Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalItemParam::on_select_original_button_click));
+ static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
+ pButton->set_tooltip_text(_("Select original"));
+ }
+
+ static_cast<Gtk::HBox*>(_widget)->show_all_children();
+
+ return dynamic_cast<Gtk::Widget *> (_widget);
+}
+
+void
+OriginalItemParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*/)
+{
+ if (!inverse) {
+ emit_changed();
+ SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+}
+
+void
+OriginalItemParam::linked_transformed_callback(Geom::Affine const * /*rel_transf*/, SPItem * /*moved_item*/)
+{
+/** \todo find good way to compensate for referenced item transform, like done for normal clones.
+ * See sp-use.cpp: sp_use_move_compensate */
+}
+
+
+void
+OriginalItemParam::on_select_original_button_click()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPItem *original = ref.getObject();
+ if (desktop == NULL || original == NULL) {
+ return;
+ }
+ Inkscape::Selection *selection = desktop->getSelection();
+ selection->clear();
+ selection->set(original);
+}
+
+} /* namespace LivePathEffect */
+
+} /* 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 :
diff --git a/src/live_effects/parameter/originalitem.h b/src/live_effects/parameter/originalitem.h
new file mode 100644
index 000000000..58d04e05a
--- /dev/null
+++ b/src/live_effects/parameter/originalitem.h
@@ -0,0 +1,49 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINAL_ITEM_H
+#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINAL_ITEM_H
+
+/*
+ * Inkscape::LiveItemEffectParameters
+ *
+* Copyright (C) Johan Engelen 2012 <j.b.c.engelen@alumnus.utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/parameter/item.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class OriginalItemParam: public ItemParam {
+public:
+ OriginalItemParam ( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect);
+ virtual ~OriginalItemParam();
+ void setInverse(bool inversed) { inverse = inversed; }
+ bool linksToItem() const { return (href != NULL); }
+ SPItem * getObject() const { return ref.getObject(); }
+
+ virtual Gtk::Widget * param_newWidget();
+
+protected:
+ virtual void linked_modified_callback(SPObject *linked_obj, guint flags);
+ virtual void linked_transformed_callback(Geom::Affine const *rel_transf, SPItem *moved_item);
+
+ void on_select_original_button_click();
+
+private:
+ bool inverse;
+ OriginalItemParam(const OriginalItemParam&);
+ OriginalItemParam& operator=(const OriginalItemParam&);
+};
+
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
diff --git a/src/live_effects/parameter/originalpath.cpp b/src/live_effects/parameter/originalpath.cpp
index 2741461be..1e78f7fe1 100644
--- a/src/live_effects/parameter/originalpath.cpp
+++ b/src/live_effects/parameter/originalpath.cpp
@@ -56,7 +56,7 @@ OriginalPathParam::param_newWidget()
}
{ // Paste path to link button
- Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) );
Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
pButton->set_relief(Gtk::RELIEF_NONE);
pIcon->show();
@@ -89,7 +89,7 @@ OriginalPathParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*
{
SPCurve *curve = NULL;
if (SP_IS_SHAPE(linked_obj)) {
- curve = SP_SHAPE(linked_obj)->getCurveBeforeLPE();
+ curve = SP_SHAPE(linked_obj)->getCurve();
}
if (SP_IS_TEXT(linked_obj)) {
curve = SP_TEXT(linked_obj)->getNormalizedBpath();
diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp
index 4ee068ebf..693821ed2 100644
--- a/src/live_effects/parameter/originalpatharray.cpp
+++ b/src/live_effects/parameter/originalpatharray.cpp
@@ -144,7 +144,7 @@ Gtk::Widget* OriginalPathArrayParam::param_newWidget()
{ // Paste path to link button
- Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("gtk-stock", Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("edit-clone", Inkscape::ICON_SIZE_BUTTON) );
Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
pButton->set_relief(Gtk::RELIEF_NONE);
pIcon->show();
@@ -386,7 +386,7 @@ void OriginalPathArrayParam::setPathVector(SPObject *linked_obj, guint /*flags*/
}
SPCurve *curve = NULL;
if (SP_IS_SHAPE(linked_obj)) {
- curve = SP_SHAPE(linked_obj)->getCurveBeforeLPE();
+ curve = SP_SHAPE(linked_obj)->getCurve();
}
if (SP_IS_TEXT(linked_obj)) {
curve = SP_TEXT(linked_obj)->getNormalizedBpath();
diff --git a/src/live_effects/parameter/originalpatharray.h b/src/live_effects/parameter/originalpatharray.h
index 296c0f7f7..fe9371644 100644
--- a/src/live_effects/parameter/originalpatharray.h
+++ b/src/live_effects/parameter/originalpatharray.h
@@ -65,12 +65,11 @@ public:
virtual bool param_readSVGValue(const gchar * strvalue);
virtual gchar * param_getSVGValue() const;
virtual void param_set_default();
-
+ virtual void param_update_default(const gchar * default_value){};
/** Disable the canvas indicators of parent class by overriding this method */
virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {};
/** Disable the canvas indicators of parent class by overriding this method */
virtual void addCanvasIndicators(SPLPEItem const* /*lpeitem*/, std::vector<Geom::PathVector> & /*hp_vec*/) {};
-
std::vector<PathAndDirection*> _vector;
protected:
diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp
index d4e213948..2f73488aa 100644
--- a/src/live_effects/parameter/parameter.cpp
+++ b/src/live_effects/parameter/parameter.cpp
@@ -4,11 +4,9 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "ui/widget/registered-widget.h"
-#include <glibmm/i18n.h>
-#include "live_effects/parameter/parameter.h"
#include "live_effects/effect.h"
+#include "live_effects/parameter/parameter.h"
#include "svg/svg.h"
#include "xml/repr.h"
@@ -16,6 +14,8 @@
#include "verbs.h"
+#include <glibmm/i18n.h>
+
#define noLPEREALPARAM_DEBUG
namespace Inkscape {
@@ -39,6 +39,7 @@ Parameter::Parameter( const Glib::ustring& label, const Glib::ustring& tip,
void
Parameter::param_write_to_repr(const char * svgd)
{
+ param_effect->upd_params = true;
param_effect->getRepr()->setAttribute(param_key.c_str(), svgd);
}
@@ -54,7 +55,7 @@ void Parameter::write_to_SVG(void)
*/
ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip,
const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
- Effect* effect, gdouble default_value, bool no_widget)
+ Effect* effect, gdouble default_value)
: Parameter(label, tip, key, wr, effect),
value(default_value),
min(-SCALARPARAM_G_MAXDOUBLE),
@@ -65,8 +66,7 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip,
inc_step(0.1),
inc_page(1),
add_slider(false),
- overwrite_widget(false),
- hide_widget(no_widget)
+ _set_undo(true)
{
}
@@ -101,9 +101,28 @@ ScalarParam::param_set_default()
param_set_value(defvalue);
}
+void
+ScalarParam::param_update_default(gdouble default_value)
+{
+ defvalue = default_value;
+}
+
+void
+ScalarParam::param_update_default(const gchar * default_value)
+{
+ double newval;
+ unsigned int success = sp_svg_number_read_d(default_value, &newval);
+ if (success == 1) {
+ param_update_default(newval);
+ }
+}
+
void
ScalarParam::param_set_value(gdouble val)
{
+ if (value != val) {
+ param_effect->upd_params = true;
+ }
value = val;
if (integer)
value = round(value);
@@ -121,7 +140,6 @@ ScalarParam::param_set_range(gdouble min, gdouble max)
// Once again, in gtk2, this is not a problem. But in gtk3,
// widgets get allocated the amount of size they ask for,
// leading to excessively long widgets.
-
if (min >= -SCALARPARAM_G_MAXDOUBLE) {
this->min = min;
} else {
@@ -130,9 +148,8 @@ ScalarParam::param_set_range(gdouble min, gdouble max)
if (max <= SCALARPARAM_G_MAXDOUBLE) {
this->max = max;
} else {
- this->max = SCALARPARAM_G_MAXDOUBLE;
+ this->max = SCALARPARAM_G_MAXDOUBLE;
}
-
param_set_value(value); // reset value to see whether it is in ranges
}
@@ -146,15 +163,15 @@ ScalarParam::param_make_integer(bool yes)
}
void
-ScalarParam::param_overwrite_widget(bool overwrite_widget)
+ScalarParam::param_set_undo(bool set_undo)
{
- this->overwrite_widget = overwrite_widget;
+ _set_undo = set_undo;
}
Gtk::Widget *
ScalarParam::param_newWidget()
{
- if(!hide_widget){
+ if(widget_is_visible){
Inkscape::UI::Widget::RegisteredScalar *rsu = Gtk::manage( new Inkscape::UI::Widget::RegisteredScalar(
param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) );
@@ -166,7 +183,7 @@ ScalarParam::param_newWidget()
if (add_slider) {
rsu->addSlider();
}
- if(!overwrite_widget){
+ if(_set_undo){
rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
}
return dynamic_cast<Gtk::Widget *> (rsu);
diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h
index 0ef28650a..7ab7e30dd 100644
--- a/src/live_effects/parameter/parameter.h
+++ b/src/live_effects/parameter/parameter.h
@@ -12,6 +12,7 @@
#include <glibmm/ustring.h>
#include <2geom/forward.h>
#include <2geom/pathvector.h>
+#include "ui/widget/registered-widget.h"
// In gtk2, this wasn't an issue; we could toss around
// G_MAXDOUBLE and not worry about size allocations. But
@@ -56,10 +57,11 @@ public:
virtual bool param_readSVGValue(const gchar * strvalue) = 0; // returns true if new value is valid / accepted.
virtual gchar * param_getSVGValue() const = 0;
+ virtual void param_widget_is_visible(bool is_visible) {widget_is_visible = is_visible;}
void write_to_SVG();
virtual void param_set_default() = 0;
-
+ virtual void param_update_default(const gchar * default_value) = 0;
// This creates a new widget (newed with Gtk::manage(new ...);)
virtual Gtk::Widget * param_newWidget() = 0;
@@ -67,7 +69,7 @@ public:
// overload these for your particular parameter to make it provide knotholder handles or canvas helperpaths
virtual bool providesKnotHolderEntities() const { return false; }
- virtual void addKnotHolderEntities(KnotHolder */*knotholder*/, SPDesktop */*desktop*/, SPItem */*item*/) {};
+ virtual void addKnotHolderEntities(KnotHolder */*knotholder*/, SPItem */*item*/) {};
virtual void addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/) {};
virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {};
@@ -76,6 +78,7 @@ public:
virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/) {};
Glib::ustring param_key;
+ Glib::ustring param_tooltip;
Inkscape::UI::Widget::Registry * param_wr;
Glib::ustring param_label;
@@ -83,7 +86,6 @@ public:
bool widget_is_visible;
protected:
- Glib::ustring param_tooltip;
Effect* param_effect;
@@ -102,23 +104,24 @@ public:
const Glib::ustring& key,
Inkscape::UI::Widget::Registry* wr,
Effect* effect,
- gdouble default_value = 1.0,
- bool no_widget = false);
+ gdouble default_value = 1.0);
virtual ~ScalarParam();
virtual bool param_readSVGValue(const gchar * strvalue);
virtual gchar * param_getSVGValue() const;
virtual void param_set_default();
+ void param_update_default(gdouble default_value);
+ virtual void param_update_default(const gchar * default_value);
void param_set_value(gdouble val);
void param_make_integer(bool yes = true);
void param_set_range(gdouble min, gdouble max);
void param_set_digits(unsigned digits);
void param_set_increments(double step, double page);
-
void addSlider(bool add_slider_widget) { add_slider = add_slider_widget; };
-
- void param_overwrite_widget(bool overwrite_widget);
+ double param_get_max() { return max; };
+ double param_get_min() { return min; };
+ void param_set_undo(bool set_undo);
virtual Gtk::Widget * param_newWidget();
inline operator gdouble() const { return value; };
@@ -133,8 +136,7 @@ protected:
double inc_step;
double inc_page;
bool add_slider;
- bool overwrite_widget;
- bool hide_widget;
+ bool _set_undo;
private:
ScalarParam(const ScalarParam&);
diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp
index 7ea1d465c..54f5d93e8 100644
--- a/src/live_effects/parameter/path.cpp
+++ b/src/live_effects/parameter/path.cpp
@@ -5,10 +5,16 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "ui/widget/point.h"
+#include "live_effects/parameter/path.h"
+
#include <glibmm/i18n.h>
-#include "live_effects/parameter/path.h"
+#include <gtkmm/button.h>
+#include <gtkmm/label.h>
+
+#include "bad-uri-exception.h"
+#include "ui/widget/point.h"
+
#include "live_effects/effect.h"
#include "svg/svg.h"
#include <2geom/svg-path-parser.h>
@@ -17,7 +23,6 @@
#include <2geom/d2.h>
#include "widgets/icon.h"
-#include <gtk/gtk.h>
#include "selection-chemistry.h"
#include "xml/repr.h"
#include "desktop.h"
@@ -44,8 +49,6 @@
#include "ui/tool/multi-path-manipulator.h"
#include "ui/tool/shape-record.h"
-#include <gtkmm/button.h>
-#include <gtkmm/label.h>
#include "ui/icon-names.h"
namespace Inkscape {
@@ -66,14 +69,31 @@ PathParam::PathParam( const Glib::ustring& label, const Glib::ustring& tip,
defvalue = g_strdup(default_value);
param_readSVGValue(defvalue);
oncanvas_editable = true;
-
+ _edit_button = true;
+ _copy_button = true;
+ _paste_button = true;
+ _link_button = true;
ref_changed_connection = ref.changedSignal().connect(sigc::mem_fun(*this, &PathParam::ref_changed));
}
PathParam::~PathParam()
{
remove_link();
-
+ using namespace Inkscape::UI;
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop) {
+ if (tools_isactive(desktop, TOOLS_NODES)) {
+ SPItem * item = SP_ACTIVE_DESKTOP->getSelection()->singleItem();
+ if (item != NULL) {
+ Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(desktop->event_context);
+ std::set<ShapeRecord> shapes;
+ ShapeRecord r;
+ r.item = item;
+ shapes.insert(r);
+ nt->_multipath->setItems(shapes);
+ }
+ }
+ }
g_free(defvalue);
}
@@ -150,6 +170,15 @@ PathParam::param_getSVGValue() const
}
}
+void
+PathParam::set_buttons(bool edit_button, bool copy_button, bool paste_button, bool link_button)
+{
+ _edit_button = edit_button;
+ _copy_button = copy_button;
+ _paste_button = paste_button;
+ _link_button = link_button;
+}
+
Gtk::Widget *
PathParam::param_newWidget()
{
@@ -158,47 +187,55 @@ PathParam::param_newWidget()
Gtk::Label* pLabel = Gtk::manage(new Gtk::Label(param_label));
static_cast<Gtk::HBox*>(_widget)->pack_start(*pLabel, true, true);
pLabel->set_tooltip_text(param_tooltip);
-
- Gtk::Widget* pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("tool-node-editor"), Inkscape::ICON_SIZE_BUTTON) );
- Gtk::Button * pButton = Gtk::manage(new Gtk::Button());
- pButton->set_relief(Gtk::RELIEF_NONE);
- pIcon->show();
- pButton->add(*pIcon);
- pButton->show();
- pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_edit_button_click));
- static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
- pButton->set_tooltip_text(_("Edit on-canvas"));
-
- pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-copy"), Inkscape::ICON_SIZE_BUTTON) );
- pButton = Gtk::manage(new Gtk::Button());
- pButton->set_relief(Gtk::RELIEF_NONE);
- pIcon->show();
- pButton->add(*pIcon);
- pButton->show();
- pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_copy_button_click));
- static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
- pButton->set_tooltip_text(_("Copy path"));
-
- pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) );
- pButton = Gtk::manage(new Gtk::Button());
- pButton->set_relief(Gtk::RELIEF_NONE);
- pIcon->show();
- pButton->add(*pIcon);
- pButton->show();
- pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_paste_button_click));
- static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
- pButton->set_tooltip_text(_("Paste path"));
-
- pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) );
- pButton = Gtk::manage(new Gtk::Button());
- pButton->set_relief(Gtk::RELIEF_NONE);
- pIcon->show();
- pButton->add(*pIcon);
- pButton->show();
- pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_link_button_click));
- static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
- pButton->set_tooltip_text(_("Link to path on clipboard"));
-
+ Gtk::Widget * pIcon = NULL;
+ Gtk::Button * pButton = NULL;
+ if (_edit_button) {
+ pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("tool-node-editor"), Inkscape::ICON_SIZE_BUTTON) );
+ pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_edit_button_click));
+ static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
+ pButton->set_tooltip_text(_("Edit on-canvas"));
+ }
+
+ if (_copy_button) {
+ pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-copy"), Inkscape::ICON_SIZE_BUTTON) );
+ pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_copy_button_click));
+ static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
+ pButton->set_tooltip_text(_("Copy path"));
+ }
+
+ if (_paste_button) {
+ pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) );
+ pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_paste_button_click));
+ static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
+ pButton->set_tooltip_text(_("Paste path"));
+ }
+ if (_link_button) {
+ pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) );
+ pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_link_button_click));
+ static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true);
+ pButton->set_tooltip_text(_("Link to path on clipboard"));
+ }
+
static_cast<Gtk::HBox*>(_widget)->show_all_children();
return dynamic_cast<Gtk::Widget *> (_widget);
@@ -207,6 +244,9 @@ PathParam::param_newWidget()
void
PathParam::param_editOncanvas(SPItem *item, SPDesktop * dt)
{
+ SPDocument *document = dt->getDocument();
+ bool saved = DocumentUndo::getUndoSensitive(document);
+ DocumentUndo::setUndoSensitive(document, false);
using namespace Inkscape::UI;
// TODO remove the tools_switch atrocity.
@@ -223,11 +263,17 @@ PathParam::param_editOncanvas(SPItem *item, SPDesktop * dt)
if (!href) {
r.item = reinterpret_cast<SPItem*>(param_effect->getLPEObj());
r.lpe_key = param_key;
+ Geom::PathVector stored_pv = _pathvector;
+ param_write_to_repr("M0,0 L1,0");
+ gchar *svgd = sp_svg_write_path(stored_pv);
+ param_write_to_repr(svgd);
+ g_free(svgd);
} else {
r.item = ref.getObject();
}
shapes.insert(r);
nt->_multipath->setItems(shapes);
+ DocumentUndo::setUndoSensitive(document, saved);
}
void
@@ -414,6 +460,10 @@ PathParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*/)
SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG);
}
+void
+PathParam::param_update_default(const gchar * default_value){
+ defvalue = strdup(default_value);
+}
/* CALLBACK FUNCTIONS FOR THE BUTTONS */
void
diff --git a/src/live_effects/parameter/path.h b/src/live_effects/parameter/path.h
index d2dddbe97..ff5e4f1b8 100644
--- a/src/live_effects/parameter/path.h
+++ b/src/live_effects/parameter/path.h
@@ -40,10 +40,11 @@ public:
virtual gchar * param_getSVGValue() const;
virtual void param_set_default();
+ virtual void param_update_default(const gchar * default_value);
void param_set_and_write_default();
void set_new_value (Geom::PathVector const &newpath, bool write_to_svg);
void set_new_value (Geom::Piecewise<Geom::D2<Geom::SBasis> > const &newpath, bool write_to_svg);
-
+ void set_buttons(bool edit_button, bool copy_button, bool paste_button, bool link_button);
virtual void param_editOncanvas(SPItem * item, SPDesktop * dt);
virtual void param_setup_nodepath(Inkscape::NodePath::Path *np);
virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector<Geom::PathVector> &hp_vec);
@@ -90,6 +91,10 @@ protected:
gchar * defvalue;
private:
+ bool _edit_button;
+ bool _copy_button;
+ bool _paste_button;
+ bool _link_button;
PathParam(const PathParam&);
PathParam& operator=(const PathParam&);
};
diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp
index ca3471b29..4ca88a6b8 100644
--- a/src/live_effects/parameter/point.cpp
+++ b/src/live_effects/parameter/point.cpp
@@ -4,7 +4,6 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "ui/widget/registered-widget.h"
#include "live_effects/parameter/point.h"
#include "live_effects/effect.h"
#include "svg/svg.h"
@@ -16,9 +15,6 @@
#include "knotholder.h"
#include <glibmm/i18n.h>
-// needed for on-canvas editting:
-#include "desktop.h"
-
namespace Inkscape {
namespace LivePathEffect {
@@ -62,9 +58,22 @@ PointParam::param_get_default() const{
}
void
-PointParam::param_update_default(Geom::Point newpoint)
+PointParam::param_update_default(Geom::Point default_point)
{
- defvalue = newpoint;
+ defvalue = default_point;
+}
+
+void
+PointParam::param_update_default(const gchar * default_point)
+{
+ gchar ** strarray = g_strsplit(default_point, ",", 2);
+ double newx, newy;
+ unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
+ success += sp_svg_number_read_d(strarray[1], &newy);
+ g_strfreev (strarray);
+ if (success == 2) {
+ param_update_default( Geom::Point(newx, newy) );
+ }
}
void
@@ -123,9 +132,8 @@ PointParam::param_newWidget()
*param_wr,
param_effect->getRepr(),
param_effect->getSPDoc() ) );
- // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP)
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
- Geom::Affine transf = desktop->doc2dt();
+ Geom::Affine transf = Geom::Scale(1, -1);
+ transf[5] = SP_ACTIVE_DOCUMENT->getHeight().value("px");
pointwdg->setTransform(transf);
pointwdg->setValue( *this );
pointwdg->clearProgrammatically();
@@ -134,7 +142,6 @@ PointParam::param_newWidget()
Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() );
static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true);
static_cast<Gtk::HBox*>(hbox)->show_all_children();
-
return dynamic_cast<Gtk::Widget *> (hbox);
}
@@ -174,7 +181,7 @@ PointParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &or
s = A;
}
}
- pparam->param_setValue(s, this->pparam->liveupdate);
+ pparam->param_setValue(s);
SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item);
if(splpeitem && this->pparam->liveupdate){
sp_lpe_item_update_patheffect(splpeitem, false, false);
@@ -191,23 +198,23 @@ void
PointParamKnotHolderEntity::knot_click(guint state)
{
if (state & GDK_CONTROL_MASK) {
- if (state & GDK_MOD1_MASK) {
- this->pparam->param_set_default();
- SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item);
- if(splpeitem){
- sp_lpe_item_update_patheffect(splpeitem, false, false);
- }
+ if (state & GDK_MOD1_MASK) {
+ this->pparam->param_set_default();
+ SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item);
+ if(splpeitem){
+ sp_lpe_item_update_patheffect(splpeitem, false, false);
}
+ }
}
}
void
-PointParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+PointParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
knoth = knotholder;
PointParamKnotHolderEntity *e = new PointParamKnotHolderEntity(this);
// TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself???
- e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color);
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color);
knotholder->add(e);
}
diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h
index 4329e0bcd..a5153ad80 100644
--- a/src/live_effects/parameter/point.h
+++ b/src/live_effects/parameter/point.h
@@ -11,7 +11,7 @@
#include <glib.h>
#include <2geom/point.h>
-
+#include "ui/widget/registered-widget.h"
#include "live_effects/parameter/parameter.h"
#include "knot-holder-entity.h"
@@ -43,14 +43,15 @@ public:
void param_set_default();
Geom::Point param_get_default() const;
void param_set_liveupdate(bool live_update);
- void param_update_default(Geom::Point newpoint);
+ void param_update_default(Geom::Point default_point);
+
+ virtual void param_update_default(const gchar * default_point);
virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/);
void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
virtual bool providesKnotHolderEntities() const { return true; }
- virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
-
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
friend class PointParamKnotHolderEntity;
private:
PointParam(const PointParam&);
diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp
index c61e8f9cb..7753d819d 100644
--- a/src/live_effects/parameter/powerstrokepointarray.cpp
+++ b/src/live_effects/parameter/powerstrokepointarray.cpp
@@ -248,11 +248,11 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state)
}
}
-void PowerStrokePointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+void PowerStrokePointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
for (unsigned int i = 0; i < _vector.size(); ++i) {
PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(this, i);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("<b>Stroke width control point</b>: drag to alter the stroke width. <b>Ctrl+click</b> adds a control point, <b>Ctrl+Alt+click</b> deletes it, <b>Shift+click</b> launches width dialog."),
knot_shape, knot_mode, knot_color);
knotholder->add(e);
diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h
index 70b22e27e..a34163ca1 100644
--- a/src/live_effects/parameter/powerstrokepointarray.h
+++ b/src/live_effects/parameter/powerstrokepointarray.h
@@ -38,14 +38,14 @@ public:
float median_width();
virtual bool providesKnotHolderEntities() const { return true; }
- virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
+ virtual void param_update_default(const gchar * default_value){};
void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in, Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_normal_in);
Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2() const { return last_pwd2; }
Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2_normal() const { return last_pwd2_normal; }
void recalculate_controlpoints_for_new_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
-
friend class PowerStrokePointArrayParamKnotHolderEntity;
private:
diff --git a/src/live_effects/parameter/random.cpp b/src/live_effects/parameter/random.cpp
index 075e85ee1..b1375adda 100644
--- a/src/live_effects/parameter/random.cpp
+++ b/src/live_effects/parameter/random.cpp
@@ -78,8 +78,23 @@ RandomParam::param_set_default()
}
void
+RandomParam::param_update_default(gdouble default_value){
+ defvalue = default_value;
+}
+
+void
+RandomParam::param_update_default(const gchar * default_value){
+ double newval;
+ unsigned int success = sp_svg_number_read_d(default_value, &newval);
+ if (success == 1) {
+ param_update_default(newval);
+ }
+}
+
+void
RandomParam::param_set_value(gdouble val, long newseed)
{
+ param_effect->upd_params = true;
value = val;
if (integer)
value = round(value);
diff --git a/src/live_effects/parameter/random.h b/src/live_effects/parameter/random.h
index ca4440336..5fb6027ac 100644
--- a/src/live_effects/parameter/random.h
+++ b/src/live_effects/parameter/random.h
@@ -38,9 +38,9 @@ public:
void param_set_value(gdouble val, long newseed);
void param_make_integer(bool yes = true);
void param_set_range(gdouble min, gdouble max);
-
+ void param_update_default(gdouble default_value);
+ virtual void param_update_default(const gchar * default_value);
void resetRandomizer();
-
operator gdouble();
inline gdouble get_value() { return value; } ;
diff --git a/src/live_effects/parameter/satellitesarray.cpp b/src/live_effects/parameter/satellitesarray.cpp
new file mode 100644
index 000000000..ce4da243e
--- /dev/null
+++ b/src/live_effects/parameter/satellitesarray.cpp
@@ -0,0 +1,584 @@
+/*
+ * Author(s):
+ * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ *
+ * Copyright (C) 2014 Author(s)
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "knotholder.h"
+#include "ui/dialog/lpe-fillet-chamfer-properties.h"
+#include "live_effects/parameter/satellitesarray.h"
+#include "live_effects/effect.h"
+#include "sp-lpe-item.h"
+#include "inkscape.h"
+#include <preferences.h>
+// TODO due to internal breakage in glibmm headers,
+// this has to be included last.
+#include <glibmm/i18n.h>
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+SatellitesArrayParam::SatellitesArrayParam(const Glib::ustring &label,
+ const Glib::ustring &tip,
+ const Glib::ustring &key,
+ Inkscape::UI::Widget::Registry *wr,
+ Effect *effect)
+ : ArrayParam<std::vector<Satellite> >(label, tip, key, wr, effect, 0), _knoth(NULL)
+{
+ _knot_shape = SP_KNOT_SHAPE_DIAMOND;
+ _knot_mode = SP_KNOT_MODE_XOR;
+ _knot_color = 0xAAFF8800;
+ _helper_size = 0;
+ _use_distance = false;
+ _global_knot_hide = false;
+ _current_zoom = 0;
+ _effectType = FILLET_CHAMFER;
+ _last_pathvector_satellites = NULL;
+ param_widget_is_visible(false);
+}
+
+
+void SatellitesArrayParam::set_oncanvas_looks(SPKnotShapeType shape,
+ SPKnotModeType mode,
+ guint32 color)
+{
+ _knot_shape = shape;
+ _knot_mode = mode;
+ _knot_color = color;
+}
+
+void SatellitesArrayParam::setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write)
+{
+ _last_pathvector_satellites = pathVectorSatellites;
+ if (write) {
+ param_set_and_write_new_value(_last_pathvector_satellites->getSatellites());
+ } else {
+ param_setValue(_last_pathvector_satellites->getSatellites());
+ }
+}
+
+void SatellitesArrayParam::setUseDistance(bool use_knot_distance)
+{
+ _use_distance = use_knot_distance;
+}
+
+void SatellitesArrayParam::setCurrentZoom(double current_zoom)
+{
+ _current_zoom = current_zoom;
+}
+
+void SatellitesArrayParam::setGlobalKnotHide(bool global_knot_hide)
+{
+ _global_knot_hide = global_knot_hide;
+}
+void SatellitesArrayParam::setEffectType(EffectType et)
+{
+ _effectType = et;
+}
+
+void SatellitesArrayParam::setHelperSize(int hs)
+{
+ _helper_size = hs;
+ updateCanvasIndicators();
+}
+
+void SatellitesArrayParam::updateCanvasIndicators(bool mirror)
+{
+ if (!_last_pathvector_satellites) {
+ return;
+ }
+
+ if (!_hp.empty()) {
+ _hp.clear();
+ }
+ Geom::PathVector pathv = _last_pathvector_satellites->getPathVector();
+ if (pathv.empty()) {
+ return;
+ }
+ if (mirror == true) {
+ _hp.clear();
+ }
+ if (_effectType == FILLET_CHAMFER) {
+ for (size_t i = 0; i < _vector.size(); ++i) {
+ for (size_t j = 0; j < _vector[i].size(); ++j) {
+ if (_vector[i][j].hidden || //Ignore if hidden
+ (!_vector[i][j].has_mirror && mirror == true) || //Ignore if not have mirror and we are in mirror loop
+ _vector[i][j].amount == 0 || //no helper in 0 value
+ pathv[i].size() == j || //ignore last satellite in open paths with fillet chamfer effect
+ (!pathv[i].closed() && j == 0)) //ignore first satellites on open paths
+ {
+ continue;
+ }
+ Geom::Curve *curve_in = pathv[i][j].duplicate();
+ double pos = 0;
+ bool overflow = false;
+ double size_out = _vector[i][j].arcDistance(*curve_in);
+ double lenght_out = curve_in->length();
+ gint previous_index = j - 1; //Always are previous index because we skip first satellite on open paths
+ if (j == 0 && pathv[i].closed()) {
+ previous_index = pathv[i].size() - 1;
+ }
+ if ( previous_index < 0 ) {
+ return;
+ }
+ double lenght_in = pathv.curveAt(previous_index).length();
+ if (mirror) {
+ curve_in = const_cast<Geom::Curve *>(&pathv.curveAt(previous_index));
+ pos = _vector[i][j].time(size_out, true, *curve_in);
+ if (lenght_out < size_out) {
+ overflow = true;
+ }
+ } else {
+ pos = _vector[i][j].time(*curve_in);
+ if (lenght_in < size_out) {
+ overflow = true;
+ }
+ }
+ if (pos <= 0 || pos >= 1) {
+ continue;
+ }
+ Geom::Point point_a = curve_in->pointAt(pos);
+ Geom::Point deriv_a = unit_vector(derivative(curve_in->toSBasis()).pointAt(pos));
+ Geom::Rotate rot(Geom::Rotate::from_degrees(-90));
+ deriv_a = deriv_a * rot;
+ Geom::Point point_c = point_a - deriv_a * _helper_size;
+ Geom::Point point_d = point_a + deriv_a * _helper_size;
+ Geom::Ray ray_1(point_c, point_d);
+ char const *svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5";
+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
+ Geom::Affine aff = Geom::Affine();
+ aff *= Geom::Scale(_helper_size);
+ if (mirror) {
+ aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90));
+ } else {
+ aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270));
+ }
+ aff *= Geom::Translate(curve_in->pointAt(pos));
+ pathv *= aff;
+ _hp.push_back(pathv[0]);
+ _hp.push_back(pathv[1]);
+ if (overflow) {
+ double diameter = _helper_size;
+ if (_helper_size == 0) {
+ diameter = 15;
+ char const *svgd;
+ svgd = "M 0.7,0.35 A 0.35,0.35 0 0 1 0.35,0.7 0.35,0.35 0 0 1 0,0.35 "
+ "0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z";
+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
+ aff = Geom::Affine();
+ aff *= Geom::Scale(diameter);
+ aff *= Geom::Translate(point_a - Geom::Point(diameter * 0.35, diameter * 0.35));
+ pathv *= aff;
+ _hp.push_back(pathv[0]);
+ } else {
+ char const *svgd;
+ svgd = "M 0 -1.32 A 1.32 1.32 0 0 0 -1.32 0 A 1.32 1.32 0 0 0 0 1.32 A "
+ "1.32 1.32 0 0 0 1.18 0.59 L 0 0 L 1.18 -0.59 A 1.32 1.32 0 0 0 "
+ "0 -1.32 z";
+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
+ aff = Geom::Affine();
+ aff *= Geom::Scale(_helper_size / 2.0);
+ if (mirror) {
+ aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90));
+ } else {
+ aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270));
+ }
+ aff *= Geom::Translate(curve_in->pointAt(pos));
+ pathv *= aff;
+ _hp.push_back(pathv[0]);
+ }
+ }
+ }
+ }
+ }
+ if (!_knot_reset_helper.empty()) {
+ _hp.insert(_hp.end(), _knot_reset_helper.begin(), _knot_reset_helper.end() );
+ }
+ if (mirror) {
+ updateCanvasIndicators(false);
+ }
+}
+void SatellitesArrayParam::updateCanvasIndicators()
+{
+ updateCanvasIndicators(true);
+}
+
+void SatellitesArrayParam::addCanvasIndicators(
+ SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ hp_vec.push_back(_hp);
+}
+
+void SatellitesArrayParam::param_transform_multiply(Geom::Affine const &postmul, bool /*set*/)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ if (prefs->getBool("/options/transform/rectcorners", true)) {
+ for (size_t i = 0; i < _vector.size(); ++i) {
+ for (size_t j = 0; j < _vector[i].size(); ++j) {
+ if (!_vector[i][j].is_time && _vector[i][j].amount > 0) {
+ _vector[i][j].amount = _vector[i][j].amount * ((postmul.expansionX() + postmul.expansionY()) / 2);
+ }
+ }
+ }
+ param_set_and_write_new_value(_vector);
+ }
+}
+
+void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
+ SPItem *item,
+ bool mirror)
+{
+ if (!_last_pathvector_satellites) {
+ return;
+ }
+ Geom::PathVector pathv = _last_pathvector_satellites->getPathVector();
+ size_t index = 0;
+ for (size_t i = 0; i < _vector.size(); ++i) {
+ for (size_t j = 0; j < _vector[i].size(); ++j) {
+ if (!_vector[i][j].has_mirror && mirror) {
+ continue;
+ }
+ SatelliteType type = _vector[i][j].satellite_type;
+ if (mirror && i == 0 && j == 0) {
+ index = index + _last_pathvector_satellites->getTotalSatellites();
+ }
+ using namespace Geom;
+ //If is for filletChamfer effect...
+ if (_effectType == FILLET_CHAMFER) {
+ const gchar *tip;
+ if (type == CHAMFER) {
+ tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else if (type == INVERSE_CHAMFER) {
+ tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else if (type == INVERSE_FILLET) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else {
+ tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ }
+ FilletChamferKnotHolderEntity *e = new FilletChamferKnotHolderEntity(this, index);
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),_knot_shape, _knot_mode, _knot_color);
+ knotholder->add(e);
+ }
+ index++;
+ }
+ }
+ if (mirror) {
+ addKnotHolderEntities(knotholder, item, false);
+ }
+}
+
+void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
+ SPItem *item)
+{
+ _knoth = knotholder;
+ addKnotHolderEntities(knotholder, item, true);
+}
+
+FilletChamferKnotHolderEntity::FilletChamferKnotHolderEntity(
+ SatellitesArrayParam *p, size_t index)
+ : _pparam(p), _index(index) {}
+
+void FilletChamferKnotHolderEntity::knot_set(Geom::Point const &p,
+ Geom::Point const &/*origin*/,
+ guint state)
+{
+ if (!_pparam->_last_pathvector_satellites) {
+ return;
+ }
+ size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
+ bool is_mirror = false;
+ size_t index = _index;
+ if (_index >= total_satellites) {
+ index = _index - total_satellites;
+ is_mirror = true;
+ }
+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
+ size_t path_index = index_data.first;
+ size_t curve_index = index_data.second;
+
+ Geom::Point s = snap_knot_position(p, state);
+ if (!valid_index(path_index, curve_index)) {
+ return;
+ }
+ Satellite satellite = _pparam->_vector[path_index][curve_index];
+ Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
+ if (satellite.hidden ||
+ (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
+ pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
+ {
+ return;
+ }
+ gint previous_index = curve_index - 1;
+ if (curve_index == 0 && pathv[path_index].closed()) {
+ previous_index = pathv[path_index].size() - 1;
+ }
+ if ( previous_index < 0 ) {
+ return;
+ }
+ Geom::Curve const &curve_in = pathv[path_index][previous_index];
+ double mirror_time = Geom::nearest_time(s, curve_in);
+ Geom::Point mirror = curve_in.pointAt(mirror_time);
+ double normal_time = Geom::nearest_time(s, pathv[path_index][curve_index]);
+ Geom::Point normal = pathv[path_index][curve_index].pointAt(normal_time);
+ double distance_mirror = Geom::distance(mirror,s);
+ double distance_normal = Geom::distance(normal,s);
+ if (Geom::are_near(s, pathv[path_index][curve_index].initialPoint(), 1.5 / _pparam->_current_zoom)) {
+ satellite.amount = 0;
+ } else if (distance_mirror < distance_normal) {
+ double time_start = 0;
+ Satellites satellites = _pparam->_last_pathvector_satellites->getSatellites();
+ time_start = satellites[path_index][previous_index].time(curve_in);
+ if (time_start > mirror_time) {
+ mirror_time = time_start;
+ }
+ double size = arcLengthAt(mirror_time, curve_in);
+ double amount = curve_in.length() - size;
+ if (satellite.is_time) {
+ amount = timeAtArcLength(amount, pathv[path_index][curve_index]);
+ }
+ satellite.amount = amount;
+ } else {
+ satellite.setPosition(s, pathv[path_index][curve_index]);
+ }
+ _pparam->_knot_reset_helper.clear();
+ if (satellite.amount == 0) {
+ char const *svgd;
+ svgd = "M -5.39,8.78 -9.13,5.29 -10.38,10.28 Z M -7.22,7.07 -3.43,3.37 m -1.95,-12.16 -3.74,3.5 -1.26,-5 z "
+ "m -1.83,1.71 3.78,3.7 M 5.24,8.78 8.98,5.29 10.24,10.28 Z "
+ "M 7.07,7.07 3.29,3.37 M 5.24,-8.78 l 3.74,3.5 1.26,-5 z M 7.07,-7.07 3.29,-3.37";
+ _pparam->_knot_reset_helper = sp_svg_read_pathv(svgd);
+ _pparam->_knot_reset_helper *= Geom::Affine(_pparam->_helper_size * 0.1,0,0,_pparam->_helper_size * 0.1,0,0) * Geom::Translate(pathv[path_index][curve_index].initialPoint());
+ }
+ _pparam->_vector[path_index][curve_index] = satellite;
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+}
+
+Geom::Point FilletChamferKnotHolderEntity::knot_get() const
+{
+ if (!_pparam->_last_pathvector_satellites || _pparam->_global_knot_hide) {
+ return Geom::Point(Geom::infinity(), Geom::infinity());
+ }
+ Geom::Point tmp_point;
+ size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
+ bool is_mirror = false;
+ size_t index = _index;
+ if (_index >= total_satellites) {
+ index = _index - total_satellites;
+ is_mirror = true;
+ }
+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
+ size_t path_index = index_data.first;
+ size_t curve_index = index_data.second;
+ if (!valid_index(path_index, curve_index)) {
+ return Geom::Point(Geom::infinity(), Geom::infinity());
+ }
+ Satellite satellite = _pparam->_vector[path_index][curve_index];
+ Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
+ if (satellite.hidden ||
+ (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
+ pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
+ {
+ return Geom::Point(Geom::infinity(), Geom::infinity());
+ }
+ this->knot->show();
+ if (is_mirror) {
+ gint previous_index = curve_index - 1;
+ if (curve_index == 0 && pathv[path_index].closed()) {
+ previous_index = pathv[path_index].size() - 1;
+ }
+ if ( previous_index < 0 ) {
+ return Geom::Point(Geom::infinity(), Geom::infinity());
+ }
+ Geom::Curve const &curve_in = pathv[path_index][previous_index];
+ double s = satellite.arcDistance(pathv[path_index][curve_index]);
+ double t = satellite.time(s, true, curve_in);
+ if (t > 1) {
+ t = 1;
+ }
+ if (t < 0) {
+ t = 0;
+ }
+ double time_start = 0;
+ time_start = _pparam->_last_pathvector_satellites->getSatellites()[path_index][previous_index].time(curve_in);
+ if (time_start > t) {
+ t = time_start;
+ }
+ tmp_point = (curve_in).pointAt(t);
+ } else {
+ tmp_point = satellite.getPosition(pathv[path_index][curve_index]);
+ }
+ Geom::Point const canvas_point = tmp_point;
+ _pparam->updateCanvasIndicators();
+ return canvas_point;
+}
+
+void FilletChamferKnotHolderEntity::knot_click(guint state)
+{
+ if (!_pparam->_last_pathvector_satellites) {
+ return;
+ }
+ size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
+ bool is_mirror = false;
+ size_t index = _index;
+ if (_index >= total_satellites) {
+ index = _index - total_satellites;
+ is_mirror = true;
+ }
+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
+ size_t path_index = index_data.first;
+ size_t curve_index = index_data.second;
+ if (!valid_index(path_index, curve_index)) {
+ return;
+ }
+ Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
+ if ((!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
+ pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
+ {
+ return;
+ }
+ if (state & GDK_CONTROL_MASK) {
+ if (state & GDK_MOD1_MASK) {
+ _pparam->_vector[path_index][curve_index].amount = 0.0;
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ } else {
+ using namespace Geom;
+ SatelliteType type = _pparam->_vector[path_index][curve_index].satellite_type;
+ switch (type) {
+ case FILLET:
+ type = INVERSE_FILLET;
+ break;
+ case INVERSE_FILLET:
+ type = CHAMFER;
+ break;
+ case CHAMFER:
+ type = INVERSE_CHAMFER;
+ break;
+ default:
+ type = FILLET;
+ break;
+ }
+ _pparam->_vector[path_index][curve_index].satellite_type = type;
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ const gchar *tip;
+ if (type == CHAMFER) {
+ tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> resets");
+ } else if (type == INVERSE_CHAMFER) {
+ tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> resets");
+ } else if (type == INVERSE_FILLET) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> resets");
+ } else {
+ tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> resets");
+ }
+ this->knot->tip = g_strdup(tip);
+ this->knot->show();
+ }
+ } else if (state & GDK_SHIFT_MASK) {
+ double amount = _pparam->_vector[path_index][curve_index].amount;
+ gint previous_index = curve_index - 1;
+ if (curve_index == 0 && pathv[path_index].closed()) {
+ previous_index = pathv[path_index].size() - 1;
+ }
+ if ( previous_index < 0 ) {
+ return;
+ }
+ if (!_pparam->_use_distance && !_pparam->_vector[path_index][curve_index].is_time) {
+ amount = _pparam->_vector[path_index][curve_index].lenToRad(amount, pathv[path_index][previous_index], pathv[path_index][curve_index], _pparam->_vector[path_index][previous_index]);
+ }
+ bool aprox = false;
+ Geom::D2<Geom::SBasis> d2_out = pathv[path_index][curve_index].toSBasis();
+ Geom::D2<Geom::SBasis> d2_in = pathv[path_index][previous_index].toSBasis();
+ aprox = ((d2_in)[0].degreesOfFreedom() != 2 ||
+ d2_out[0].degreesOfFreedom() != 2) &&
+ !_pparam->_use_distance
+ ? true
+ : false;
+ Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog(
+ this->desktop, amount, this, _pparam->_use_distance,
+ aprox, _pparam->_vector[path_index][curve_index]);
+
+ }
+}
+
+void FilletChamferKnotHolderEntity::knot_set_offset(Satellite satellite)
+{
+ if (!_pparam->_last_pathvector_satellites) {
+ return;
+ }
+ size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
+ bool is_mirror = false;
+ size_t index = _index;
+ if (_index >= total_satellites) {
+ index = _index - total_satellites;
+ is_mirror = true;
+ }
+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
+ size_t path_index = index_data.first;
+ size_t curve_index = index_data.second;
+ if (!valid_index(path_index, curve_index)) {
+ return;
+ }
+ Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
+ if (satellite.hidden ||
+ (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
+ pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
+ {
+ return;
+ }
+ double amount = satellite.amount;
+ double max_amount = amount;
+ if (!_pparam->_use_distance && !satellite.is_time) {
+ gint previous_index = curve_index - 1;
+ if (curve_index == 0 && pathv[path_index].closed()) {
+ previous_index = pathv[path_index].size() - 1;
+ }
+ if ( previous_index < 0 ) {
+ return;
+ }
+ amount = _pparam->_vector[path_index][curve_index].radToLen(amount, pathv[path_index][previous_index], pathv[path_index][curve_index]);
+ if (max_amount > 0 && amount == 0) {
+ amount = _pparam->_vector[path_index][curve_index].amount;
+ }
+ }
+ satellite.amount = amount;
+ _pparam->_vector[path_index][curve_index] = satellite;
+ this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
+ SPLPEItem *splpeitem = dynamic_cast<SPLPEItem *>(item);
+ if (splpeitem) {
+ sp_lpe_item_update_patheffect(splpeitem, false, false);
+ }
+}
+
+} /* namespace LivePathEffect */
+
+} /* 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 :
diff --git a/src/live_effects/parameter/satellitesarray.h b/src/live_effects/parameter/satellitesarray.h
new file mode 100644
index 000000000..5ae372ac2
--- /dev/null
+++ b/src/live_effects/parameter/satellitesarray.h
@@ -0,0 +1,114 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_SATELLITES_ARRAY_H
+#define INKSCAPE_LIVEPATHEFFECT_SATELLITES_ARRAY_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ * Special thanks to Johan Engelen for the base of the effect -powerstroke-
+ * Also to ScislaC for point me to the idea
+ * Also su_v for his construvtive feedback and time
+ * To Nathan Hurst for his review and help on refactor
+ * and finaly to Liam P. White for his big help on coding, that save me a lot of
+ * hours
+ *
+ *
+ * This parameter act as bridge from pathVectorSatellites class to serialize it as a LPE
+ * parameter
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/parameter/array.h"
+#include "live_effects/effect-enum.h"
+#include "helper/geom-pathvectorsatellites.h"
+#include "knot-holder-entity.h"
+#include <glib.h>
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class FilletChamferKnotHolderEntity;
+
+class SatellitesArrayParam : public ArrayParam<std::vector<Satellite> > {
+public:
+ SatellitesArrayParam(const Glib::ustring &label, const Glib::ustring &tip,
+ const Glib::ustring &key,
+ Inkscape::UI::Widget::Registry *wr, Effect *effect);
+
+ virtual Gtk::Widget *param_newWidget()
+ {
+ return NULL;
+ }
+ virtual void setHelperSize(int hs);
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item, bool mirror);
+ virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
+ virtual void updateCanvasIndicators();
+ virtual void updateCanvasIndicators(bool mirror);
+ virtual bool providesKnotHolderEntities() const
+ {
+ return true;
+ }
+ void param_transform_multiply(Geom::Affine const &postmul, bool /*set*/);
+ void setUseDistance(bool use_knot_distance);
+ void setCurrentZoom(double current_zoom);
+ void setGlobalKnotHide(bool global_knot_hide);
+ void setEffectType(EffectType et);
+ void setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write = true);
+ void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
+
+ friend class FilletChamferKnotHolderEntity;
+ friend class LPEFilletChamfer;
+
+protected:
+ KnotHolder *_knoth;
+
+private:
+ SatellitesArrayParam(const SatellitesArrayParam &);
+ SatellitesArrayParam &operator=(const SatellitesArrayParam &);
+
+ SPKnotShapeType _knot_shape;
+ SPKnotModeType _knot_mode;
+ guint32 _knot_color;
+ Geom::PathVector _hp;
+ Geom::PathVector _knot_reset_helper;
+ int _helper_size;
+ bool _use_distance;
+ bool _global_knot_hide;
+ double _current_zoom;
+ EffectType _effectType;
+ PathVectorSatellites *_last_pathvector_satellites;
+
+};
+
+class FilletChamferKnotHolderEntity : public KnotHolderEntity {
+public:
+ FilletChamferKnotHolderEntity(SatellitesArrayParam *p, size_t index);
+ virtual ~FilletChamferKnotHolderEntity()
+ {
+ _pparam->_knoth = NULL;
+ }
+
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin,
+ guint state);
+ virtual Geom::Point knot_get() const;
+ virtual void knot_click(guint state);
+ void knot_set_offset(Satellite);
+ /** Checks whether the index falls within the size of the parameter's vector
+ */
+ bool valid_index(size_t index,size_t subindex) const
+ {
+ return (_pparam->_vector.size() > index && _pparam->_vector[index].size() > subindex);
+ };
+
+private:
+ SatellitesArrayParam *_pparam;
+ size_t _index;
+};
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp
index 234a6174d..d633666aa 100644
--- a/src/live_effects/parameter/text.cpp
+++ b/src/live_effects/parameter/text.cpp
@@ -31,12 +31,16 @@ TextParam::TextParam( const Glib::ustring& label, const Glib::ustring& tip,
Effect* effect, const Glib::ustring default_value )
: Parameter(label, tip, key, wr, effect),
value(default_value),
- defvalue(default_value)
+ defvalue(default_value),
+ _hide_canvas_text(false)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP; // FIXME: we shouldn't use this!
- canvas_text = (SPCanvasText *) sp_canvastext_new(desktop->getTempGroup(), desktop, Geom::Point(0,0), "");
- sp_canvastext_set_text (canvas_text, default_value.c_str());
- sp_canvastext_set_coords (canvas_text, 0, 0);
+ if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) { // FIXME: we shouldn't use this!
+ canvas_text = (SPCanvasText *) sp_canvastext_new(desktop->getTempGroup(), desktop, Geom::Point(0,0), "");
+ sp_canvastext_set_text (canvas_text, default_value.c_str());
+ sp_canvastext_set_coords (canvas_text, 0, 0);
+ } else {
+ _hide_canvas_text = true;
+ }
}
void
@@ -46,9 +50,26 @@ TextParam::param_set_default()
}
void
+TextParam::param_update_default(const gchar * default_value)
+{
+ defvalue = (Glib::ustring)default_value;
+}
+
+void
+TextParam::param_hide_canvas_text()
+{
+ if (!_hide_canvas_text) {
+ sp_canvastext_set_text(canvas_text, " ");
+ _hide_canvas_text = true;
+ }
+}
+
+void
TextParam::setPos(Geom::Point pos)
{
- sp_canvastext_set_coords (canvas_text, pos);
+ if (!_hide_canvas_text) {
+ sp_canvastext_set_coords (canvas_text, pos);
+ }
}
void
@@ -63,9 +84,10 @@ TextParam::setPosAndAnchor(const Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2,
Point dir = unit_vector(derivative(pwd2_reparam).valueAt(t_reparam));
Point n = -rot90(dir);
double angle = Geom::angle_between(dir, Point(1,0));
-
- sp_canvastext_set_coords(canvas_text, pos + n * length);
- sp_canvastext_set_anchor_manually(canvas_text, std::sin(angle), -std::cos(angle));
+ if (!_hide_canvas_text) {
+ sp_canvastext_set_coords(canvas_text, pos + n * length);
+ sp_canvastext_set_anchor_manually(canvas_text, std::sin(angle), -std::cos(angle));
+ }
}
void
@@ -73,7 +95,9 @@ TextParam::setAnchor(double x_value, double y_value)
{
anchor_x = x_value;
anchor_y = y_value;
- sp_canvastext_set_anchor_manually (canvas_text, anchor_x, anchor_y);
+ if (!_hide_canvas_text) {
+ sp_canvastext_set_anchor_manually (canvas_text, anchor_x, anchor_y);
+ }
}
bool
@@ -86,7 +110,10 @@ TextParam::param_readSVGValue(const gchar * strvalue)
gchar *
TextParam::param_getSVGValue() const
{
- return g_strdup(value.c_str());
+ Inkscape::SVGOStringStream os;
+ os << value;
+ gchar * str = g_strdup(os.str().c_str());
+ return str;
}
Gtk::Widget *
@@ -94,21 +121,23 @@ TextParam::param_newWidget()
{
Inkscape::UI::Widget::RegisteredText *rsu = Gtk::manage(new Inkscape::UI::Widget::RegisteredText(
param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc()));
-
- rsu->setText(value.c_str());
+ rsu->setText(value);
rsu->setProgrammatically = false;
rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change text parameter"));
-
return dynamic_cast<Gtk::Widget *> (rsu);
}
void
TextParam::param_setValue(const Glib::ustring newvalue)
{
+ if (value != newvalue) {
+ param_effect->upd_params = true;
+ }
value = newvalue;
-
- sp_canvastext_set_text (canvas_text, newvalue.c_str());
+ if (!_hide_canvas_text) {
+ sp_canvastext_set_text (canvas_text, newvalue.c_str());
+ }
}
} /* namespace LivePathEffect */
diff --git a/src/live_effects/parameter/text.h b/src/live_effects/parameter/text.h
index 62de70eec..137f3ee02 100644
--- a/src/live_effects/parameter/text.h
+++ b/src/live_effects/parameter/text.h
@@ -39,21 +39,23 @@ public:
virtual bool param_readSVGValue(const gchar * strvalue);
virtual gchar * param_getSVGValue() const;
- void param_setValue(const Glib::ustring newvalue);
+ void param_setValue(Glib::ustring newvalue);
+ void param_hide_canvas_text();
virtual void param_set_default();
+ virtual void param_update_default(const gchar * default_value);
void setPos(Geom::Point pos);
void setPosAndAnchor(const Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2,
const double t, const double length, bool use_curvature = false);
void setAnchor(double x_value, double y_value);
- const Glib::ustring get_value() const { return defvalue; };
+ const Glib::ustring get_value() const { return value; };
private:
TextParam(const TextParam&);
TextParam& operator=(const TextParam&);
double anchor_x;
double anchor_y;
-
+ bool _hide_canvas_text;
Glib::ustring value;
Glib::ustring defvalue;
diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp
index 47a8b5615..eb40a7e41 100644
--- a/src/live_effects/parameter/togglebutton.cpp
+++ b/src/live_effects/parameter/togglebutton.cpp
@@ -12,6 +12,7 @@
#include "live_effects/effect.h"
#include "svg/svg.h"
#include "svg/stringstream.h"
+#include "selection.h"
#include "widgets/icon.h"
#include "inkscape.h"
#include "verbs.h"
@@ -24,10 +25,10 @@ namespace LivePathEffect {
ToggleButtonParam::ToggleButtonParam( const Glib::ustring& label, const Glib::ustring& tip,
const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
Effect* effect, bool default_value, const Glib::ustring& inactive_label,
- char const * icon_active, char const * icon_inactive,
- Inkscape::IconSize icon_size)
+ char const * _icon_active, char const * _icon_inactive,
+ Inkscape::IconSize _icon_size)
: Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value),
- inactiveLabel(inactive_label), iconActive(icon_active), iconInactive(icon_inactive), iconSize(icon_size)
+ inactive_label(inactive_label), _icon_active(_icon_active), _icon_inactive(_icon_inactive), _icon_size(_icon_size)
{
checkwdg = NULL;
}
@@ -59,6 +60,18 @@ ToggleButtonParam::param_getSVGValue() const
return str;
}
+void
+ToggleButtonParam::param_update_default(bool default_value)
+{
+ defvalue = default_value;
+}
+
+void
+ToggleButtonParam::param_update_default(const gchar * default_value)
+{
+ param_update_default(helperfns_read_bool(default_value, defvalue));
+}
+
Gtk::Widget *
ToggleButtonParam::param_newWidget()
{
@@ -67,52 +80,50 @@ ToggleButtonParam::param_newWidget()
}
checkwdg = Gtk::manage(
- new Inkscape::UI::Widget::RegisteredToggleButton( param_label,
+ new Inkscape::UI::Widget::RegisteredToggleButton(param_label,
param_tooltip,
param_key,
*param_wr,
false,
param_effect->getRepr(),
param_effect->getSPDoc()) );
-#if GTK_CHECK_VERSION(3,0,0)
- GtkWidget * boxButton = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_box_set_homogeneous(GTK_BOX(boxButton), false);
-#else
- GtkWidget * boxButton = gtk_hbox_new (false, 0);
-#endif
- GtkWidget * labelButton = gtk_label_new ("");
+ auto box_button = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous(GTK_BOX(box_button), false);
+ GtkWidget * label_button = gtk_label_new ("");
if (!param_label.empty()) {
- if(value || inactiveLabel.empty()){
- gtk_label_set_text(GTK_LABEL(labelButton), param_label.c_str());
+ if(value || inactive_label.empty()){
+ gtk_label_set_text(GTK_LABEL(label_button), param_label.c_str());
}else{
- gtk_label_set_text(GTK_LABEL(labelButton), inactiveLabel.c_str());
+ gtk_label_set_text(GTK_LABEL(label_button), inactive_label.c_str());
}
}
- gtk_widget_show(labelButton);
- if ( iconActive ) {
- if(!iconInactive){
- iconInactive = iconActive;
+ gtk_widget_show(label_button);
+ if ( _icon_active ) {
+ if(!_icon_inactive){
+ _icon_inactive = _icon_active;
}
- gtk_widget_show(boxButton);
- GtkWidget *iconButton = sp_icon_new(iconSize, iconActive);
+ gtk_widget_show(box_button);
+ GtkWidget *icon_button = NULL;
if(!value){
- iconButton = sp_icon_new(iconSize, iconInactive);
+ icon_button = sp_icon_new(_icon_size, _icon_inactive);
+ } else {
+ icon_button = sp_icon_new(_icon_size, _icon_active);
}
- gtk_widget_show(iconButton);
- gtk_box_pack_start (GTK_BOX(boxButton), iconButton, false, false, 1);
+ gtk_widget_show(icon_button);
+ gtk_box_pack_start (GTK_BOX(box_button), icon_button, false, false, 1);
if (!param_label.empty()) {
- gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1);
+ gtk_box_pack_start (GTK_BOX(box_button), label_button, false, false, 1);
}
}else{
- gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1);
+ gtk_box_pack_start (GTK_BOX(box_button), label_button, false, false, 1);
}
- checkwdg->add(*Gtk::manage(Glib::wrap(boxButton)));
+
+ checkwdg->add(*Gtk::manage(Glib::wrap(box_button)));
checkwdg->setActive(value);
checkwdg->setProgrammatically = false;
checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter"));
_toggled_connection = checkwdg->signal_toggled().connect(sigc::mem_fun(*this, &ToggleButtonParam::toggled));
-
return checkwdg;
}
@@ -126,37 +137,46 @@ ToggleButtonParam::refresh_button()
if(!checkwdg){
return;
}
- Gtk::Widget * boxButton = checkwdg->get_child();
- if(!boxButton){
+ Gtk::Widget * box_button = checkwdg->get_child();
+ if(!box_button){
return;
}
- GList * childs = gtk_container_get_children(GTK_CONTAINER(boxButton->gobj()));
- guint totalWidgets = g_list_length (childs);
+ GList * childs = gtk_container_get_children(GTK_CONTAINER(box_button->gobj()));
+ guint total_widgets = g_list_length (childs);
if (!param_label.empty()) {
- if(value || inactiveLabel.empty()){
- gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, totalWidgets-1)), param_label.c_str());
+ if(value || inactive_label.empty()){
+ gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, total_widgets-1)), param_label.c_str());
}else{
- gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, totalWidgets-1)), inactiveLabel.c_str());
+ gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, total_widgets-1)), inactive_label.c_str());
}
}
- if ( iconActive ) {
- GdkPixbuf * iconPixbuf = sp_pixbuf_new( iconSize, iconActive );
+ if ( _icon_active ) {
+ GdkPixbuf * icon_pixbuf = NULL;
if(!value){
- iconPixbuf = sp_pixbuf_new( iconSize, iconInactive);
+ icon_pixbuf = sp_pixbuf_new( _icon_size, _icon_inactive );
+ } else {
+ icon_pixbuf = sp_pixbuf_new( _icon_size, _icon_active );
}
- gtk_image_set_from_pixbuf (GTK_IMAGE(g_list_nth_data(childs, 0)), iconPixbuf);
+ gtk_image_set_from_pixbuf (GTK_IMAGE(g_list_nth_data(childs, 0)), icon_pixbuf);
}
}
void
ToggleButtonParam::param_setValue(bool newvalue)
{
+ if (value != newvalue) {
+ param_effect->upd_params = true;
+ }
value = newvalue;
refresh_button();
}
void
ToggleButtonParam::toggled() {
+ if (SP_ACTIVE_DESKTOP) {
+ Inkscape::Selection *selection = SP_ACTIVE_DESKTOP->getSelection();
+ selection->emitModified();
+ }
_signal_toggled.emit();
}
diff --git a/src/live_effects/parameter/togglebutton.h b/src/live_effects/parameter/togglebutton.h
index 4e545bcfd..d6ca15e75 100644
--- a/src/live_effects/parameter/togglebutton.h
+++ b/src/live_effects/parameter/togglebutton.h
@@ -51,6 +51,8 @@ public:
sigc::signal<void>& signal_toggled() { return _signal_toggled; }
virtual void toggled();
+ void param_update_default(bool default_value);
+ virtual void param_update_default(const gchar * default_value);
private:
ToggleButtonParam(const ToggleButtonParam&);
@@ -59,10 +61,10 @@ private:
void refresh_button();
bool value;
bool defvalue;
- const Glib::ustring inactiveLabel;
- const char * iconActive;
- const char * iconInactive;
- Inkscape::IconSize iconSize;
+ const Glib::ustring inactive_label;
+ const char * _icon_active;
+ const char * _icon_inactive;
+ Inkscape::IconSize _icon_size;
Inkscape::UI::Widget::RegisteredToggleButton * checkwdg;
sigc::signal<void> _signal_toggled;
diff --git a/src/live_effects/parameter/transformedpoint.cpp b/src/live_effects/parameter/transformedpoint.cpp
index 0d03432c3..22d5ba3a4 100644
--- a/src/live_effects/parameter/transformedpoint.cpp
+++ b/src/live_effects/parameter/transformedpoint.cpp
@@ -82,6 +82,25 @@ TransformedPointParam::param_getSVGValue() const
return str;
}
+void
+TransformedPointParam::param_update_default(Geom::Point default_point)
+{
+ defvalue = default_point;
+}
+
+void
+TransformedPointParam::param_update_default(const gchar * default_point)
+{
+ gchar ** strarray = g_strsplit(default_point, ",", 2);
+ double newx, newy;
+ unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
+ success += sp_svg_number_read_d(strarray[1], &newy);
+ g_strfreev (strarray);
+ if (success == 2) {
+ param_update_default( Geom::Point(newx, newy) );
+ }
+}
+
Gtk::Widget *
TransformedPointParam::param_newWidget()
{
diff --git a/src/live_effects/parameter/transformedpoint.h b/src/live_effects/parameter/transformedpoint.h
index c96bedb53..269cc508e 100644
--- a/src/live_effects/parameter/transformedpoint.h
+++ b/src/live_effects/parameter/transformedpoint.h
@@ -51,7 +51,9 @@ public:
void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
void set_oncanvas_color(guint32 color);
-
+ Geom::Point param_get_default() { return defvalue; }
+ void param_update_default(Geom::Point default_point);
+ virtual void param_update_default(const gchar * default_point);
virtual bool providesKnotHolderEntities() const { return true; }
virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
diff --git a/src/live_effects/parameter/unit.cpp b/src/live_effects/parameter/unit.cpp
index 0ee553e2c..b9b91c1e6 100644
--- a/src/live_effects/parameter/unit.cpp
+++ b/src/live_effects/parameter/unit.cpp
@@ -54,9 +54,16 @@ UnitParam::param_set_default()
param_set_value(*defunit);
}
+void
+UnitParam::param_update_default(const gchar * default_unit)
+{
+ defunit = unit_table.getUnit((Glib::ustring)default_unit);
+}
+
void
UnitParam::param_set_value(Inkscape::Util::Unit const &val)
{
+ param_effect->upd_params = true;
unit = new Inkscape::Util::Unit(val);
}
diff --git a/src/live_effects/parameter/unit.h b/src/live_effects/parameter/unit.h
index 59a483018..c662b6edc 100644
--- a/src/live_effects/parameter/unit.h
+++ b/src/live_effects/parameter/unit.h
@@ -33,10 +33,10 @@ public:
virtual gchar * param_getSVGValue() const;
virtual void param_set_default();
void param_set_value(Inkscape::Util::Unit const &val);
+ virtual void param_update_default(const gchar * default_unit);
const gchar *get_abbreviation() const;
-
virtual Gtk::Widget * param_newWidget();
-
+
operator Inkscape::Util::Unit const *() const { return unit; }
private:
diff --git a/src/live_effects/parameter/vector.cpp b/src/live_effects/parameter/vector.cpp
index cfaa9e7e7..470fa9c2d 100644
--- a/src/live_effects/parameter/vector.cpp
+++ b/src/live_effects/parameter/vector.cpp
@@ -14,7 +14,6 @@
#include "svg/stringstream.h"
#include "live_effects/effect.h"
-#include "desktop.h"
#include "verbs.h"
namespace Inkscape {
@@ -49,6 +48,25 @@ VectorParam::param_set_default()
setVector(defvalue);
}
+void
+VectorParam::param_update_default(Geom::Point default_point)
+{
+ defvalue = default_point;
+}
+
+void
+VectorParam::param_update_default(const gchar * default_point)
+{
+ gchar ** strarray = g_strsplit(default_point, ",", 2);
+ double newx, newy;
+ unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
+ success += sp_svg_number_read_d(strarray[1], &newy);
+ g_strfreev (strarray);
+ if (success == 2) {
+ param_update_default( Geom::Point(newx, newy) );
+ }
+}
+
bool
VectorParam::param_readSVGValue(const gchar * strvalue)
{
@@ -117,7 +135,7 @@ VectorParam::set_and_write_new_values(Geom::Point const &new_origin, Geom::Point
void
VectorParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/)
{
- set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() );
+ set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() );
}
@@ -188,14 +206,14 @@ private:
};
void
-VectorParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+VectorParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
VectorParamKnotHolderEntity_Origin *origin_e = new VectorParamKnotHolderEntity_Origin(this);
- origin_e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), ori_knot_shape, ori_knot_mode, ori_knot_color);
+ origin_e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), ori_knot_shape, ori_knot_mode, ori_knot_color);
knotholder->add(origin_e);
VectorParamKnotHolderEntity_Vector *vector_e = new VectorParamKnotHolderEntity_Vector(this);
- vector_e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color);
+ vector_e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color);
knotholder->add(vector_e);
}
diff --git a/src/live_effects/parameter/vector.h b/src/live_effects/parameter/vector.h
index 35ca04437..d270e9f43 100644
--- a/src/live_effects/parameter/vector.h
+++ b/src/live_effects/parameter/vector.h
@@ -51,9 +51,10 @@ public:
void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
void set_origin_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
void set_oncanvas_color(guint32 color);
-
+ void param_update_default(Geom::Point default_point);
+ virtual void param_update_default(const gchar * default_point);
virtual bool providesKnotHolderEntities() const { return true; }
- virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
private:
VectorParam(const VectorParam&);
diff --git a/src/live_effects/spiro.cpp b/src/live_effects/spiro.cpp
index 0ac2815bf..a2ff4813e 100644
--- a/src/live_effects/spiro.cpp
+++ b/src/live_effects/spiro.cpp
@@ -29,7 +29,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#include <string.h>
#include "display/curve.h"
-#include <2geom/math-utils.h>
#define SPIRO_SHOW_INFINITE_COORDINATE_CALLS