Merge lp:~liampwhite/inkscape/inkscape into lp:inkscape/experimental
- inkscape
- Merge into experimental
Proposed by
Liam P. White
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 13545 | ||||||||
Proposed branch: | lp:~liampwhite/inkscape/inkscape | ||||||||
Merge into: | lp:inkscape/experimental | ||||||||
Diff against target: |
12144 lines (+10546/-196) 97 files modified
po/POTFILES.in (+15/-0) src/Makefile_insert (+3/-0) src/attributes.cpp (+2/-0) src/attributes.h (+2/-0) src/display/cairo-utils.cpp (+1/-3) src/display/cairo-utils.h (+3/-0) src/display/drawing-item.cpp (+3/-2) src/display/sp-canvas.cpp (+1/-1) src/interface.cpp (+11/-0) src/interface.h (+1/-0) src/knotholder.cpp (+25/-11) src/live_effects/CMakeLists.txt (+13/-0) src/live_effects/Makefile_insert (+16/-0) src/live_effects/effect-enum.h (+7/-0) src/live_effects/effect.cpp (+71/-6) src/live_effects/effect.h (+11/-0) src/live_effects/lpe-attach-path.cpp (+198/-0) src/live_effects/lpe-attach-path.h (+52/-0) src/live_effects/lpe-bounding-box.cpp (+67/-0) src/live_effects/lpe-bounding-box.h (+37/-0) src/live_effects/lpe-ellipse_5pts.cpp (+214/-0) src/live_effects/lpe-ellipse_5pts.h (+50/-0) src/live_effects/lpe-fill-between-many.cpp (+78/-0) src/live_effects/lpe-fill-between-many.h (+36/-0) src/live_effects/lpe-fill-between-strokes.cpp (+116/-0) src/live_effects/lpe-fill-between-strokes.h (+38/-0) src/live_effects/lpe-jointype.cpp (+184/-0) src/live_effects/lpe-jointype.h (+45/-0) src/live_effects/lpe-knot.cpp (+4/-0) src/live_effects/lpe-knot.h (+2/-1) src/live_effects/lpe-powerstroke-interpolators.h (+40/-0) src/live_effects/lpe-powerstroke.cpp (+89/-11) src/live_effects/lpe-powerstroke.h (+2/-0) src/live_effects/lpe-tangent_to_curve.cpp (+8/-11) src/live_effects/lpe-tangent_to_curve.h (+0/-1) src/live_effects/lpe-taperstroke.cpp (+630/-0) src/live_effects/lpe-taperstroke.h (+72/-0) src/live_effects/parameter/Makefile_insert (+4/-0) src/live_effects/parameter/filletchamferpointarray.cpp (+3/-0) src/live_effects/parameter/originalpatharray.cpp (+497/-0) src/live_effects/parameter/originalpatharray.h (+123/-0) src/live_effects/parameter/powerstrokepointarray.cpp (+36/-7) src/live_effects/parameter/powerstrokepointarray.h (+21/-2) src/live_effects/parameter/transformedpoint.cpp (+182/-0) src/live_effects/parameter/transformedpoint.h (+87/-0) src/live_effects/pathoutlineprovider.cpp (+795/-0) src/live_effects/pathoutlineprovider.h (+55/-0) src/menus-skeleton.h (+3/-0) src/path-chemistry.cpp (+8/-0) src/selection-chemistry.cpp (+159/-48) src/selection-chemistry.h (+1/-0) src/snap.cpp (+1/-1) src/sp-item-group.cpp (+12/-0) src/sp-item-group.h (+8/-0) src/sp-item.cpp (+40/-0) src/sp-item.h (+15/-0) src/sp-lpe-item.cpp (+8/-2) src/sp-object.h (+1/-0) src/sp-tag-use-reference.cpp (+156/-0) src/sp-tag-use-reference.h (+78/-0) src/sp-tag-use.cpp (+206/-0) src/sp-tag-use.h (+55/-0) src/sp-tag.cpp (+154/-0) src/sp-tag.h (+57/-0) src/ui/dialog/Makefile_insert (+6/-0) src/ui/dialog/calligraphic-profile-rename.h (+1/-1) src/ui/dialog/color-item.cpp (+2/-0) src/ui/dialog/dialog-manager.cpp (+6/-0) src/ui/dialog/filedialog.h (+1/-0) src/ui/dialog/lpe-powerstroke-properties.cpp (+211/-0) src/ui/dialog/lpe-powerstroke-properties.h (+99/-0) src/ui/dialog/objects.cpp (+2144/-0) src/ui/dialog/objects.h (+263/-0) src/ui/dialog/swatches.cpp (+32/-75) src/ui/dialog/swatches.h (+0/-2) src/ui/dialog/tags.cpp (+1165/-0) src/ui/dialog/tags.h (+181/-0) src/ui/tool/multi-path-manipulator.cpp (+3/-3) src/ui/tool/multi-path-manipulator.h (+1/-1) src/ui/tools/node-tool.cpp (+2/-1) src/ui/tools/pen-tool.cpp (+3/-1) src/ui/widget/Makefile_insert (+11/-2) src/ui/widget/addtoicon.cpp (+157/-0) src/ui/widget/addtoicon.h (+98/-0) src/ui/widget/clipmaskicon.cpp (+184/-0) src/ui/widget/clipmaskicon.h (+102/-0) src/ui/widget/filter-effect-chooser.cpp (+2/-0) src/ui/widget/filter-effect-chooser.h (+3/-1) src/ui/widget/highlight-picker.cpp (+214/-0) src/ui/widget/highlight-picker.h (+90/-0) src/ui/widget/insertordericon.cpp (+173/-0) src/ui/widget/insertordericon.h (+100/-0) src/ui/widget/layertypeicon.cpp (+174/-0) src/ui/widget/layertypeicon.h (+108/-0) src/verbs.cpp (+92/-1) src/verbs.h (+5/-0) src/widgets/desktop-widget.cpp (+1/-1) |
||||||||
To merge this branch: | bzr merge lp:~liampwhite/inkscape/inkscape | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Owens | Approve | ||
Johan Engelen | Pending | ||
Review via email: mp+225765@code.launchpad.net |
Commit message
Description of the change
Proposing to merge to watch progression of diff.
To post a comment you must log in.
lp:~liampwhite/inkscape/inkscape
updated
- 13179. By Liam P. White <inkscapebrony at-sign gmail dot com>
-
Update to experimental r13428
- 13180. By Liam P. White <inkscapebrony at-sign gmail dot com>
-
Update to experimental r13429
- 13181. By Liam P. White <inkscapebrony at-sign gmail dot com>
-
Duplicate LPE entries
- 13182. By Liam P. White <inkscapebrony at-sign gmail dot com>
-
Update to experimental r13436
- 13183. By Liam P. White <inkscapebrony at-sign gmail dot com>
-
This file does not need executable permissions
- 13184. By Liam P. White <inkscapebrony at-sign gmail dot com>
-
Refactoring of linejoin code
- 13185. By Liam P. White
-
Update to experimental r13452
- 13186. By Liam P. White
-
Fix make check
- 13187. By Liam P. White
-
I'm an idiot
- 13188. By Liam P. White
-
Update to experimental r13460
- 13189. By Liam P. White
-
Update to experimental r13464
- 13190. By Liam P. White
-
Messed up German translation (??)
- 13191. By Liam P. White
-
Ponyscape feature: finish pen drawing on context switch
- 13192. By Liam P. White
-
Update to experimental r13465
- 13193. By Liam P. White
-
Update to experimental r13479
- 13194. By Liam P. White
-
Clone Original -> Fill Between Many
- 13195. By Liam P. White
-
Update to experimental r13483
- 13196. By Liam P. White
-
Update to experimental r13531
- 13197. By Liam P. White
-
Fix gtk3 build
- 13198. By Liam P. White
-
Update to experimental r13543
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'po/POTFILES.in' | |||
2 | --- po/POTFILES.in 2014-08-30 15:50:55 +0000 | |||
3 | +++ po/POTFILES.in 2014-09-07 17:02:32 +0000 | |||
4 | @@ -153,7 +153,18 @@ | |||
5 | 153 | src/live_effects/lpe-skeleton.cpp | 153 | src/live_effects/lpe-skeleton.cpp |
6 | 154 | src/live_effects/lpe-sketch.cpp | 154 | src/live_effects/lpe-sketch.cpp |
7 | 155 | src/live_effects/lpe-vonkoch.cpp | 155 | src/live_effects/lpe-vonkoch.cpp |
8 | 156 | src/live_effects/lpe-envelope-perspective.cpp | ||
9 | 157 | src/live_effects/lpe-attach-path.cpp | ||
10 | 158 | src/live_effects/lpe-bounding-box.cpp | ||
11 | 159 | src/live_effects/lpe-ellipse_5pts.cpp | ||
12 | 160 | src/live_effects/lpe-fill-between-many.cpp | ||
13 | 161 | src/live_effects/lpe-fill-between-strokes.cpp | ||
14 | 162 | src/live_effects/lpe-jointype.cpp | ||
15 | 163 | src/live_effects/lpe-taperstroke.cpp | ||
16 | 164 | src/live_effects/lpe-fillet-chamfer.cpp | ||
17 | 156 | src/live_effects/parameter/filletchamferpointarray.cpp | 165 | src/live_effects/parameter/filletchamferpointarray.cpp |
18 | 166 | src/live_effects/parameter/originalpatharray.cpp | ||
19 | 167 | src/live_effects/parameter/transformedpoint.cpp | ||
20 | 157 | src/live_effects/parameter/pointreseteable.cpp | 168 | src/live_effects/parameter/pointreseteable.cpp |
21 | 158 | src/live_effects/parameter/togglebutton.cpp | 169 | src/live_effects/parameter/togglebutton.cpp |
22 | 159 | src/live_effects/parameter/bool.cpp | 170 | src/live_effects/parameter/bool.cpp |
23 | @@ -260,6 +271,10 @@ | |||
24 | 260 | src/ui/dialog/tracedialog.cpp | 271 | src/ui/dialog/tracedialog.cpp |
25 | 261 | src/ui/dialog/transformation.cpp | 272 | src/ui/dialog/transformation.cpp |
26 | 262 | src/ui/dialog/xml-tree.cpp | 273 | src/ui/dialog/xml-tree.cpp |
27 | 274 | src/ui/dialog/lpe-fillet-chamfer-properties.cpp | ||
28 | 275 | src/ui/dialog/lpe-powerstroke-properties.cpp | ||
29 | 276 | src/ui/dialog/objects.cpp | ||
30 | 277 | src/ui/dialog/tags.cpp | ||
31 | 263 | src/ui/tool/curve-drag-point.cpp | 278 | src/ui/tool/curve-drag-point.cpp |
32 | 264 | src/ui/tool/multi-path-manipulator.cpp | 279 | src/ui/tool/multi-path-manipulator.cpp |
33 | 265 | src/ui/tool/node.cpp | 280 | src/ui/tool/node.cpp |
34 | 266 | 281 | ||
35 | === modified file 'src/Makefile_insert' | |||
36 | --- src/Makefile_insert 2014-08-31 18:17:26 +0000 | |||
37 | +++ src/Makefile_insert 2014-09-07 17:02:32 +0000 | |||
38 | @@ -199,6 +199,9 @@ | |||
39 | 199 | sp-style-elem.cpp sp-style-elem.h \ | 199 | sp-style-elem.cpp sp-style-elem.h \ |
40 | 200 | sp-switch.cpp sp-switch.h \ | 200 | sp-switch.cpp sp-switch.h \ |
41 | 201 | sp-symbol.cpp sp-symbol.h \ | 201 | sp-symbol.cpp sp-symbol.h \ |
42 | 202 | sp-tag.cpp sp-tag.h \ | ||
43 | 203 | sp-tag-use.cpp sp-tag-use.h \ | ||
44 | 204 | sp-tag-use-reference.cpp sp-tag-use-reference.h \ | ||
45 | 202 | sp-text.cpp sp-text.h \ | 205 | sp-text.cpp sp-text.h \ |
46 | 203 | sp-textpath.h \ | 206 | sp-textpath.h \ |
47 | 204 | sp-title.cpp sp-title.h \ | 207 | sp-title.cpp sp-title.h \ |
48 | 205 | 208 | ||
49 | === modified file 'src/attributes.cpp' | |||
50 | --- src/attributes.cpp 2014-08-18 20:19:55 +0000 | |||
51 | +++ src/attributes.cpp 2014-09-07 17:02:32 +0000 | |||
52 | @@ -40,6 +40,7 @@ | |||
53 | 40 | {SP_ATTR_TRANSFORM_CENTER_X, "inkscape:transform-center-x"}, | 40 | {SP_ATTR_TRANSFORM_CENTER_X, "inkscape:transform-center-x"}, |
54 | 41 | {SP_ATTR_TRANSFORM_CENTER_Y, "inkscape:transform-center-y"}, | 41 | {SP_ATTR_TRANSFORM_CENTER_Y, "inkscape:transform-center-y"}, |
55 | 42 | {SP_ATTR_INKSCAPE_PATH_EFFECT, "inkscape:path-effect"}, | 42 | {SP_ATTR_INKSCAPE_PATH_EFFECT, "inkscape:path-effect"}, |
56 | 43 | {SP_ATTR_INKSCAPE_HIGHLIGHT_COLOR, "inkscape:highlight-color"}, | ||
57 | 43 | /* SPAnchor */ | 44 | /* SPAnchor */ |
58 | 44 | {SP_ATTR_XLINK_HREF, "xlink:href"}, | 45 | {SP_ATTR_XLINK_HREF, "xlink:href"}, |
59 | 45 | {SP_ATTR_XLINK_TYPE, "xlink:type"}, | 46 | {SP_ATTR_XLINK_TYPE, "xlink:type"}, |
60 | @@ -50,6 +51,7 @@ | |||
61 | 50 | {SP_ATTR_XLINK_ACTUATE, "xlink:actuate"}, | 51 | {SP_ATTR_XLINK_ACTUATE, "xlink:actuate"}, |
62 | 51 | {SP_ATTR_TARGET, "target"}, | 52 | {SP_ATTR_TARGET, "target"}, |
63 | 52 | {SP_ATTR_INKSCAPE_GROUPMODE, "inkscape:groupmode"}, | 53 | {SP_ATTR_INKSCAPE_GROUPMODE, "inkscape:groupmode"}, |
64 | 54 | {SP_ATTR_INKSCAPE_EXPANDED, "inkscape:expanded"}, | ||
65 | 53 | /* SPRoot */ | 55 | /* SPRoot */ |
66 | 54 | {SP_ATTR_VERSION, "version"}, | 56 | {SP_ATTR_VERSION, "version"}, |
67 | 55 | {SP_ATTR_WIDTH, "width"}, | 57 | {SP_ATTR_WIDTH, "width"}, |
68 | 56 | 58 | ||
69 | === modified file 'src/attributes.h' | |||
70 | --- src/attributes.h 2014-08-04 16:19:41 +0000 | |||
71 | +++ src/attributes.h 2014-09-07 17:02:32 +0000 | |||
72 | @@ -40,6 +40,7 @@ | |||
73 | 40 | SP_ATTR_TRANSFORM_CENTER_X, | 40 | SP_ATTR_TRANSFORM_CENTER_X, |
74 | 41 | SP_ATTR_TRANSFORM_CENTER_Y, | 41 | SP_ATTR_TRANSFORM_CENTER_Y, |
75 | 42 | SP_ATTR_INKSCAPE_PATH_EFFECT, | 42 | SP_ATTR_INKSCAPE_PATH_EFFECT, |
76 | 43 | SP_ATTR_INKSCAPE_HIGHLIGHT_COLOR, | ||
77 | 43 | /* SPAnchor */ | 44 | /* SPAnchor */ |
78 | 44 | SP_ATTR_XLINK_HREF, | 45 | SP_ATTR_XLINK_HREF, |
79 | 45 | SP_ATTR_XLINK_TYPE, | 46 | SP_ATTR_XLINK_TYPE, |
80 | @@ -51,6 +52,7 @@ | |||
81 | 51 | SP_ATTR_TARGET, | 52 | SP_ATTR_TARGET, |
82 | 52 | /* SPGroup */ | 53 | /* SPGroup */ |
83 | 53 | SP_ATTR_INKSCAPE_GROUPMODE, | 54 | SP_ATTR_INKSCAPE_GROUPMODE, |
84 | 55 | SP_ATTR_INKSCAPE_EXPANDED, | ||
85 | 54 | /* SPRoot */ | 56 | /* SPRoot */ |
86 | 55 | SP_ATTR_VERSION, | 57 | SP_ATTR_VERSION, |
87 | 56 | SP_ATTR_WIDTH, | 58 | SP_ATTR_WIDTH, |
88 | 57 | 59 | ||
89 | === modified file 'src/display/cairo-utils.cpp' | |||
90 | --- src/display/cairo-utils.cpp 2014-09-06 15:25:51 +0000 | |||
91 | +++ src/display/cairo-utils.cpp 2014-09-07 17:02:32 +0000 | |||
92 | @@ -33,8 +33,6 @@ | |||
93 | 33 | #include "helper/geom-curves.h" | 33 | #include "helper/geom-curves.h" |
94 | 34 | #include "display/cairo-templates.h" | 34 | #include "display/cairo-templates.h" |
95 | 35 | 35 | ||
96 | 36 | static void ink_cairo_pixbuf_cleanup(guchar *, void *); | ||
97 | 37 | |||
98 | 38 | /** | 36 | /** |
99 | 39 | * Key for cairo_surface_t to keep track of current color interpolation value | 37 | * Key for cairo_surface_t to keep track of current color interpolation value |
100 | 40 | * Only the address of the structure is used, it is never initialized. See: | 38 | * Only the address of the structure is used, it is never initialized. See: |
101 | @@ -1172,7 +1170,7 @@ | |||
102 | 1172 | * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by | 1170 | * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by |
103 | 1173 | * a Cairo surface. | 1171 | * a Cairo surface. |
104 | 1174 | */ | 1172 | */ |
106 | 1175 | static void ink_cairo_pixbuf_cleanup(guchar * /*pixels*/, void *data) | 1173 | void ink_cairo_pixbuf_cleanup(guchar * /*pixels*/, void *data) |
107 | 1176 | { | 1174 | { |
108 | 1177 | cairo_surface_t *surface = static_cast<cairo_surface_t*>(data); | 1175 | cairo_surface_t *surface = static_cast<cairo_surface_t*>(data); |
109 | 1178 | cairo_surface_destroy(surface); | 1176 | cairo_surface_destroy(surface); |
110 | 1179 | 1177 | ||
111 | === modified file 'src/display/cairo-utils.h' | |||
112 | --- src/display/cairo-utils.h 2014-08-30 17:23:17 +0000 | |||
113 | +++ src/display/cairo-utils.h 2014-09-07 17:02:32 +0000 | |||
114 | @@ -20,6 +20,9 @@ | |||
115 | 20 | struct SPColor; | 20 | struct SPColor; |
116 | 21 | typedef struct _GdkPixbuf GdkPixbuf; | 21 | typedef struct _GdkPixbuf GdkPixbuf; |
117 | 22 | 22 | ||
118 | 23 | void ink_cairo_pixbuf_cleanup(unsigned char *, void *); | ||
119 | 24 | void convert_pixbuf_argb32_to_normal(GdkPixbuf *pb); | ||
120 | 25 | |||
121 | 23 | namespace Inkscape { | 26 | namespace Inkscape { |
122 | 24 | 27 | ||
123 | 25 | /** | 28 | /** |
124 | 26 | 29 | ||
125 | === modified file 'src/display/drawing-item.cpp' | |||
126 | --- src/display/drawing-item.cpp 2014-08-18 21:18:05 +0000 | |||
127 | +++ src/display/drawing-item.cpp 2014-09-07 17:02:32 +0000 | |||
128 | @@ -825,9 +825,10 @@ | |||
129 | 825 | { | 825 | { |
130 | 826 | // Sometimes there's no BBOX in state, reason unknown (bug 992817) | 826 | // Sometimes there's no BBOX in state, reason unknown (bug 992817) |
131 | 827 | // I made this not an assert to remove the warning | 827 | // I made this not an assert to remove the warning |
132 | 828 | // This warning clutters the console output, so commented out | ||
133 | 828 | if (!(_state & STATE_BBOX) || !(_state & STATE_PICK)) { | 829 | if (!(_state & STATE_BBOX) || !(_state & STATE_PICK)) { |
136 | 829 | g_warning("Invalid state when picking: STATE_BBOX = %d, STATE_PICK = %d", | 830 | /*g_warning("Invalid state when picking: STATE_BBOX = %d, STATE_PICK = %d", |
137 | 830 | _state & STATE_BBOX, _state & STATE_PICK); | 831 | _state & STATE_BBOX, _state & STATE_PICK);*/ |
138 | 831 | return NULL; | 832 | return NULL; |
139 | 832 | } | 833 | } |
140 | 833 | // ignore invisible and insensitive items unless sticky | 834 | // ignore invisible and insensitive items unless sticky |
141 | 834 | 835 | ||
142 | === modified file 'src/display/sp-canvas.cpp' | |||
143 | --- src/display/sp-canvas.cpp 2014-08-26 11:14:18 +0000 | |||
144 | +++ src/display/sp-canvas.cpp 2014-09-07 17:02:32 +0000 | |||
145 | @@ -1146,7 +1146,7 @@ | |||
146 | 1146 | sp_canvas_init(SPCanvas *canvas) | 1146 | sp_canvas_init(SPCanvas *canvas) |
147 | 1147 | { | 1147 | { |
148 | 1148 | gtk_widget_set_has_window (GTK_WIDGET (canvas), TRUE); | 1148 | gtk_widget_set_has_window (GTK_WIDGET (canvas), TRUE); |
150 | 1149 | //gtk_widget_set_double_buffered (GTK_WIDGET (canvas), TRUE); | 1149 | gtk_widget_set_double_buffered (GTK_WIDGET (canvas), FALSE); |
151 | 1150 | gtk_widget_set_can_focus (GTK_WIDGET (canvas), TRUE); | 1150 | gtk_widget_set_can_focus (GTK_WIDGET (canvas), TRUE); |
152 | 1151 | 1151 | ||
153 | 1152 | canvas->pick_event.type = GDK_LEAVE_NOTIFY; | 1152 | canvas->pick_event.type = GDK_LEAVE_NOTIFY; |
154 | 1153 | 1153 | ||
155 | === modified file 'src/interface.cpp' | |||
156 | --- src/interface.cpp 2014-09-02 21:14:55 +0000 | |||
157 | +++ src/interface.cpp 2014-09-07 17:02:32 +0000 | |||
158 | @@ -1756,6 +1756,13 @@ | |||
159 | 1756 | } | 1756 | } |
160 | 1757 | mi->show(); | 1757 | mi->show(); |
161 | 1758 | append(*mi); | 1758 | append(*mi); |
162 | 1759 | |||
163 | 1760 | /*SSet Clip Group */ | ||
164 | 1761 | mi = Gtk::manage(new Gtk::MenuItem(_("Create Clip G_roup"),1)); | ||
165 | 1762 | mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::CreateGroupClip)); | ||
166 | 1763 | mi->set_sensitive(TRUE); | ||
167 | 1764 | mi->show(); | ||
168 | 1765 | append(*mi); | ||
169 | 1759 | 1766 | ||
170 | 1760 | /* Set Clip */ | 1767 | /* Set Clip */ |
171 | 1761 | mi = Gtk::manage(new Gtk::MenuItem(_("Set Cl_ip"), 1)); | 1768 | mi = Gtk::manage(new Gtk::MenuItem(_("Set Cl_ip"), 1)); |
172 | @@ -1867,6 +1874,10 @@ | |||
173 | 1867 | sp_selection_unset_mask(_desktop, false); | 1874 | sp_selection_unset_mask(_desktop, false); |
174 | 1868 | } | 1875 | } |
175 | 1869 | 1876 | ||
176 | 1877 | void ContextMenu::CreateGroupClip(void) | ||
177 | 1878 | { | ||
178 | 1879 | sp_selection_set_clipgroup(_desktop); | ||
179 | 1880 | } | ||
180 | 1870 | 1881 | ||
181 | 1871 | void ContextMenu::SetClip(void) | 1882 | void ContextMenu::SetClip(void) |
182 | 1872 | { | 1883 | { |
183 | 1873 | 1884 | ||
184 | === modified file 'src/interface.h' | |||
185 | --- src/interface.h 2014-08-31 18:17:26 +0000 | |||
186 | +++ src/interface.h 2014-09-07 17:02:32 +0000 | |||
187 | @@ -183,6 +183,7 @@ | |||
188 | 183 | void SelectSameStrokeStyle(void); | 183 | void SelectSameStrokeStyle(void); |
189 | 184 | void SelectSameObjectType(void); | 184 | void SelectSameObjectType(void); |
190 | 185 | void ItemCreateLink(void); | 185 | void ItemCreateLink(void); |
191 | 186 | void CreateGroupClip(void); | ||
192 | 186 | void SetMask(void); | 187 | void SetMask(void); |
193 | 187 | void ReleaseMask(void); | 188 | void ReleaseMask(void); |
194 | 188 | void SetClip(void); | 189 | void SetClip(void); |
195 | 189 | 190 | ||
196 | === modified file 'src/knotholder.cpp' | |||
197 | --- src/knotholder.cpp 2014-08-04 16:10:37 +0000 | |||
198 | +++ src/knotholder.cpp 2014-09-07 17:02:32 +0000 | |||
199 | @@ -154,8 +154,15 @@ | |||
200 | 154 | } | 154 | } |
201 | 155 | 155 | ||
202 | 156 | // for drag, this is done by ungrabbed_handler, but for click we must do it here | 156 | // for drag, this is done by ungrabbed_handler, but for click we must do it here |
205 | 157 | DocumentUndo::done(saved_item->document, object_verb, | 157 | |
206 | 158 | _("Change handle")); | 158 | if (saved_item) { //increasingly aggressive sanity checks |
207 | 159 | if (saved_item->document) { | ||
208 | 160 | if (object_verb <= SP_VERB_LAST && object_verb >= SP_VERB_INVALID) { | ||
209 | 161 | DocumentUndo::done(saved_item->document, object_verb, | ||
210 | 162 | _("Change handle")); | ||
211 | 163 | } | ||
212 | 164 | } | ||
213 | 165 | } // else { abort(); } | ||
214 | 159 | } | 166 | } |
215 | 160 | 167 | ||
216 | 161 | void | 168 | void |
217 | @@ -203,14 +210,16 @@ | |||
218 | 203 | /* do cleanup tasks (e.g., for LPE items write the parameter values | 210 | /* do cleanup tasks (e.g., for LPE items write the parameter values |
219 | 204 | * that were changed by dragging the handle to SVG) | 211 | * that were changed by dragging the handle to SVG) |
220 | 205 | */ | 212 | */ |
222 | 206 | if (SP_IS_LPE_ITEM(object)) { | 213 | if (dynamic_cast<SPLPEItem*> (object)) { |
223 | 207 | // This writes all parameters to SVG. Is this sufficiently efficient or should we only | 214 | // This writes all parameters to SVG. Is this sufficiently efficient or should we only |
224 | 208 | // write the ones that were changed? | 215 | // write the ones that were changed? |
230 | 209 | 216 | SPLPEItem * lpeitem = SP_LPE_ITEM(object); | |
231 | 210 | Inkscape::LivePathEffect::Effect *lpe = SP_LPE_ITEM(object)->getCurrentLPE(); | 217 | if (lpeitem) { |
232 | 211 | if (lpe) { | 218 | Inkscape::LivePathEffect::Effect *lpe = lpeitem->getCurrentLPE(); |
233 | 212 | LivePathEffectObject *lpeobj = lpe->getLPEObj(); | 219 | if (lpe) { |
234 | 213 | lpeobj->updateRepr(); | 220 | LivePathEffectObject *lpeobj = lpe->getLPEObj(); |
235 | 221 | lpeobj->updateRepr(); | ||
236 | 222 | } | ||
237 | 214 | } | 223 | } |
238 | 215 | } | 224 | } |
239 | 216 | 225 | ||
240 | @@ -232,9 +241,14 @@ | |||
241 | 232 | else | 241 | else |
242 | 233 | object_verb = SP_VERB_SELECTION_DYNAMIC_OFFSET; | 242 | object_verb = SP_VERB_SELECTION_DYNAMIC_OFFSET; |
243 | 234 | } | 243 | } |
247 | 235 | 244 | if (object) { //increasingly aggressive sanity checks | |
248 | 236 | DocumentUndo::done(object->document, object_verb, | 245 | if (object->document) { |
249 | 237 | _("Move handle")); | 246 | if (object_verb <= SP_VERB_LAST && object_verb >= SP_VERB_INVALID) { |
250 | 247 | DocumentUndo::done(object->document, object_verb, | ||
251 | 248 | _("Move handle")); | ||
252 | 249 | } | ||
253 | 250 | } | ||
254 | 251 | } //else { abort(); } | ||
255 | 238 | } | 252 | } |
256 | 239 | } | 253 | } |
257 | 240 | 254 | ||
258 | 241 | 255 | ||
259 | === modified file 'src/live_effects/CMakeLists.txt' | |||
260 | --- src/live_effects/CMakeLists.txt 2014-08-12 22:30:34 +0000 | |||
261 | +++ src/live_effects/CMakeLists.txt 2014-09-07 17:02:32 +0000 | |||
262 | @@ -2,8 +2,10 @@ | |||
263 | 2 | set(live_effects_SRC | 2 | set(live_effects_SRC |
264 | 3 | effect.cpp | 3 | effect.cpp |
265 | 4 | lpe-angle_bisector.cpp | 4 | lpe-angle_bisector.cpp |
266 | 5 | lpe-attach-path.cpp | ||
267 | 5 | lpe-bendpath.cpp | 6 | lpe-bendpath.cpp |
268 | 6 | lpe-boolops.cpp | 7 | lpe-boolops.cpp |
269 | 8 | lpe-bounding-box.cpp | ||
270 | 7 | lpe-circle_3pts.cpp | 9 | lpe-circle_3pts.cpp |
271 | 8 | lpe-circle_with_radius.cpp | 10 | lpe-circle_with_radius.cpp |
272 | 9 | lpe-clone-original.cpp | 11 | lpe-clone-original.cpp |
273 | @@ -11,9 +13,12 @@ | |||
274 | 11 | lpe-copy_rotate.cpp | 13 | lpe-copy_rotate.cpp |
275 | 12 | lpe-curvestitch.cpp | 14 | lpe-curvestitch.cpp |
276 | 13 | lpe-dynastroke.cpp | 15 | lpe-dynastroke.cpp |
277 | 16 | lpe-ellipse-5pts.cpp | ||
278 | 14 | lpe-envelope.cpp | 17 | lpe-envelope.cpp |
279 | 15 | lpe-envelope-perspective.cpp | 18 | lpe-envelope-perspective.cpp |
280 | 16 | lpe-extrude.cpp | 19 | lpe-extrude.cpp |
281 | 20 | lpe-fill-between-many.cpp | ||
282 | 21 | lpe-fill-between-strokes.cpp | ||
283 | 17 | lpe-fillet-chamfer.cpp | 22 | lpe-fillet-chamfer.cpp |
284 | 18 | lpe-gears.cpp | 23 | lpe-gears.cpp |
285 | 19 | lpe-interpolate.cpp | 24 | lpe-interpolate.cpp |
286 | @@ -55,11 +60,13 @@ | |||
287 | 55 | parameter/parameter.cpp | 60 | parameter/parameter.cpp |
288 | 56 | parameter/path.cpp | 61 | parameter/path.cpp |
289 | 57 | parameter/originalpath.cpp | 62 | parameter/originalpath.cpp |
290 | 63 | parameter/originalpatharray.cpp | ||
291 | 58 | parameter/path-reference.cpp | 64 | parameter/path-reference.cpp |
292 | 59 | parameter/point.cpp | 65 | parameter/point.cpp |
293 | 60 | parameter/powerstrokepointarray.cpp | 66 | parameter/powerstrokepointarray.cpp |
294 | 61 | parameter/random.cpp | 67 | parameter/random.cpp |
295 | 62 | parameter/text.cpp | 68 | parameter/text.cpp |
296 | 69 | paramter/transformedpoint.cpp | ||
297 | 63 | parameter/togglebutton.cpp | 70 | parameter/togglebutton.cpp |
298 | 64 | parameter/unit.cpp | 71 | parameter/unit.cpp |
299 | 65 | parameter/vector.cpp | 72 | parameter/vector.cpp |
300 | @@ -70,8 +77,10 @@ | |||
301 | 70 | effect-enum.h | 77 | effect-enum.h |
302 | 71 | effect.h | 78 | effect.h |
303 | 72 | lpe-angle_bisector.h | 79 | lpe-angle_bisector.h |
304 | 80 | lpe-attach-path.h | ||
305 | 73 | lpe-bendpath.h | 81 | lpe-bendpath.h |
306 | 74 | lpe-boolops.h | 82 | lpe-boolops.h |
307 | 83 | lpe-bounding-box.h | ||
308 | 75 | lpe-circle_3pts.h | 84 | lpe-circle_3pts.h |
309 | 76 | lpe-circle_with_radius.h | 85 | lpe-circle_with_radius.h |
310 | 77 | lpe-clone-original.h | 86 | lpe-clone-original.h |
311 | @@ -79,8 +88,11 @@ | |||
312 | 79 | lpe-copy_rotate.h | 88 | lpe-copy_rotate.h |
313 | 80 | lpe-curvestitch.h | 89 | lpe-curvestitch.h |
314 | 81 | lpe-dynastroke.h | 90 | lpe-dynastroke.h |
315 | 91 | lpe-ellipse-5pts.h | ||
316 | 82 | lpe-envelope.h | 92 | lpe-envelope.h |
317 | 83 | lpe-extrude.h | 93 | lpe-extrude.h |
318 | 94 | lpe-fill-between-many.h | ||
319 | 95 | lpe-fill-between-strokes.h | ||
320 | 84 | lpe-fillet-chamfer.h | 96 | lpe-fillet-chamfer.h |
321 | 85 | lpe-gears.h | 97 | lpe-gears.h |
322 | 86 | lpe-interpolate.h | 98 | lpe-interpolate.h |
323 | @@ -125,6 +137,7 @@ | |||
324 | 125 | parameter/path-reference.h | 137 | parameter/path-reference.h |
325 | 126 | parameter/path.h | 138 | parameter/path.h |
326 | 127 | parameter/originalpath.h | 139 | parameter/originalpath.h |
327 | 140 | parameter/originalpatharray.h | ||
328 | 128 | parameter/point.h | 141 | parameter/point.h |
329 | 129 | parameter/powerstrokepointarray.h | 142 | parameter/powerstrokepointarray.h |
330 | 130 | parameter/random.h | 143 | parameter/random.h |
331 | 131 | 144 | ||
332 | === modified file 'src/live_effects/Makefile_insert' | |||
333 | --- src/live_effects/Makefile_insert 2014-08-23 16:39:36 +0000 | |||
334 | +++ src/live_effects/Makefile_insert 2014-09-07 17:02:32 +0000 | |||
335 | @@ -97,5 +97,21 @@ | |||
336 | 97 | live_effects/lpe-path_length.h \ | 97 | live_effects/lpe-path_length.h \ |
337 | 98 | live_effects/lpe-line_segment.cpp \ | 98 | live_effects/lpe-line_segment.cpp \ |
338 | 99 | live_effects/lpe-line_segment.h \ | 99 | live_effects/lpe-line_segment.h \ |
339 | 100 | live_effects/lpe-bounding-box.cpp \ | ||
340 | 101 | live_effects/lpe-bounding-box.h \ | ||
341 | 102 | live_effects/lpe-attach-path.cpp \ | ||
342 | 103 | live_effects/lpe-attach-path.h \ | ||
343 | 104 | live_effects/lpe-fill-between-strokes.cpp \ | ||
344 | 105 | live_effects/lpe-fill-between-strokes.h \ | ||
345 | 106 | live_effects/lpe-fill-between-many.cpp \ | ||
346 | 107 | live_effects/lpe-fill-between-many.h \ | ||
347 | 108 | live_effects/lpe-ellipse_5pts.cpp \ | ||
348 | 109 | live_effects/lpe-ellipse_5pts.h \ | ||
349 | 110 | live_effects/pathoutlineprovider.cpp \ | ||
350 | 111 | live_effects/pathoutlineprovider.h \ | ||
351 | 112 | live_effects/lpe-jointype.cpp \ | ||
352 | 113 | live_effects/lpe-jointype.h \ | ||
353 | 114 | live_effects/lpe-taperstroke.cpp \ | ||
354 | 115 | live_effects/lpe-taperstroke.h \ | ||
355 | 100 | live_effects/lpe-envelope-perspective.cpp \ | 116 | live_effects/lpe-envelope-perspective.cpp \ |
356 | 101 | live_effects/lpe-envelope-perspective.h | 117 | live_effects/lpe-envelope-perspective.h |
357 | 102 | 118 | ||
358 | === modified file 'src/live_effects/effect-enum.h' | |||
359 | --- src/live_effects/effect-enum.h 2014-08-23 16:39:36 +0000 | |||
360 | +++ src/live_effects/effect-enum.h 2014-09-07 17:02:32 +0000 | |||
361 | @@ -56,6 +56,13 @@ | |||
362 | 56 | EXTRUDE, | 56 | EXTRUDE, |
363 | 57 | POWERSTROKE, | 57 | POWERSTROKE, |
364 | 58 | CLONE_ORIGINAL, | 58 | CLONE_ORIGINAL, |
365 | 59 | ATTACH_PATH, | ||
366 | 60 | FILL_BETWEEN_STROKES, | ||
367 | 61 | FILL_BETWEEN_MANY, | ||
368 | 62 | ELLIPSE_5PTS, | ||
369 | 63 | BOUNDING_BOX, | ||
370 | 64 | JOIN_TYPE, | ||
371 | 65 | TAPER_STROKE, | ||
372 | 59 | ENVELOPE_PERSPECTIVE, | 66 | ENVELOPE_PERSPECTIVE, |
373 | 60 | FILLET_CHAMFER, | 67 | FILLET_CHAMFER, |
374 | 61 | 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) | 68 | 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) |
375 | 62 | 69 | ||
376 | === modified file 'src/live_effects/effect.cpp' | |||
377 | --- src/live_effects/effect.cpp 2014-08-23 16:39:36 +0000 | |||
378 | +++ src/live_effects/effect.cpp 2014-09-07 17:02:32 +0000 | |||
379 | @@ -5,6 +5,8 @@ | |||
380 | 5 | * Released under GNU GPL, read the file 'COPYING' for more information | 5 | * Released under GNU GPL, read the file 'COPYING' for more information |
381 | 6 | */ | 6 | */ |
382 | 7 | 7 | ||
383 | 8 | //#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects | ||
384 | 9 | |||
385 | 8 | #ifdef HAVE_CONFIG_H | 10 | #ifdef HAVE_CONFIG_H |
386 | 9 | # include "config.h" | 11 | # include "config.h" |
387 | 10 | #endif | 12 | #endif |
388 | @@ -19,7 +21,6 @@ | |||
389 | 19 | #include "live_effects/lpe-rough-hatches.h" | 21 | #include "live_effects/lpe-rough-hatches.h" |
390 | 20 | #include "live_effects/lpe-dynastroke.h" | 22 | #include "live_effects/lpe-dynastroke.h" |
391 | 21 | #include "live_effects/lpe-test-doEffect-stack.h" | 23 | #include "live_effects/lpe-test-doEffect-stack.h" |
392 | 22 | #include "live_effects/lpe-bspline.h" | ||
393 | 23 | #include "live_effects/lpe-gears.h" | 24 | #include "live_effects/lpe-gears.h" |
394 | 24 | #include "live_effects/lpe-curvestitch.h" | 25 | #include "live_effects/lpe-curvestitch.h" |
395 | 25 | #include "live_effects/lpe-circle_with_radius.h" | 26 | #include "live_effects/lpe-circle_with_radius.h" |
396 | @@ -51,6 +52,14 @@ | |||
397 | 51 | #include "live_effects/lpe-extrude.h" | 52 | #include "live_effects/lpe-extrude.h" |
398 | 52 | #include "live_effects/lpe-powerstroke.h" | 53 | #include "live_effects/lpe-powerstroke.h" |
399 | 53 | #include "live_effects/lpe-clone-original.h" | 54 | #include "live_effects/lpe-clone-original.h" |
400 | 55 | #include "live_effects/lpe-bspline.h" | ||
401 | 56 | #include "live_effects/lpe-attach-path.h" | ||
402 | 57 | #include "live_effects/lpe-fill-between-strokes.h" | ||
403 | 58 | #include "live_effects/lpe-fill-between-many.h" | ||
404 | 59 | #include "live_effects/lpe-ellipse_5pts.h" | ||
405 | 60 | #include "live_effects/lpe-bounding-box.h" | ||
406 | 61 | #include "live_effects/lpe-jointype.h" | ||
407 | 62 | #include "live_effects/lpe-taperstroke.h" | ||
408 | 54 | #include "live_effects/lpe-envelope-perspective.h" | 63 | #include "live_effects/lpe-envelope-perspective.h" |
409 | 55 | #include "live_effects/lpe-fillet-chamfer.h" | 64 | #include "live_effects/lpe-fillet-chamfer.h" |
410 | 56 | 65 | ||
411 | @@ -132,10 +141,18 @@ | |||
412 | 132 | {SHOW_HANDLES, N_("Show handles"), "show_handles"}, | 141 | {SHOW_HANDLES, N_("Show handles"), "show_handles"}, |
413 | 133 | {ROUGHEN, N_("Roughen"), "roughen"}, | 142 | {ROUGHEN, N_("Roughen"), "roughen"}, |
414 | 134 | {BSPLINE, N_("BSpline"), "bspline"}, | 143 | {BSPLINE, N_("BSpline"), "bspline"}, |
419 | 135 | {SIMPLIFY, N_("Simplify"), "simplify"}, | 144 | {JOIN_TYPE, N_("Join type"), "join_type"}, |
420 | 136 | {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, | 145 | {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, |
421 | 137 | // TRANSLATORS: "Envelope Perspective" should be equivalent to "perspective transformation" | 146 | /* Ponyscape */ |
422 | 138 | {ENVELOPE_PERSPECTIVE, N_("Envelope Perspective"), "envelope-perspective"}, | 147 | {ATTACH_PATH, N_("Attach path"), "attach_path"}, |
423 | 148 | {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, | ||
424 | 149 | {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, | ||
425 | 150 | {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, | ||
426 | 151 | {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, | ||
427 | 152 | /* 0.91 */ | ||
428 | 153 | {SIMPLIFY, N_("Simplify"), "simplify"}, | ||
429 | 154 | {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, | ||
430 | 155 | {ENVELOPE_PERSPECTIVE, N_("Envelope-Perspective"), "envelope-perspective"}, | ||
431 | 139 | {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, | 156 | {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, |
432 | 140 | {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, | 157 | {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, |
433 | 141 | }; | 158 | }; |
434 | @@ -267,6 +284,27 @@ | |||
435 | 267 | case CLONE_ORIGINAL: | 284 | case CLONE_ORIGINAL: |
436 | 268 | neweffect = static_cast<Effect*> ( new LPECloneOriginal(lpeobj) ); | 285 | neweffect = static_cast<Effect*> ( new LPECloneOriginal(lpeobj) ); |
437 | 269 | break; | 286 | break; |
438 | 287 | case ATTACH_PATH: | ||
439 | 288 | neweffect = static_cast<Effect*> ( new LPEAttachPath(lpeobj) ); | ||
440 | 289 | break; | ||
441 | 290 | case FILL_BETWEEN_STROKES: | ||
442 | 291 | neweffect = static_cast<Effect*> ( new LPEFillBetweenStrokes(lpeobj) ); | ||
443 | 292 | break; | ||
444 | 293 | case FILL_BETWEEN_MANY: | ||
445 | 294 | neweffect = static_cast<Effect*> ( new LPEFillBetweenMany(lpeobj) ); | ||
446 | 295 | break; | ||
447 | 296 | case ELLIPSE_5PTS: | ||
448 | 297 | neweffect = static_cast<Effect*> ( new LPEEllipse5Pts(lpeobj) ); | ||
449 | 298 | break; | ||
450 | 299 | case BOUNDING_BOX: | ||
451 | 300 | neweffect = static_cast<Effect*> ( new LPEBoundingBox(lpeobj) ); | ||
452 | 301 | break; | ||
453 | 302 | case JOIN_TYPE: | ||
454 | 303 | neweffect = static_cast<Effect*> ( new LPEJoinType(lpeobj) ); | ||
455 | 304 | break; | ||
456 | 305 | case TAPER_STROKE: | ||
457 | 306 | neweffect = static_cast<Effect*> ( new LPETaperStroke(lpeobj) ); | ||
458 | 307 | break; | ||
459 | 270 | case SIMPLIFY: | 308 | case SIMPLIFY: |
460 | 271 | neweffect = static_cast<Effect*> ( new LPESimplify(lpeobj) ); | 309 | neweffect = static_cast<Effect*> ( new LPESimplify(lpeobj) ); |
461 | 272 | break; | 310 | break; |
462 | @@ -286,7 +324,7 @@ | |||
463 | 286 | neweffect = static_cast<Effect*> ( new LPEShowHandles(lpeobj) ); | 324 | neweffect = static_cast<Effect*> ( new LPEShowHandles(lpeobj) ); |
464 | 287 | break; | 325 | break; |
465 | 288 | default: | 326 | default: |
467 | 289 | g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); | 327 | g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); |
468 | 290 | neweffect = NULL; | 328 | neweffect = NULL; |
469 | 291 | break; | 329 | break; |
470 | 292 | } | 330 | } |
471 | @@ -369,6 +407,33 @@ | |||
472 | 369 | //Do nothing for simple effects | 407 | //Do nothing for simple effects |
473 | 370 | } | 408 | } |
474 | 371 | 409 | ||
475 | 410 | void Effect::doAfterEffect (SPLPEItem const* lpeitem) | ||
476 | 411 | { | ||
477 | 412 | } | ||
478 | 413 | |||
479 | 414 | void Effect::doOnRemove (SPLPEItem const* lpeitem) | ||
480 | 415 | { | ||
481 | 416 | } | ||
482 | 417 | |||
483 | 418 | //secret impl methods (shhhh!) | ||
484 | 419 | void Effect::doOnApply_impl(SPLPEItem const* lpeitem) | ||
485 | 420 | { | ||
486 | 421 | sp_lpe_item = const_cast<SPLPEItem *>(lpeitem); | ||
487 | 422 | /*sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); | ||
488 | 423 | pathvector_before_effect = sp_curve->get_pathvector();*/ | ||
489 | 424 | doOnApply(lpeitem); | ||
490 | 425 | } | ||
491 | 426 | |||
492 | 427 | void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) | ||
493 | 428 | { | ||
494 | 429 | sp_lpe_item = const_cast<SPLPEItem *>(lpeitem); | ||
495 | 430 | //printf("(SPLPEITEM*) %p\n", sp_lpe_item); | ||
496 | 431 | sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); | ||
497 | 432 | pathvector_before_effect = sp_curve->get_pathvector(); | ||
498 | 433 | |||
499 | 434 | doBeforeEffect(lpeitem); | ||
500 | 435 | } | ||
501 | 436 | |||
502 | 372 | /** | 437 | /** |
503 | 373 | * Effects can have a parameter path set before they are applied by accepting a nonzero number of | 438 | * Effects can have a parameter path set before they are applied by accepting a nonzero number of |
504 | 374 | * mouse clicks. This method activates the pen context, which waits for the specified number of | 439 | * mouse clicks. This method activates the pen context, which waits for the specified number of |
505 | 375 | 440 | ||
506 | === modified file 'src/live_effects/effect.h' | |||
507 | --- src/live_effects/effect.h 2014-05-05 07:13:35 +0000 | |||
508 | +++ src/live_effects/effect.h 2014-09-07 17:02:32 +0000 | |||
509 | @@ -53,8 +53,16 @@ | |||
510 | 53 | 53 | ||
511 | 54 | EffectType effectType() const; | 54 | EffectType effectType() const; |
512 | 55 | 55 | ||
513 | 56 | //basically, to get this method called before the derived classes, a bit | ||
514 | 57 | //of indirection is needed. We first call these methods, then the below. | ||
515 | 58 | void doOnApply_impl(SPLPEItem const* lpeitem); | ||
516 | 59 | void doBeforeEffect_impl(SPLPEItem const* lpeitem); | ||
517 | 60 | |||
518 | 56 | virtual void doOnApply (SPLPEItem const* lpeitem); | 61 | virtual void doOnApply (SPLPEItem const* lpeitem); |
519 | 57 | virtual void doBeforeEffect (SPLPEItem const* lpeitem); | 62 | virtual void doBeforeEffect (SPLPEItem const* lpeitem); |
520 | 63 | |||
521 | 64 | virtual void doAfterEffect (SPLPEItem const* lpeitem); | ||
522 | 65 | virtual void doOnRemove (SPLPEItem const* lpeitem); | ||
523 | 58 | 66 | ||
524 | 59 | void writeParamsToSVG(); | 67 | void writeParamsToSVG(); |
525 | 60 | 68 | ||
526 | @@ -147,6 +155,9 @@ | |||
527 | 147 | // instead of normally 'splitting' the path into continuous pwd2 paths and calling doEffect_pwd2 for each. | 155 | // instead of normally 'splitting' the path into continuous pwd2 paths and calling doEffect_pwd2 for each. |
528 | 148 | bool concatenate_before_pwd2; | 156 | bool concatenate_before_pwd2; |
529 | 149 | 157 | ||
530 | 158 | SPLPEItem * sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. | ||
531 | 159 | SPCurve * sp_curve; | ||
532 | 160 | std::vector<Geom::Path> pathvector_before_effect; | ||
533 | 150 | private: | 161 | private: |
534 | 151 | bool provides_own_flash_paths; // if true, the standard flash path is suppressed | 162 | bool provides_own_flash_paths; // if true, the standard flash path is suppressed |
535 | 152 | 163 | ||
536 | 153 | 164 | ||
537 | === added file 'src/live_effects/lpe-attach-path.cpp' | |||
538 | --- src/live_effects/lpe-attach-path.cpp 1970-01-01 00:00:00 +0000 | |||
539 | +++ src/live_effects/lpe-attach-path.cpp 2014-09-07 17:02:32 +0000 | |||
540 | @@ -0,0 +1,198 @@ | |||
541 | 1 | /* | ||
542 | 2 | * Copyright (C) Johan Engelen 2012 <j.b.c.engelen@alumnus.utwente.nl> | ||
543 | 3 | * | ||
544 | 4 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
545 | 5 | */ | ||
546 | 6 | |||
547 | 7 | #include <glibmm/i18n.h> | ||
548 | 8 | #include <math.h> | ||
549 | 9 | |||
550 | 10 | #include "live_effects/lpe-attach-path.h" | ||
551 | 11 | |||
552 | 12 | #include "display/curve.h" | ||
553 | 13 | #include "sp-item.h" | ||
554 | 14 | #include "2geom/path.h" | ||
555 | 15 | #include "sp-shape.h" | ||
556 | 16 | #include "sp-text.h" | ||
557 | 17 | #include "2geom/bezier-curve.h" | ||
558 | 18 | #include "2geom/path-sink.h" | ||
559 | 19 | #include "parameter/parameter.h" | ||
560 | 20 | #include "live_effects/parameter/point.h" | ||
561 | 21 | #include "parameter/originalpath.h" | ||
562 | 22 | #include "2geom/affine.h" | ||
563 | 23 | |||
564 | 24 | namespace Inkscape { | ||
565 | 25 | namespace LivePathEffect { | ||
566 | 26 | |||
567 | 27 | LPEAttachPath::LPEAttachPath(LivePathEffectObject *lpeobject) : | ||
568 | 28 | Effect(lpeobject), | ||
569 | 29 | start_path(_("Start path:"), _("Path to attach to the start of this path"), "startpath", &wr, this), | ||
570 | 30 | start_path_position(_("Start path position:"), _("Position to attach path start to"), "startposition", &wr, this, 0.0), | ||
571 | 31 | start_path_curve_start(_("Start path curve start:"), _("Starting curve"), "startcurvestart", &wr, this, Geom::Point(20,0)/*, true*/), | ||
572 | 32 | start_path_curve_end(_("Start path curve end:"), _("Ending curve"), "startcurveend", &wr, this, Geom::Point(20,0)/*, true*/), | ||
573 | 33 | end_path(_("End path:"), _("Path to attach to the end of this path"), "endpath", &wr, this), | ||
574 | 34 | end_path_position(_("End path position:"), _("Position to attach path end to"), "endposition", &wr, this, 0.0), | ||
575 | 35 | end_path_curve_start(_("End path curve start:"), _("Starting curve"), "endcurvestart", &wr, this, Geom::Point(20,0)/*, true*/), | ||
576 | 36 | end_path_curve_end(_("End path curve end:"), _("Ending curve"), "endcurveend", &wr, this, Geom::Point(20,0)/*, true*/) | ||
577 | 37 | { | ||
578 | 38 | registerParameter( dynamic_cast<Parameter *>(&start_path) ); | ||
579 | 39 | registerParameter( dynamic_cast<Parameter *>(&start_path_position) ); | ||
580 | 40 | registerParameter( dynamic_cast<Parameter *>(&start_path_curve_start) ); | ||
581 | 41 | registerParameter( dynamic_cast<Parameter *>(&start_path_curve_end) ); | ||
582 | 42 | |||
583 | 43 | registerParameter( dynamic_cast<Parameter *>(&end_path) ); | ||
584 | 44 | registerParameter( dynamic_cast<Parameter *>(&end_path_position) ); | ||
585 | 45 | registerParameter( dynamic_cast<Parameter *>(&end_path_curve_start) ); | ||
586 | 46 | registerParameter( dynamic_cast<Parameter *>(&end_path_curve_end) ); | ||
587 | 47 | |||
588 | 48 | //perceived_path = true; | ||
589 | 49 | show_orig_path = true; | ||
590 | 50 | curve_start_previous_origin = start_path_curve_end.getOrigin(); | ||
591 | 51 | curve_end_previous_origin = end_path_curve_end.getOrigin(); | ||
592 | 52 | } | ||
593 | 53 | |||
594 | 54 | LPEAttachPath::~LPEAttachPath() | ||
595 | 55 | { | ||
596 | 56 | |||
597 | 57 | } | ||
598 | 58 | |||
599 | 59 | void LPEAttachPath::resetDefaults(SPItem const * item) | ||
600 | 60 | { | ||
601 | 61 | curve_start_previous_origin = start_path_curve_end.getOrigin(); | ||
602 | 62 | curve_end_previous_origin = end_path_curve_end.getOrigin(); | ||
603 | 63 | } | ||
604 | 64 | |||
605 | 65 | void LPEAttachPath::doEffect (SPCurve * curve) | ||
606 | 66 | { | ||
607 | 67 | std::vector<Geom::Path> this_pathv = curve->get_pathvector(); | ||
608 | 68 | if (sp_lpe_item && !this_pathv.empty()) { | ||
609 | 69 | Geom::Path p = Geom::Path(this_pathv.front().initialPoint()); | ||
610 | 70 | |||
611 | 71 | bool set_start_end = start_path_curve_end.getOrigin() != curve_start_previous_origin; | ||
612 | 72 | bool set_end_end = end_path_curve_end.getOrigin() != curve_end_previous_origin; | ||
613 | 73 | |||
614 | 74 | if (start_path.linksToPath()) { | ||
615 | 75 | |||
616 | 76 | std::vector<Geom::Path> linked_pathv = start_path.get_pathvector(); | ||
617 | 77 | Geom::Affine linkedtransform = start_path.getObject()->getRelativeTransform(sp_lpe_item); | ||
618 | 78 | |||
619 | 79 | if ( !linked_pathv.empty() ) | ||
620 | 80 | { | ||
621 | 81 | Geom::Path transformedpath = linked_pathv.front() * linkedtransform; | ||
622 | 82 | start_path_curve_start.setOrigin(this_pathv.front().initialPoint()); | ||
623 | 83 | |||
624 | 84 | std::vector<Geom::Point> derivs = this_pathv.front().front().pointAndDerivatives(0, 3); | ||
625 | 85 | |||
626 | 86 | for (unsigned deriv_n = 1; deriv_n < derivs.size(); deriv_n++) { | ||
627 | 87 | Geom::Coord length = derivs[deriv_n].length(); | ||
628 | 88 | if ( ! Geom::are_near(length, 0) ) { | ||
629 | 89 | if (set_start_end) { | ||
630 | 90 | start_path_position.param_set_value(transformedpath.nearestPoint(start_path_curve_end.getOrigin())); | ||
631 | 91 | } | ||
632 | 92 | |||
633 | 93 | if (start_path_position > transformedpath.size()) { | ||
634 | 94 | start_path_position.param_set_value(transformedpath.size()); | ||
635 | 95 | } else if (start_path_position < 0) { | ||
636 | 96 | start_path_position.param_set_value(0); | ||
637 | 97 | } | ||
638 | 98 | const Geom::Curve *c = start_path_position >= transformedpath.size() ? &transformedpath.back() : &transformedpath.at_index((int)start_path_position); | ||
639 | 99 | |||
640 | 100 | std::vector<Geom::Point> derivs_2 = c->pointAndDerivatives(start_path_position >= transformedpath.size() ? 1 : (start_path_position - (int)start_path_position), 3); | ||
641 | 101 | for (unsigned deriv_n_2 = 1; deriv_n_2 < derivs_2.size(); deriv_n_2++) { | ||
642 | 102 | Geom::Coord length_2 = derivs[deriv_n_2].length(); | ||
643 | 103 | if ( ! Geom::are_near(length_2, 0) ) { | ||
644 | 104 | start_path_curve_end.setOrigin(derivs_2[0]); | ||
645 | 105 | curve_start_previous_origin = start_path_curve_end.getOrigin(); | ||
646 | 106 | |||
647 | 107 | double startangle = atan2(start_path_curve_start.getVector().y(), start_path_curve_start.getVector().x()); | ||
648 | 108 | double endangle = atan2(start_path_curve_end.getVector().y(), start_path_curve_end.getVector().x()); | ||
649 | 109 | double startderiv = atan2(derivs[deriv_n].y(), derivs[deriv_n].x()); | ||
650 | 110 | double endderiv = atan2(derivs_2[deriv_n_2].y(), derivs_2[deriv_n_2].x()); | ||
651 | 111 | Geom::Point pt1 = Geom::Point(start_path_curve_start.getVector().length() * cos(startangle + startderiv), start_path_curve_start.getVector().length() * sin(startangle + startderiv)); | ||
652 | 112 | Geom::Point pt2 = Geom::Point(start_path_curve_end.getVector().length() * cos(endangle + endderiv), start_path_curve_end.getVector().length() * sin(endangle + endderiv)); | ||
653 | 113 | p = Geom::Path(derivs_2[0]); | ||
654 | 114 | p.appendNew<Geom::CubicBezier>(-pt2 + derivs_2[0], -pt1 + this_pathv.front().initialPoint(), this_pathv.front().initialPoint()); | ||
655 | 115 | break; | ||
656 | 116 | |||
657 | 117 | } | ||
658 | 118 | } | ||
659 | 119 | break; | ||
660 | 120 | } | ||
661 | 121 | } | ||
662 | 122 | } | ||
663 | 123 | } | ||
664 | 124 | |||
665 | 125 | p.append(this_pathv.front()); | ||
666 | 126 | |||
667 | 127 | if (end_path.linksToPath()) { | ||
668 | 128 | |||
669 | 129 | std::vector<Geom::Path> linked_pathv = end_path.get_pathvector(); | ||
670 | 130 | Geom::Affine linkedtransform = end_path.getObject()->getRelativeTransform(sp_lpe_item); | ||
671 | 131 | |||
672 | 132 | if ( !linked_pathv.empty() ) | ||
673 | 133 | { | ||
674 | 134 | Geom::Path transformedpath = linked_pathv.front() * linkedtransform; | ||
675 | 135 | Geom::Curve * last_seg_reverse = this_pathv.front().back().reverse(); | ||
676 | 136 | |||
677 | 137 | end_path_curve_start.setOrigin(last_seg_reverse->initialPoint()); | ||
678 | 138 | |||
679 | 139 | std::vector<Geom::Point> derivs = last_seg_reverse->pointAndDerivatives(0, 3); | ||
680 | 140 | for (unsigned deriv_n = 1; deriv_n < derivs.size(); deriv_n++) { | ||
681 | 141 | Geom::Coord length = derivs[deriv_n].length(); | ||
682 | 142 | if ( ! Geom::are_near(length, 0) ) { | ||
683 | 143 | if (set_end_end) { | ||
684 | 144 | end_path_position.param_set_value(transformedpath.nearestPoint(end_path_curve_end.getOrigin())); | ||
685 | 145 | } | ||
686 | 146 | |||
687 | 147 | if (end_path_position > transformedpath.size()) { | ||
688 | 148 | end_path_position.param_set_value(transformedpath.size()); | ||
689 | 149 | } else if (end_path_position < 0) { | ||
690 | 150 | end_path_position.param_set_value(0); | ||
691 | 151 | } | ||
692 | 152 | const Geom::Curve *c = end_path_position >= transformedpath.size() ? &transformedpath.back() : &transformedpath.at_index((int)end_path_position); | ||
693 | 153 | |||
694 | 154 | std::vector<Geom::Point> derivs_2 = c->pointAndDerivatives(end_path_position >= transformedpath.size() ? 1 : (end_path_position - (int)end_path_position), 3); | ||
695 | 155 | for (unsigned deriv_n_2 = 1; deriv_n_2 < derivs_2.size(); deriv_n_2++) { | ||
696 | 156 | Geom::Coord length_2 = derivs[deriv_n_2].length(); | ||
697 | 157 | if ( ! Geom::are_near(length_2, 0) ) { | ||
698 | 158 | |||
699 | 159 | end_path_curve_end.setOrigin(derivs_2[0]); | ||
700 | 160 | curve_end_previous_origin = end_path_curve_end.getOrigin(); | ||
701 | 161 | |||
702 | 162 | double startangle = atan2(end_path_curve_start.getVector().y(), end_path_curve_start.getVector().x()); | ||
703 | 163 | double endangle = atan2(end_path_curve_end.getVector().y(), end_path_curve_end.getVector().x()); | ||
704 | 164 | double startderiv = atan2(derivs[deriv_n].y(), derivs[deriv_n].x()); | ||
705 | 165 | double endderiv = atan2(derivs_2[deriv_n_2].y(), derivs_2[deriv_n_2].x()); | ||
706 | 166 | Geom::Point pt1 = Geom::Point(end_path_curve_start.getVector().length() * cos(startangle + startderiv), end_path_curve_start.getVector().length() * sin(startangle + startderiv)); | ||
707 | 167 | Geom::Point pt2 = Geom::Point(end_path_curve_end.getVector().length() * cos(endangle + endderiv), end_path_curve_end.getVector().length() * sin(endangle + endderiv)); | ||
708 | 168 | p.appendNew<Geom::CubicBezier>(-pt1 + this_pathv.front().finalPoint(), -pt2 + derivs_2[0], derivs_2[0]); | ||
709 | 169 | |||
710 | 170 | break; | ||
711 | 171 | |||
712 | 172 | } | ||
713 | 173 | } | ||
714 | 174 | break; | ||
715 | 175 | } | ||
716 | 176 | } | ||
717 | 177 | delete last_seg_reverse; | ||
718 | 178 | } | ||
719 | 179 | } | ||
720 | 180 | Geom::PathVector outvector; | ||
721 | 181 | outvector.push_back(p); | ||
722 | 182 | curve->set_pathvector(outvector); | ||
723 | 183 | } | ||
724 | 184 | } | ||
725 | 185 | |||
726 | 186 | } // namespace LivePathEffect | ||
727 | 187 | } /* namespace Inkscape */ | ||
728 | 188 | |||
729 | 189 | /* | ||
730 | 190 | Local Variables: | ||
731 | 191 | mode:c++ | ||
732 | 192 | c-file-style:"stroustrup" | ||
733 | 193 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
734 | 194 | indent-tabs-mode:nil | ||
735 | 195 | fill-column:99 | ||
736 | 196 | End: | ||
737 | 197 | */ | ||
738 | 198 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : | ||
739 | 0 | 199 | ||
740 | === added file 'src/live_effects/lpe-attach-path.h' | |||
741 | --- src/live_effects/lpe-attach-path.h 1970-01-01 00:00:00 +0000 | |||
742 | +++ src/live_effects/lpe-attach-path.h 2014-09-07 17:02:32 +0000 | |||
743 | @@ -0,0 +1,52 @@ | |||
744 | 1 | #ifndef INKSCAPE_LPE_ATTACH_PATH_H | ||
745 | 2 | #define INKSCAPE_LPE_ATTACH_PATH_H | ||
746 | 3 | |||
747 | 4 | /* | ||
748 | 5 | * Inkscape::LPEAttachPath | ||
749 | 6 | * | ||
750 | 7 | * Copyright (C) Ted Janeczko 2012 <flutterguy317@gmail.com> | ||
751 | 8 | * | ||
752 | 9 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
753 | 10 | */ | ||
754 | 11 | |||
755 | 12 | #include "live_effects/effect.h" | ||
756 | 13 | #include "live_effects/parameter/parameter.h" | ||
757 | 14 | #include "live_effects/parameter/point.h" | ||
758 | 15 | #include "live_effects/parameter/originalpath.h" | ||
759 | 16 | #include "live_effects/parameter/vector.h" | ||
760 | 17 | #include "live_effects/parameter/bool.h" | ||
761 | 18 | #include "live_effects/parameter/transformedpoint.h" | ||
762 | 19 | |||
763 | 20 | namespace Inkscape { | ||
764 | 21 | namespace LivePathEffect { | ||
765 | 22 | |||
766 | 23 | class LPEAttachPath : public Effect { | ||
767 | 24 | public: | ||
768 | 25 | LPEAttachPath(LivePathEffectObject *lpeobject); | ||
769 | 26 | virtual ~LPEAttachPath(); | ||
770 | 27 | |||
771 | 28 | virtual void doEffect (SPCurve * curve); | ||
772 | 29 | virtual void resetDefaults(SPItem const * item); | ||
773 | 30 | |||
774 | 31 | private: | ||
775 | 32 | LPEAttachPath(const LPEAttachPath&); | ||
776 | 33 | LPEAttachPath& operator=(const LPEAttachPath&); | ||
777 | 34 | |||
778 | 35 | Geom::Point curve_start_previous_origin; | ||
779 | 36 | Geom::Point curve_end_previous_origin; | ||
780 | 37 | |||
781 | 38 | OriginalPathParam start_path; | ||
782 | 39 | ScalarParam start_path_position; | ||
783 | 40 | TransformedPointParam start_path_curve_start; | ||
784 | 41 | VectorParam start_path_curve_end; | ||
785 | 42 | |||
786 | 43 | OriginalPathParam end_path; | ||
787 | 44 | ScalarParam end_path_position; | ||
788 | 45 | TransformedPointParam end_path_curve_start; | ||
789 | 46 | VectorParam end_path_curve_end; | ||
790 | 47 | }; | ||
791 | 48 | |||
792 | 49 | }; //namespace LivePathEffect | ||
793 | 50 | }; //namespace Inkscape | ||
794 | 51 | |||
795 | 52 | #endif | ||
796 | 0 | 53 | ||
797 | === added file 'src/live_effects/lpe-bounding-box.cpp' | |||
798 | --- src/live_effects/lpe-bounding-box.cpp 1970-01-01 00:00:00 +0000 | |||
799 | +++ src/live_effects/lpe-bounding-box.cpp 2014-09-07 17:02:32 +0000 | |||
800 | @@ -0,0 +1,67 @@ | |||
801 | 1 | /* | ||
802 | 2 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
803 | 3 | * | ||
804 | 4 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
805 | 5 | */ | ||
806 | 6 | |||
807 | 7 | #include <glibmm/i18n.h> | ||
808 | 8 | |||
809 | 9 | #include "live_effects/lpe-bounding-box.h" | ||
810 | 10 | |||
811 | 11 | #include "display/curve.h" | ||
812 | 12 | #include "sp-item.h" | ||
813 | 13 | #include "2geom/path.h" | ||
814 | 14 | #include "sp-shape.h" | ||
815 | 15 | #include "sp-text.h" | ||
816 | 16 | #include "2geom/bezier-curve.h" | ||
817 | 17 | #include "lpe-bounding-box.h" | ||
818 | 18 | |||
819 | 19 | namespace Inkscape { | ||
820 | 20 | namespace LivePathEffect { | ||
821 | 21 | |||
822 | 22 | LPEBoundingBox::LPEBoundingBox(LivePathEffectObject *lpeobject) : | ||
823 | 23 | Effect(lpeobject), | ||
824 | 24 | linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this), | ||
825 | 25 | visual_bounds(_("Visual Bounds"), _("Uses the visual bounding box"), "visualbounds", &wr, this) | ||
826 | 26 | { | ||
827 | 27 | registerParameter( dynamic_cast<Parameter *>(&linked_path) ); | ||
828 | 28 | registerParameter( dynamic_cast<Parameter *>(&visual_bounds) ); | ||
829 | 29 | //perceived_path = true; | ||
830 | 30 | } | ||
831 | 31 | |||
832 | 32 | LPEBoundingBox::~LPEBoundingBox() | ||
833 | 33 | { | ||
834 | 34 | |||
835 | 35 | } | ||
836 | 36 | |||
837 | 37 | void LPEBoundingBox::doEffect (SPCurve * curve) | ||
838 | 38 | { | ||
839 | 39 | if (curve) { | ||
840 | 40 | if ( linked_path.linksToPath() && linked_path.getObject() ) { | ||
841 | 41 | SPItem * item = linked_path.getObject(); | ||
842 | 42 | Geom::OptRect bbox = visual_bounds.get_value() ? item->visualBounds() : item->geometricBounds(); | ||
843 | 43 | Geom::Path p(Geom::Point(bbox->left(), bbox->top())); | ||
844 | 44 | p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->top())); | ||
845 | 45 | p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->bottom())); | ||
846 | 46 | p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->bottom())); | ||
847 | 47 | p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->top())); | ||
848 | 48 | std::vector<Geom::Path> out; | ||
849 | 49 | out.push_back(p); | ||
850 | 50 | curve->set_pathvector(out); | ||
851 | 51 | } | ||
852 | 52 | } | ||
853 | 53 | } | ||
854 | 54 | |||
855 | 55 | } // namespace LivePathEffect | ||
856 | 56 | } /* namespace Inkscape */ | ||
857 | 57 | |||
858 | 58 | /* | ||
859 | 59 | Local Variables: | ||
860 | 60 | mode:c++ | ||
861 | 61 | c-file-style:"stroustrup" | ||
862 | 62 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
863 | 63 | indent-tabs-mode:nil | ||
864 | 64 | fill-column:99 | ||
865 | 65 | End: | ||
866 | 66 | */ | ||
867 | 67 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : | ||
868 | 0 | 68 | ||
869 | === added file 'src/live_effects/lpe-bounding-box.h' | |||
870 | --- src/live_effects/lpe-bounding-box.h 1970-01-01 00:00:00 +0000 | |||
871 | +++ src/live_effects/lpe-bounding-box.h 2014-09-07 17:02:32 +0000 | |||
872 | @@ -0,0 +1,37 @@ | |||
873 | 1 | #ifndef INKSCAPE_LPE_BOUNDING_BOX_H | ||
874 | 2 | #define INKSCAPE_LPE_BOUNDING_BOX_H | ||
875 | 3 | |||
876 | 4 | /* | ||
877 | 5 | * Inkscape::LPEFillBetweenStrokes | ||
878 | 6 | * | ||
879 | 7 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
880 | 8 | * | ||
881 | 9 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
882 | 10 | */ | ||
883 | 11 | |||
884 | 12 | #include "live_effects/effect.h" | ||
885 | 13 | #include "live_effects/parameter/originalpath.h" | ||
886 | 14 | |||
887 | 15 | namespace Inkscape { | ||
888 | 16 | namespace LivePathEffect { | ||
889 | 17 | |||
890 | 18 | class LPEBoundingBox : public Effect { | ||
891 | 19 | public: | ||
892 | 20 | LPEBoundingBox(LivePathEffectObject *lpeobject); | ||
893 | 21 | virtual ~LPEBoundingBox(); | ||
894 | 22 | |||
895 | 23 | virtual void doEffect (SPCurve * curve); | ||
896 | 24 | |||
897 | 25 | private: | ||
898 | 26 | OriginalPathParam linked_path; | ||
899 | 27 | BoolParam visual_bounds; | ||
900 | 28 | |||
901 | 29 | private: | ||
902 | 30 | LPEBoundingBox(const LPEBoundingBox&); | ||
903 | 31 | LPEBoundingBox& operator=(const LPEBoundingBox&); | ||
904 | 32 | }; | ||
905 | 33 | |||
906 | 34 | }; //namespace LivePathEffect | ||
907 | 35 | }; //namespace Inkscape | ||
908 | 36 | |||
909 | 37 | #endif | ||
910 | 0 | 38 | ||
911 | === added file 'src/live_effects/lpe-ellipse_5pts.cpp' | |||
912 | --- src/live_effects/lpe-ellipse_5pts.cpp 1970-01-01 00:00:00 +0000 | |||
913 | +++ src/live_effects/lpe-ellipse_5pts.cpp 2014-09-07 17:02:32 +0000 | |||
914 | @@ -0,0 +1,214 @@ | |||
915 | 1 | /** \file | ||
916 | 2 | * LPE "Ellipse through 5 points" implementation | ||
917 | 3 | */ | ||
918 | 4 | |||
919 | 5 | /* | ||
920 | 6 | * Authors: | ||
921 | 7 | * Theodore Janeczko | ||
922 | 8 | * | ||
923 | 9 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
924 | 10 | * | ||
925 | 11 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
926 | 12 | */ | ||
927 | 13 | |||
928 | 14 | #include "live_effects/lpe-ellipse_5pts.h" | ||
929 | 15 | |||
930 | 16 | // You might need to include other 2geom files. You can add them here: | ||
931 | 17 | #include <glibmm/i18n.h> | ||
932 | 18 | #include <2geom/path.h> | ||
933 | 19 | #include <2geom/circle.h> | ||
934 | 20 | #include <2geom/ellipse.h> | ||
935 | 21 | #include <2geom/path-sink.h> | ||
936 | 22 | #include "inkscape.h" | ||
937 | 23 | #include "desktop.h" | ||
938 | 24 | #include "message-stack.h" | ||
939 | 25 | |||
940 | 26 | namespace Inkscape { | ||
941 | 27 | namespace LivePathEffect { | ||
942 | 28 | |||
943 | 29 | LPEEllipse5Pts::LPEEllipse5Pts(LivePathEffectObject *lpeobject) : | ||
944 | 30 | Effect(lpeobject) | ||
945 | 31 | { | ||
946 | 32 | //perceived_path = true; | ||
947 | 33 | } | ||
948 | 34 | |||
949 | 35 | LPEEllipse5Pts::~LPEEllipse5Pts() | ||
950 | 36 | { | ||
951 | 37 | } | ||
952 | 38 | |||
953 | 39 | static double _det3(double (*mat)[3]) | ||
954 | 40 | { | ||
955 | 41 | for (int i = 0; i < 2; i++) | ||
956 | 42 | { | ||
957 | 43 | for (int j = i + 1; j < 3; j++) | ||
958 | 44 | { | ||
959 | 45 | for (int k = i + 1; k < 3; k++) | ||
960 | 46 | { | ||
961 | 47 | mat[j][k] = (mat[j][k] * mat[i][i] - mat[j][i] * mat[i][k]); | ||
962 | 48 | if (i) mat[j][k] /= mat[i-1][i-1]; | ||
963 | 49 | } | ||
964 | 50 | } | ||
965 | 51 | } | ||
966 | 52 | return mat[2][2]; | ||
967 | 53 | } | ||
968 | 54 | static double _det5(double (*mat)[5]) | ||
969 | 55 | { | ||
970 | 56 | for (int i = 0; i < 4; i++) | ||
971 | 57 | { | ||
972 | 58 | for (int j = i + 1; j < 5; j++) | ||
973 | 59 | { | ||
974 | 60 | for (int k = i + 1; k < 5; k++) | ||
975 | 61 | { | ||
976 | 62 | mat[j][k] = (mat[j][k] * mat[i][i] - mat[j][i] * mat[i][k]); | ||
977 | 63 | if (i) mat[j][k] /= mat[i-1][i-1]; | ||
978 | 64 | } | ||
979 | 65 | } | ||
980 | 66 | } | ||
981 | 67 | return mat[4][4]; | ||
982 | 68 | } | ||
983 | 69 | |||
984 | 70 | std::vector<Geom::Path> | ||
985 | 71 | LPEEllipse5Pts::doEffect_path (std::vector<Geom::Path> const & path_in) | ||
986 | 72 | { | ||
987 | 73 | std::vector<Geom::Path> path_out = std::vector<Geom::Path>(); | ||
988 | 74 | |||
989 | 75 | if (path_in[0].size() < 4) { | ||
990 | 76 | |||
991 | 77 | SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Five points required for constructing an ellipse")); | ||
992 | 78 | return path_in; | ||
993 | 79 | } | ||
994 | 80 | // we assume that the path has >= 3 nodes | ||
995 | 81 | Geom::Point A = path_in[0].initialPoint(); | ||
996 | 82 | Geom::Point B = path_in[0].pointAt(1); | ||
997 | 83 | Geom::Point C = path_in[0].pointAt(2); | ||
998 | 84 | Geom::Point D = path_in[0].pointAt(3); | ||
999 | 85 | Geom::Point E = path_in[0].pointAt(4); | ||
1000 | 86 | |||
1001 | 87 | using namespace Geom; | ||
1002 | 88 | |||
1003 | 89 | double rowmajor_matrix[5][6] = | ||
1004 | 90 | { | ||
1005 | 91 | {A.x()*A.x(), A.x()*A.y(), A.y()*A.y(), A.x(), A.y(), 1}, | ||
1006 | 92 | {B.x()*B.x(), B.x()*B.y(), B.y()*B.y(), B.x(), B.y(), 1}, | ||
1007 | 93 | {C.x()*C.x(), C.x()*C.y(), C.y()*C.y(), C.x(), C.y(), 1}, | ||
1008 | 94 | {D.x()*D.x(), D.x()*D.y(), D.y()*D.y(), D.x(), D.y(), 1}, | ||
1009 | 95 | {E.x()*E.x(), E.x()*E.y(), E.y()*E.y(), E.x(), E.y(), 1} | ||
1010 | 96 | }; | ||
1011 | 97 | |||
1012 | 98 | double mat_a[5][5] = | ||
1013 | 99 | { | ||
1014 | 100 | {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, | ||
1015 | 101 | {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, | ||
1016 | 102 | {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, | ||
1017 | 103 | {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]}, | ||
1018 | 104 | {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} | ||
1019 | 105 | }; | ||
1020 | 106 | double mat_b[5][5] = | ||
1021 | 107 | { | ||
1022 | 108 | {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, | ||
1023 | 109 | {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, | ||
1024 | 110 | {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, | ||
1025 | 111 | {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]}, | ||
1026 | 112 | {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} | ||
1027 | 113 | }; | ||
1028 | 114 | double mat_c[5][5] = | ||
1029 | 115 | { | ||
1030 | 116 | {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, | ||
1031 | 117 | {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, | ||
1032 | 118 | {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, | ||
1033 | 119 | {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]}, | ||
1034 | 120 | {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} | ||
1035 | 121 | }; | ||
1036 | 122 | double mat_d[5][5] = | ||
1037 | 123 | { | ||
1038 | 124 | {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, | ||
1039 | 125 | {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, | ||
1040 | 126 | {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, | ||
1041 | 127 | {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]}, | ||
1042 | 128 | {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} | ||
1043 | 129 | }; | ||
1044 | 130 | double mat_e[5][5] = | ||
1045 | 131 | { | ||
1046 | 132 | {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, | ||
1047 | 133 | {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, | ||
1048 | 134 | {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, | ||
1049 | 135 | {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, | ||
1050 | 136 | {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} | ||
1051 | 137 | }; | ||
1052 | 138 | double mat_f[5][5] = | ||
1053 | 139 | { | ||
1054 | 140 | {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, | ||
1055 | 141 | {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, | ||
1056 | 142 | {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, | ||
1057 | 143 | {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, | ||
1058 | 144 | {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]} | ||
1059 | 145 | }; | ||
1060 | 146 | |||
1061 | 147 | double a1 = _det5(mat_a); | ||
1062 | 148 | double b1 = -_det5(mat_b); | ||
1063 | 149 | double c1 = _det5(mat_c); | ||
1064 | 150 | double d1 = -_det5(mat_d); | ||
1065 | 151 | double e1 = _det5(mat_e); | ||
1066 | 152 | double f1 = -_det5(mat_f); | ||
1067 | 153 | |||
1068 | 154 | double mat_check[][3] = | ||
1069 | 155 | { | ||
1070 | 156 | {a1, b1/2, d1/2}, | ||
1071 | 157 | {b1/2, c1, e1/2}, | ||
1072 | 158 | {d1/2, e1/2, f1} | ||
1073 | 159 | }; | ||
1074 | 160 | |||
1075 | 161 | if (_det3(mat_check) == 0 || a1*c1 - b1*b1/4 <= 0) { | ||
1076 | 162 | SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No ellipse found for specified points")); | ||
1077 | 163 | return path_in; | ||
1078 | 164 | } | ||
1079 | 165 | |||
1080 | 166 | Geom::Ellipse el(a1, b1, c1, d1, e1, f1); | ||
1081 | 167 | |||
1082 | 168 | double s, e; | ||
1083 | 169 | double x0, y0, x1, y1, x2, y2, x3, y3; | ||
1084 | 170 | double len; | ||
1085 | 171 | |||
1086 | 172 | // figure out if we have a slice, guarding against rounding errors | ||
1087 | 173 | |||
1088 | 174 | Path p(Geom::Point(cos(0), sin(0))); | ||
1089 | 175 | |||
1090 | 176 | double end = 2 * M_PI; | ||
1091 | 177 | for (s = 0; s < end; s += M_PI_2) { | ||
1092 | 178 | e = s + M_PI_2; | ||
1093 | 179 | if (e > end) | ||
1094 | 180 | e = end; | ||
1095 | 181 | len = 4*tan((e - s)/4)/3; | ||
1096 | 182 | x0 = cos(s); | ||
1097 | 183 | y0 = sin(s); | ||
1098 | 184 | x1 = x0 + len * cos(s + M_PI_2); | ||
1099 | 185 | y1 = y0 + len * sin(s + M_PI_2); | ||
1100 | 186 | x3 = cos(e); | ||
1101 | 187 | y3 = sin(e); | ||
1102 | 188 | x2 = x3 + len * cos(e - M_PI_2); | ||
1103 | 189 | y2 = y3 + len * sin(e - M_PI_2); | ||
1104 | 190 | p.appendNew<Geom::CubicBezier>(Geom::Point(x1,y1), Geom::Point(x2,y2), Geom::Point(x3,y3)); | ||
1105 | 191 | } | ||
1106 | 192 | |||
1107 | 193 | Geom::Affine aff = Geom::Scale(el.ray(Geom::X), el.ray(Geom::Y)) * Geom::Rotate(el.rot_angle()) * Geom::Translate(el.center()); | ||
1108 | 194 | |||
1109 | 195 | path_out.push_back(p * aff); | ||
1110 | 196 | |||
1111 | 197 | return path_out; | ||
1112 | 198 | } | ||
1113 | 199 | |||
1114 | 200 | /* ######################## */ | ||
1115 | 201 | |||
1116 | 202 | } //namespace LivePathEffect | ||
1117 | 203 | } /* namespace Inkscape */ | ||
1118 | 204 | |||
1119 | 205 | /* | ||
1120 | 206 | Local Variables: | ||
1121 | 207 | mode:c++ | ||
1122 | 208 | c-file-style:"stroustrup" | ||
1123 | 209 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
1124 | 210 | indent-tabs-mode:nil | ||
1125 | 211 | fill-column:99 | ||
1126 | 212 | End: | ||
1127 | 213 | */ | ||
1128 | 214 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : | ||
1129 | 0 | 215 | ||
1130 | === added file 'src/live_effects/lpe-ellipse_5pts.h' | |||
1131 | --- src/live_effects/lpe-ellipse_5pts.h 1970-01-01 00:00:00 +0000 | |||
1132 | +++ src/live_effects/lpe-ellipse_5pts.h 2014-09-07 17:02:32 +0000 | |||
1133 | @@ -0,0 +1,50 @@ | |||
1134 | 1 | #ifndef INKSCAPE_LPE_ELLIPSE_5PTS_H | ||
1135 | 2 | #define INKSCAPE_LPE_ELLIPSE_5PTS_H | ||
1136 | 3 | |||
1137 | 4 | /** \file | ||
1138 | 5 | * LPE "Ellipse through 5 points" implementation | ||
1139 | 6 | */ | ||
1140 | 7 | |||
1141 | 8 | /* | ||
1142 | 9 | * Authors: | ||
1143 | 10 | * Theodore Janeczko | ||
1144 | 11 | * | ||
1145 | 12 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
1146 | 13 | * | ||
1147 | 14 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
1148 | 15 | */ | ||
1149 | 16 | |||
1150 | 17 | #include "live_effects/effect.h" | ||
1151 | 18 | #include "live_effects/parameter/parameter.h" | ||
1152 | 19 | #include "live_effects/parameter/point.h" | ||
1153 | 20 | |||
1154 | 21 | namespace Inkscape { | ||
1155 | 22 | namespace LivePathEffect { | ||
1156 | 23 | |||
1157 | 24 | class LPEEllipse5Pts : public Effect { | ||
1158 | 25 | public: | ||
1159 | 26 | LPEEllipse5Pts(LivePathEffectObject *lpeobject); | ||
1160 | 27 | virtual ~LPEEllipse5Pts(); | ||
1161 | 28 | |||
1162 | 29 | virtual std::vector<Geom::Path> doEffect_path (std::vector<Geom::Path> const & path_in); | ||
1163 | 30 | |||
1164 | 31 | private: | ||
1165 | 32 | LPEEllipse5Pts(const LPEEllipse5Pts&); | ||
1166 | 33 | LPEEllipse5Pts& operator=(const LPEEllipse5Pts&); | ||
1167 | 34 | }; | ||
1168 | 35 | |||
1169 | 36 | } //namespace LivePathEffect | ||
1170 | 37 | } //namespace Inkscape | ||
1171 | 38 | |||
1172 | 39 | #endif | ||
1173 | 40 | |||
1174 | 41 | /* | ||
1175 | 42 | Local Variables: | ||
1176 | 43 | mode:c++ | ||
1177 | 44 | c-file-style:"stroustrup" | ||
1178 | 45 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
1179 | 46 | indent-tabs-mode:nil | ||
1180 | 47 | fill-column:99 | ||
1181 | 48 | End: | ||
1182 | 49 | */ | ||
1183 | 50 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : | ||
1184 | 0 | 51 | ||
1185 | === added file 'src/live_effects/lpe-fill-between-many.cpp' | |||
1186 | --- src/live_effects/lpe-fill-between-many.cpp 1970-01-01 00:00:00 +0000 | |||
1187 | +++ src/live_effects/lpe-fill-between-many.cpp 2014-09-07 17:02:32 +0000 | |||
1188 | @@ -0,0 +1,78 @@ | |||
1189 | 1 | /* | ||
1190 | 2 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
1191 | 3 | * | ||
1192 | 4 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
1193 | 5 | */ | ||
1194 | 6 | |||
1195 | 7 | #include <gtkmm/box.h> | ||
1196 | 8 | |||
1197 | 9 | #include "live_effects/lpe-fill-between-many.h" | ||
1198 | 10 | |||
1199 | 11 | #include "display/curve.h" | ||
1200 | 12 | #include "sp-item.h" | ||
1201 | 13 | #include "2geom/path.h" | ||
1202 | 14 | #include "sp-shape.h" | ||
1203 | 15 | #include "sp-text.h" | ||
1204 | 16 | #include "2geom/bezier-curve.h" | ||
1205 | 17 | |||
1206 | 18 | #include <glibmm/i18n.h> | ||
1207 | 19 | |||
1208 | 20 | namespace Inkscape { | ||
1209 | 21 | namespace LivePathEffect { | ||
1210 | 22 | |||
1211 | 23 | LPEFillBetweenMany::LPEFillBetweenMany(LivePathEffectObject *lpeobject) : | ||
1212 | 24 | Effect(lpeobject), | ||
1213 | 25 | linked_paths(_("Linked path:"), _("Paths from which to take the original path data"), "linkedpaths", &wr, this) | ||
1214 | 26 | { | ||
1215 | 27 | registerParameter( dynamic_cast<Parameter *>(&linked_paths) ); | ||
1216 | 28 | //perceived_path = true; | ||
1217 | 29 | } | ||
1218 | 30 | |||
1219 | 31 | LPEFillBetweenMany::~LPEFillBetweenMany() | ||
1220 | 32 | { | ||
1221 | 33 | |||
1222 | 34 | } | ||
1223 | 35 | |||
1224 | 36 | void LPEFillBetweenMany::doEffect (SPCurve * curve) | ||
1225 | 37 | { | ||
1226 | 38 | std::vector<Geom::Path> res_pathv; | ||
1227 | 39 | SPItem * firstObj = NULL; | ||
1228 | 40 | for (std::vector<PathAndDirection*>::iterator iter = linked_paths._vector.begin(); iter != linked_paths._vector.end(); iter++) { | ||
1229 | 41 | SPObject *obj; | ||
1230 | 42 | if ((*iter)->ref.isAttached() && (obj = (*iter)->ref.getObject()) && SP_IS_ITEM(obj) && !(*iter)->_pathvector.empty()) { | ||
1231 | 43 | Geom::Path linked_path; | ||
1232 | 44 | if ((*iter)->reversed) { | ||
1233 | 45 | linked_path = (*iter)->_pathvector.front().reverse(); | ||
1234 | 46 | } else { | ||
1235 | 47 | linked_path = (*iter)->_pathvector.front(); | ||
1236 | 48 | } | ||
1237 | 49 | |||
1238 | 50 | if (!res_pathv.empty()) { | ||
1239 | 51 | linked_path = linked_path * SP_ITEM(obj)->getRelativeTransform(firstObj); | ||
1240 | 52 | res_pathv.front().appendNew<Geom::LineSegment>(linked_path.initialPoint()); | ||
1241 | 53 | res_pathv.front().append(linked_path); | ||
1242 | 54 | } else { | ||
1243 | 55 | firstObj = SP_ITEM(obj); | ||
1244 | 56 | res_pathv.push_back(linked_path); | ||
1245 | 57 | } | ||
1246 | 58 | } | ||
1247 | 59 | } | ||
1248 | 60 | if (!res_pathv.empty()) { | ||
1249 | 61 | res_pathv.front().close(); | ||
1250 | 62 | } | ||
1251 | 63 | curve->set_pathvector(res_pathv); | ||
1252 | 64 | } | ||
1253 | 65 | |||
1254 | 66 | } // namespace LivePathEffect | ||
1255 | 67 | } /* namespace Inkscape */ | ||
1256 | 68 | |||
1257 | 69 | /* | ||
1258 | 70 | Local Variables: | ||
1259 | 71 | mode:c++ | ||
1260 | 72 | c-file-style:"stroustrup" | ||
1261 | 73 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
1262 | 74 | indent-tabs-mode:nil | ||
1263 | 75 | fill-column:99 | ||
1264 | 76 | End: | ||
1265 | 77 | */ | ||
1266 | 78 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : | ||
1267 | 0 | 79 | ||
1268 | === added file 'src/live_effects/lpe-fill-between-many.h' | |||
1269 | --- src/live_effects/lpe-fill-between-many.h 1970-01-01 00:00:00 +0000 | |||
1270 | +++ src/live_effects/lpe-fill-between-many.h 2014-09-07 17:02:32 +0000 | |||
1271 | @@ -0,0 +1,36 @@ | |||
1272 | 1 | #ifndef INKSCAPE_LPE_FILL_BETWEEN_MANY_H | ||
1273 | 2 | #define INKSCAPE_LPE_FILL_BETWEEN_MANY_H | ||
1274 | 3 | |||
1275 | 4 | /* | ||
1276 | 5 | * Inkscape::LPEFillBetweenStrokes | ||
1277 | 6 | * | ||
1278 | 7 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
1279 | 8 | * | ||
1280 | 9 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
1281 | 10 | */ | ||
1282 | 11 | |||
1283 | 12 | #include "live_effects/effect.h" | ||
1284 | 13 | #include "live_effects/parameter/originalpatharray.h" | ||
1285 | 14 | |||
1286 | 15 | namespace Inkscape { | ||
1287 | 16 | namespace LivePathEffect { | ||
1288 | 17 | |||
1289 | 18 | class LPEFillBetweenMany : public Effect { | ||
1290 | 19 | public: | ||
1291 | 20 | LPEFillBetweenMany(LivePathEffectObject *lpeobject); | ||
1292 | 21 | virtual ~LPEFillBetweenMany(); | ||
1293 | 22 | |||
1294 | 23 | virtual void doEffect (SPCurve * curve); | ||
1295 | 24 | |||
1296 | 25 | private: | ||
1297 | 26 | OriginalPathArrayParam linked_paths; | ||
1298 | 27 | |||
1299 | 28 | private: | ||
1300 | 29 | LPEFillBetweenMany(const LPEFillBetweenMany&); | ||
1301 | 30 | LPEFillBetweenMany& operator=(const LPEFillBetweenMany&); | ||
1302 | 31 | }; | ||
1303 | 32 | |||
1304 | 33 | }; //namespace LivePathEffect | ||
1305 | 34 | }; //namespace Inkscape | ||
1306 | 35 | |||
1307 | 36 | #endif | ||
1308 | 0 | 37 | ||
1309 | === added file 'src/live_effects/lpe-fill-between-strokes.cpp' | |||
1310 | --- src/live_effects/lpe-fill-between-strokes.cpp 1970-01-01 00:00:00 +0000 | |||
1311 | +++ src/live_effects/lpe-fill-between-strokes.cpp 2014-09-07 17:02:32 +0000 | |||
1312 | @@ -0,0 +1,116 @@ | |||
1313 | 1 | /* | ||
1314 | 2 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
1315 | 3 | * | ||
1316 | 4 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
1317 | 5 | */ | ||
1318 | 6 | |||
1319 | 7 | #include <glibmm/i18n.h> | ||
1320 | 8 | |||
1321 | 9 | #include "live_effects/lpe-fill-between-strokes.h" | ||
1322 | 10 | |||
1323 | 11 | #include "display/curve.h" | ||
1324 | 12 | #include "sp-item.h" | ||
1325 | 13 | #include "2geom/path.h" | ||
1326 | 14 | #include "sp-shape.h" | ||
1327 | 15 | #include "sp-text.h" | ||
1328 | 16 | #include "2geom/bezier-curve.h" | ||
1329 | 17 | |||
1330 | 18 | namespace Inkscape { | ||
1331 | 19 | namespace LivePathEffect { | ||
1332 | 20 | |||
1333 | 21 | LPEFillBetweenStrokes::LPEFillBetweenStrokes(LivePathEffectObject *lpeobject) : | ||
1334 | 22 | Effect(lpeobject), | ||
1335 | 23 | linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this), | ||
1336 | 24 | second_path(_("Second path:"), _("Second path from which to take the original path data"), "secondpath", &wr, this), | ||
1337 | 25 | reverse_second(_("Reverse Second"), _("Reverses the second path order"), "reversesecond", &wr, this) | ||
1338 | 26 | { | ||
1339 | 27 | registerParameter( dynamic_cast<Parameter *>(&linked_path) ); | ||
1340 | 28 | registerParameter( dynamic_cast<Parameter *>(&second_path) ); | ||
1341 | 29 | registerParameter( dynamic_cast<Parameter *>(&reverse_second) ); | ||
1342 | 30 | //perceived_path = true; | ||
1343 | 31 | } | ||
1344 | 32 | |||
1345 | 33 | LPEFillBetweenStrokes::~LPEFillBetweenStrokes() | ||
1346 | 34 | { | ||
1347 | 35 | |||
1348 | 36 | } | ||
1349 | 37 | |||
1350 | 38 | void LPEFillBetweenStrokes::doEffect (SPCurve * curve) | ||
1351 | 39 | { | ||
1352 | 40 | if (curve) { | ||
1353 | 41 | if ( linked_path.linksToPath() && second_path.linksToPath() && linked_path.getObject() && second_path.getObject() ) { | ||
1354 | 42 | std::vector<Geom::Path> linked_pathv = linked_path.get_pathvector(); | ||
1355 | 43 | std::vector<Geom::Path> second_pathv = second_path.get_pathvector(); | ||
1356 | 44 | std::vector<Geom::Path> result_linked_pathv; | ||
1357 | 45 | std::vector<Geom::Path> result_second_pathv; | ||
1358 | 46 | Geom::Affine second_transform = second_path.getObject()->getRelativeTransform(linked_path.getObject()); | ||
1359 | 47 | |||
1360 | 48 | for (std::vector<Geom::Path>::iterator iter = linked_pathv.begin(); iter != linked_pathv.end(); ++iter) | ||
1361 | 49 | { | ||
1362 | 50 | result_linked_pathv.push_back((*iter)); | ||
1363 | 51 | } | ||
1364 | 52 | for (std::vector<Geom::Path>::iterator iter = second_pathv.begin(); iter != second_pathv.end(); ++iter) | ||
1365 | 53 | { | ||
1366 | 54 | result_second_pathv.push_back((*iter) * second_transform); | ||
1367 | 55 | } | ||
1368 | 56 | |||
1369 | 57 | if ( !result_linked_pathv.empty() && !result_second_pathv.empty() && !result_linked_pathv.front().closed() ) { | ||
1370 | 58 | if (reverse_second.get_value()) | ||
1371 | 59 | { | ||
1372 | 60 | result_linked_pathv.front().appendNew<Geom::LineSegment>(result_second_pathv.front().finalPoint()); | ||
1373 | 61 | result_linked_pathv.front().append(result_second_pathv.front().reverse()); | ||
1374 | 62 | } | ||
1375 | 63 | else | ||
1376 | 64 | { | ||
1377 | 65 | result_linked_pathv.front().appendNew<Geom::LineSegment>(result_second_pathv.front().initialPoint()); | ||
1378 | 66 | result_linked_pathv.front().append(result_second_pathv.front()); | ||
1379 | 67 | } | ||
1380 | 68 | curve->set_pathvector(result_linked_pathv); | ||
1381 | 69 | } | ||
1382 | 70 | else if ( !result_linked_pathv.empty() ) { | ||
1383 | 71 | curve->set_pathvector(result_linked_pathv); | ||
1384 | 72 | } | ||
1385 | 73 | else if ( !result_second_pathv.empty() ) { | ||
1386 | 74 | curve->set_pathvector(result_second_pathv); | ||
1387 | 75 | } | ||
1388 | 76 | } | ||
1389 | 77 | else if ( linked_path.linksToPath() && linked_path.getObject() ) { | ||
1390 | 78 | std::vector<Geom::Path> linked_pathv = linked_path.get_pathvector(); | ||
1391 | 79 | std::vector<Geom::Path> result_pathv; | ||
1392 | 80 | |||
1393 | 81 | for (std::vector<Geom::Path>::iterator iter = linked_pathv.begin(); iter != linked_pathv.end(); ++iter) | ||
1394 | 82 | { | ||
1395 | 83 | result_pathv.push_back((*iter)); | ||
1396 | 84 | } | ||
1397 | 85 | if ( !result_pathv.empty() ) { | ||
1398 | 86 | curve->set_pathvector(result_pathv); | ||
1399 | 87 | } | ||
1400 | 88 | } | ||
1401 | 89 | else if ( second_path.linksToPath() && second_path.getObject() ) { | ||
1402 | 90 | std::vector<Geom::Path> second_pathv = second_path.get_pathvector(); | ||
1403 | 91 | std::vector<Geom::Path> result_pathv; | ||
1404 | 92 | |||
1405 | 93 | for (std::vector<Geom::Path>::iterator iter = second_pathv.begin(); iter != second_pathv.end(); ++iter) | ||
1406 | 94 | { | ||
1407 | 95 | result_pathv.push_back((*iter)); | ||
1408 | 96 | } | ||
1409 | 97 | if ( !result_pathv.empty() ) { | ||
1410 | 98 | curve->set_pathvector(result_pathv); | ||
1411 | 99 | } | ||
1412 | 100 | } | ||
1413 | 101 | } | ||
1414 | 102 | } | ||
1415 | 103 | |||
1416 | 104 | } // namespace LivePathEffect | ||
1417 | 105 | } /* namespace Inkscape */ | ||
1418 | 106 | |||
1419 | 107 | /* | ||
1420 | 108 | Local Variables: | ||
1421 | 109 | mode:c++ | ||
1422 | 110 | c-file-style:"stroustrup" | ||
1423 | 111 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
1424 | 112 | indent-tabs-mode:nil | ||
1425 | 113 | fill-column:99 | ||
1426 | 114 | End: | ||
1427 | 115 | */ | ||
1428 | 116 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : | ||
1429 | 0 | 117 | ||
1430 | === added file 'src/live_effects/lpe-fill-between-strokes.h' | |||
1431 | --- src/live_effects/lpe-fill-between-strokes.h 1970-01-01 00:00:00 +0000 | |||
1432 | +++ src/live_effects/lpe-fill-between-strokes.h 2014-09-07 17:02:32 +0000 | |||
1433 | @@ -0,0 +1,38 @@ | |||
1434 | 1 | #ifndef INKSCAPE_LPE_FILL_BETWEEN_STROKES_H | ||
1435 | 2 | #define INKSCAPE_LPE_FILL_BETWEEN_STROKES_H | ||
1436 | 3 | |||
1437 | 4 | /* | ||
1438 | 5 | * Inkscape::LPEFillBetweenStrokes | ||
1439 | 6 | * | ||
1440 | 7 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
1441 | 8 | * | ||
1442 | 9 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
1443 | 10 | */ | ||
1444 | 11 | |||
1445 | 12 | #include "live_effects/effect.h" | ||
1446 | 13 | #include "live_effects/parameter/originalpath.h" | ||
1447 | 14 | |||
1448 | 15 | namespace Inkscape { | ||
1449 | 16 | namespace LivePathEffect { | ||
1450 | 17 | |||
1451 | 18 | class LPEFillBetweenStrokes : public Effect { | ||
1452 | 19 | public: | ||
1453 | 20 | LPEFillBetweenStrokes(LivePathEffectObject *lpeobject); | ||
1454 | 21 | virtual ~LPEFillBetweenStrokes(); | ||
1455 | 22 | |||
1456 | 23 | virtual void doEffect (SPCurve * curve); | ||
1457 | 24 | |||
1458 | 25 | private: | ||
1459 | 26 | OriginalPathParam linked_path; | ||
1460 | 27 | OriginalPathParam second_path; | ||
1461 | 28 | BoolParam reverse_second; | ||
1462 | 29 | |||
1463 | 30 | private: | ||
1464 | 31 | LPEFillBetweenStrokes(const LPEFillBetweenStrokes&); | ||
1465 | 32 | LPEFillBetweenStrokes& operator=(const LPEFillBetweenStrokes&); | ||
1466 | 33 | }; | ||
1467 | 34 | |||
1468 | 35 | }; //namespace LivePathEffect | ||
1469 | 36 | }; //namespace Inkscape | ||
1470 | 37 | |||
1471 | 38 | #endif | ||
1472 | 0 | 39 | ||
1473 | === added file 'src/live_effects/lpe-jointype.cpp' | |||
1474 | --- src/live_effects/lpe-jointype.cpp 1970-01-01 00:00:00 +0000 | |||
1475 | +++ src/live_effects/lpe-jointype.cpp 2014-09-07 17:02:32 +0000 | |||
1476 | @@ -0,0 +1,184 @@ | |||
1477 | 1 | /** \file | ||
1478 | 2 | * LPE "Join Type" implementation | ||
1479 | 3 | */ | ||
1480 | 4 | /* Authors: | ||
1481 | 5 | * | ||
1482 | 6 | * Liam P White | ||
1483 | 7 | * | ||
1484 | 8 | * Copyright (C) 2014 Authors | ||
1485 | 9 | * | ||
1486 | 10 | * Released under GNU GPL v2, read the file 'COPYING' for more information | ||
1487 | 11 | */ | ||
1488 | 12 | |||
1489 | 13 | #include <math.h> | ||
1490 | 14 | |||
1491 | 15 | #include "live_effects/parameter/enum.h" | ||
1492 | 16 | #include "live_effects/pathoutlineprovider.h" | ||
1493 | 17 | |||
1494 | 18 | #include "sp-shape.h" | ||
1495 | 19 | #include "style.h" | ||
1496 | 20 | #include "xml/repr.h" | ||
1497 | 21 | #include "sp-paint-server.h" | ||
1498 | 22 | #include "svg/svg-color.h" | ||
1499 | 23 | #include "desktop-style.h" | ||
1500 | 24 | #include "svg/css-ostringstream.h" | ||
1501 | 25 | #include "display/curve.h" | ||
1502 | 26 | |||
1503 | 27 | #include <2geom/path.h> | ||
1504 | 28 | #include <2geom/svg-elliptical-arc.h> | ||
1505 | 29 | |||
1506 | 30 | #include "lpe-jointype.h" | ||
1507 | 31 | |||
1508 | 32 | namespace Inkscape { | ||
1509 | 33 | namespace LivePathEffect { | ||
1510 | 34 | |||
1511 | 35 | static const Util::EnumData<unsigned> JoinTypeData[] = { | ||
1512 | 36 | {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, | ||
1513 | 37 | {LINEJOIN_ROUND, N_("Rounded"), "round"}, | ||
1514 | 38 | {LINEJOIN_POINTY, N_("Miter"), "miter"}, | ||
1515 | 39 | {LINEJOIN_REFLECTED, N_("Reflected"), "extrapolated"}, | ||
1516 | 40 | {LINEJOIN_EXTRAPOLATED, N_("Extrapolated arc"), "extrp_arc"} | ||
1517 | 41 | }; | ||
1518 | 42 | |||
1519 | 43 | static const Util::EnumData<unsigned> CapTypeData[] = { | ||
1520 | 44 | {BUTT_STRAIGHT, N_("Butt"), "butt"}, | ||
1521 | 45 | {BUTT_ROUND, N_("Rounded"), "round"}, | ||
1522 | 46 | {BUTT_SQUARE, N_("Square"), "square"}, | ||
1523 | 47 | {BUTT_POINTY, N_("Peak"), "peak"}, | ||
1524 | 48 | {BUTT_LEANED, N_("Leaned"), "leaned"} | ||
1525 | 49 | }; | ||
1526 | 50 | |||
1527 | 51 | static const Util::EnumDataConverter<unsigned> CapTypeConverter(CapTypeData, sizeof(CapTypeData)/sizeof(*CapTypeData)); | ||
1528 | 52 | static const Util::EnumDataConverter<unsigned> JoinTypeConverter(JoinTypeData, sizeof(JoinTypeData)/sizeof(*JoinTypeData)); | ||
1529 | 53 | |||
1530 | 54 | LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) : | ||
1531 | 55 | Effect(lpeobject), | ||
1532 | 56 | line_width(_("Line width"), _("Thickness of the stroke"), "line_width", &wr, this, 1.), | ||
1533 | 57 | linecap_type(_("Line cap"), _("The end shape of the stroke"), "linecap_type", CapTypeConverter, &wr, this, butt_straight), | ||
1534 | 58 | linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), | ||
1535 | 59 | start_lean(_("Start path lean"), _("Start path lean"), "start_lean", &wr, this, 0.), | ||
1536 | 60 | end_lean(_("End path lean"), _("End path lean"), "end_lean", &wr, this, 0.), | ||
1537 | 61 | miter_limit(_("Miter limit:"), _("Maximum length of the miter join (in units of stroke width)"), "miter_limit", &wr, this, 100.), | ||
1538 | 62 | attempt_force_join(_("Force miter"), _("Overrides the miter limit and forces a join."), "attempt_force_join", &wr, this, true) | ||
1539 | 63 | { | ||
1540 | 64 | show_orig_path = true; | ||
1541 | 65 | registerParameter( dynamic_cast<Parameter *>(&linecap_type) ); | ||
1542 | 66 | registerParameter( dynamic_cast<Parameter *>(&line_width) ); | ||
1543 | 67 | registerParameter( dynamic_cast<Parameter *>(&linejoin_type) ); | ||
1544 | 68 | registerParameter( dynamic_cast<Parameter *>(&start_lean) ); | ||
1545 | 69 | registerParameter( dynamic_cast<Parameter *>(&end_lean) ); | ||
1546 | 70 | registerParameter( dynamic_cast<Parameter *>(&miter_limit) ); | ||
1547 | 71 | registerParameter( dynamic_cast<Parameter *>(&attempt_force_join) ); | ||
1548 | 72 | was_initialized = false; | ||
1549 | 73 | start_lean.param_set_range(-1,1); | ||
1550 | 74 | start_lean.param_set_increments(0.1, 0.1); | ||
1551 | 75 | start_lean.param_set_digits(4); | ||
1552 | 76 | end_lean.param_set_range(-1,1); | ||
1553 | 77 | end_lean.param_set_increments(0.1, 0.1); | ||
1554 | 78 | end_lean.param_set_digits(4); | ||
1555 | 79 | } | ||
1556 | 80 | |||
1557 | 81 | LPEJoinType::~LPEJoinType() | ||
1558 | 82 | { | ||
1559 | 83 | } | ||
1560 | 84 | |||
1561 | 85 | //from LPEPowerStroke -- sets fill if stroke color because we will | ||
1562 | 86 | //be converting to a fill to make the new join. | ||
1563 | 87 | |||
1564 | 88 | void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) | ||
1565 | 89 | { | ||
1566 | 90 | if (SP_IS_SHAPE(lpeitem)) { | ||
1567 | 91 | SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem); | ||
1568 | 92 | double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; | ||
1569 | 93 | |||
1570 | 94 | SPCSSAttr *css = sp_repr_css_attr_new (); | ||
1571 | 95 | if (true) { | ||
1572 | 96 | if (lpeitem->style->stroke.isPaintserver()) { | ||
1573 | 97 | SPPaintServer * server = lpeitem->style->getStrokePaintServer(); | ||
1574 | 98 | if (server) { | ||
1575 | 99 | Glib::ustring str; | ||
1576 | 100 | str += "url(#"; | ||
1577 | 101 | str += server->getId(); | ||
1578 | 102 | str += ")"; | ||
1579 | 103 | sp_repr_css_set_property (css, "fill", str.c_str()); | ||
1580 | 104 | } | ||
1581 | 105 | } else if (lpeitem->style->stroke.isColor()) { | ||
1582 | 106 | gchar c[64]; | ||
1583 | 107 | sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); | ||
1584 | 108 | sp_repr_css_set_property (css, "fill", c); | ||
1585 | 109 | } else { | ||
1586 | 110 | sp_repr_css_set_property (css, "fill", "none"); | ||
1587 | 111 | } | ||
1588 | 112 | } else { | ||
1589 | 113 | sp_repr_css_unset_property (css, "fill"); | ||
1590 | 114 | } | ||
1591 | 115 | |||
1592 | 116 | sp_repr_css_set_property(css, "stroke", "none"); | ||
1593 | 117 | |||
1594 | 118 | sp_desktop_apply_css_recursive(item, css, true); | ||
1595 | 119 | sp_repr_css_attr_unref (css); | ||
1596 | 120 | if (!was_initialized) | ||
1597 | 121 | { | ||
1598 | 122 | was_initialized = true; | ||
1599 | 123 | line_width.param_set_value(width); | ||
1600 | 124 | } | ||
1601 | 125 | } else { | ||
1602 | 126 | g_warning("LPE Join Type can only be applied to paths (not groups)."); | ||
1603 | 127 | } | ||
1604 | 128 | } | ||
1605 | 129 | |||
1606 | 130 | //from LPEPowerStroke -- sets stroke color from existing fill color | ||
1607 | 131 | |||
1608 | 132 | void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) | ||
1609 | 133 | { | ||
1610 | 134 | |||
1611 | 135 | if (SP_IS_SHAPE(lpeitem)) { | ||
1612 | 136 | SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem); | ||
1613 | 137 | |||
1614 | 138 | SPCSSAttr *css = sp_repr_css_attr_new (); | ||
1615 | 139 | if (true) { | ||
1616 | 140 | if (lpeitem->style->fill.isPaintserver()) { | ||
1617 | 141 | SPPaintServer * server = lpeitem->style->getFillPaintServer(); | ||
1618 | 142 | if (server) { | ||
1619 | 143 | Glib::ustring str; | ||
1620 | 144 | str += "url(#"; | ||
1621 | 145 | str += server->getId(); | ||
1622 | 146 | str += ")"; | ||
1623 | 147 | sp_repr_css_set_property (css, "stroke", str.c_str()); | ||
1624 | 148 | } | ||
1625 | 149 | } else if (lpeitem->style->fill.isColor()) { | ||
1626 | 150 | gchar c[64]; | ||
1627 | 151 | sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); | ||
1628 | 152 | sp_repr_css_set_property (css, "stroke", c); | ||
1629 | 153 | } else { | ||
1630 | 154 | sp_repr_css_set_property (css, "stroke", "none"); | ||
1631 | 155 | } | ||
1632 | 156 | } else { | ||
1633 | 157 | sp_repr_css_unset_property (css, "stroke"); | ||
1634 | 158 | } | ||
1635 | 159 | |||
1636 | 160 | Inkscape::CSSOStringStream os; | ||
1637 | 161 | os << fabs(line_width); | ||
1638 | 162 | sp_repr_css_set_property (css, "stroke-width", os.str().c_str()); | ||
1639 | 163 | |||
1640 | 164 | sp_repr_css_set_property(css, "fill", "none"); | ||
1641 | 165 | |||
1642 | 166 | sp_desktop_apply_css_recursive(item, css, true); | ||
1643 | 167 | sp_repr_css_attr_unref (css); | ||
1644 | 168 | item->updateRepr(); | ||
1645 | 169 | } | ||
1646 | 170 | } | ||
1647 | 171 | |||
1648 | 172 | //NOTE: I originally had all the outliner functions defined in here, but they were actually useful | ||
1649 | 173 | //enough for other LPEs so I moved them all into pathoutlineprovider.cpp. The code here is just a | ||
1650 | 174 | //wrapper around it. | ||
1651 | 175 | std::vector<Geom::Path> LPEJoinType::doEffect_path(std::vector<Geom::Path> const & path_in) | ||
1652 | 176 | { | ||
1653 | 177 | return Outline::PathVectorOutline(path_in, line_width, static_cast<ButtTypeMod>(linecap_type.get_value()), | ||
1654 | 178 | static_cast<LineJoinType>(linejoin_type.get_value()), | ||
1655 | 179 | (attempt_force_join ? std::numeric_limits<double>::max() : miter_limit), | ||
1656 | 180 | start_lean/2 ,end_lean/2); | ||
1657 | 181 | } | ||
1658 | 182 | |||
1659 | 183 | } //namespace LivePathEffect | ||
1660 | 184 | } //namespace Inkscape | ||
1661 | 0 | 185 | ||
1662 | === added file 'src/live_effects/lpe-jointype.h' | |||
1663 | --- src/live_effects/lpe-jointype.h 1970-01-01 00:00:00 +0000 | |||
1664 | +++ src/live_effects/lpe-jointype.h 2014-09-07 17:02:32 +0000 | |||
1665 | @@ -0,0 +1,45 @@ | |||
1666 | 1 | /* Authors: | ||
1667 | 2 | * Liam P White | ||
1668 | 3 | * | ||
1669 | 4 | * Copyright (C) 2014 Authors | ||
1670 | 5 | * | ||
1671 | 6 | * Released under GNU GPL v2, read the file COPYING for more information | ||
1672 | 7 | */ | ||
1673 | 8 | #ifndef INKSCAPE_LPE_JOINTYPE_H | ||
1674 | 9 | #define INKSCAPE_LPE_JOINTYPE_H | ||
1675 | 10 | |||
1676 | 11 | #include "live_effects/effect.h" | ||
1677 | 12 | #include "live_effects/parameter/parameter.h" | ||
1678 | 13 | #include "live_effects/parameter/point.h" | ||
1679 | 14 | #include "live_effects/parameter/enum.h" | ||
1680 | 15 | |||
1681 | 16 | namespace Inkscape { | ||
1682 | 17 | namespace LivePathEffect { | ||
1683 | 18 | |||
1684 | 19 | class LPEJoinType : public Effect { | ||
1685 | 20 | public: | ||
1686 | 21 | LPEJoinType(LivePathEffectObject *lpeobject); | ||
1687 | 22 | virtual ~LPEJoinType(); | ||
1688 | 23 | |||
1689 | 24 | virtual void doOnApply(SPLPEItem const* lpeitem); | ||
1690 | 25 | virtual void doOnRemove(SPLPEItem const* lpeitem); | ||
1691 | 26 | virtual std::vector <Geom::Path> doEffect_path (std::vector<Geom::Path> const & path_in); | ||
1692 | 27 | |||
1693 | 28 | private: | ||
1694 | 29 | LPEJoinType(const LPEJoinType&); | ||
1695 | 30 | LPEJoinType& operator=(const LPEJoinType&); | ||
1696 | 31 | |||
1697 | 32 | ScalarParam line_width; | ||
1698 | 33 | EnumParam<unsigned> linecap_type; | ||
1699 | 34 | EnumParam<unsigned> linejoin_type; | ||
1700 | 35 | ScalarParam start_lean; | ||
1701 | 36 | ScalarParam end_lean; | ||
1702 | 37 | ScalarParam miter_limit; | ||
1703 | 38 | BoolParam attempt_force_join; | ||
1704 | 39 | bool was_initialized; | ||
1705 | 40 | }; | ||
1706 | 41 | |||
1707 | 42 | } //namespace LivePathEffect | ||
1708 | 43 | } //namespace Inkscape | ||
1709 | 44 | |||
1710 | 45 | #endif | ||
1711 | 0 | 46 | ||
1712 | === modified file 'src/live_effects/lpe-knot.cpp' | |||
1713 | --- src/live_effects/lpe-knot.cpp 2014-08-31 18:17:26 +0000 | |||
1714 | +++ src/live_effects/lpe-knot.cpp 2014-09-07 17:02:32 +0000 | |||
1715 | @@ -537,6 +537,10 @@ | |||
1716 | 537 | { | 537 | { |
1717 | 538 | using namespace Geom; | 538 | using namespace Geom; |
1718 | 539 | original_bbox(lpeitem); | 539 | original_bbox(lpeitem); |
1719 | 540 | |||
1720 | 541 | if (SP_IS_PATH(lpeitem)) { | ||
1721 | 542 | supplied_path = SP_PATH(lpeitem)->getCurve()->get_pathvector(); | ||
1722 | 543 | } | ||
1723 | 540 | 544 | ||
1724 | 541 | gpaths.clear(); | 545 | gpaths.clear(); |
1725 | 542 | gstroke_widths.clear(); | 546 | gstroke_widths.clear(); |
1726 | 543 | 547 | ||
1727 | === modified file 'src/live_effects/lpe-knot.h' | |||
1728 | --- src/live_effects/lpe-knot.h 2014-06-16 21:34:16 +0000 | |||
1729 | +++ src/live_effects/lpe-knot.h 2014-09-07 17:02:32 +0000 | |||
1730 | @@ -64,7 +64,8 @@ | |||
1731 | 64 | void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); | 64 | void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); |
1732 | 65 | 65 | ||
1733 | 66 | protected: | 66 | protected: |
1735 | 67 | virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); | 67 | virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); |
1736 | 68 | std::vector<Geom::Path> supplied_path; //for knotholder business | ||
1737 | 68 | 69 | ||
1738 | 69 | private: | 70 | private: |
1739 | 70 | void updateSwitcher(); | 71 | void updateSwitcher(); |
1740 | 71 | 72 | ||
1741 | === modified file 'src/live_effects/lpe-powerstroke-interpolators.h' | |||
1742 | --- src/live_effects/lpe-powerstroke-interpolators.h 2014-08-23 17:14:02 +0000 | |||
1743 | +++ src/live_effects/lpe-powerstroke-interpolators.h 2014-09-07 17:02:32 +0000 | |||
1744 | @@ -28,6 +28,7 @@ | |||
1745 | 28 | INTERP_CUBICBEZIER, | 28 | INTERP_CUBICBEZIER, |
1746 | 29 | INTERP_CUBICBEZIER_JOHAN, | 29 | INTERP_CUBICBEZIER_JOHAN, |
1747 | 30 | INTERP_SPIRO, | 30 | INTERP_SPIRO, |
1748 | 31 | INTERP_CUBICBEZIER_SMOOTH, | ||
1749 | 31 | INTERP_CENTRIPETAL_CATMULLROM | 32 | INTERP_CENTRIPETAL_CATMULLROM |
1750 | 32 | }; | 33 | }; |
1751 | 33 | 34 | ||
1752 | @@ -134,6 +135,43 @@ | |||
1753 | 134 | CubicBezierJohan& operator=(const CubicBezierJohan&); | 135 | CubicBezierJohan& operator=(const CubicBezierJohan&); |
1754 | 135 | }; | 136 | }; |
1755 | 136 | 137 | ||
1756 | 138 | /// @todo invent name for this class | ||
1757 | 139 | class CubicBezierSmooth : public Interpolator { | ||
1758 | 140 | public: | ||
1759 | 141 | CubicBezierSmooth(double beta = 0.2) { | ||
1760 | 142 | _beta = beta; | ||
1761 | 143 | }; | ||
1762 | 144 | virtual ~CubicBezierSmooth() {}; | ||
1763 | 145 | |||
1764 | 146 | virtual Path interpolateToPath(std::vector<Point> const &points) const { | ||
1765 | 147 | Path fit; | ||
1766 | 148 | fit.start(points.at(0)); | ||
1767 | 149 | unsigned int num_points = points.size(); | ||
1768 | 150 | for (unsigned int i = 1; i < num_points; ++i) { | ||
1769 | 151 | Point p0 = points.at(i-1); | ||
1770 | 152 | Point p1 = points.at(i); | ||
1771 | 153 | Point dx = Point(p1[X] - p0[X], 0); | ||
1772 | 154 | if (i == 1) { | ||
1773 | 155 | fit.appendNew<CubicBezier>(p0, p1-0.75*dx, p1); | ||
1774 | 156 | } else if (i == points.size() - 1) { | ||
1775 | 157 | fit.appendNew<CubicBezier>(p0+0.75*dx, p1, p1); | ||
1776 | 158 | } else { | ||
1777 | 159 | fit.appendNew<CubicBezier>(p0+_beta*dx, p1-_beta*dx, p1); | ||
1778 | 160 | } | ||
1779 | 161 | } | ||
1780 | 162 | return fit; | ||
1781 | 163 | }; | ||
1782 | 164 | |||
1783 | 165 | void setBeta(double beta) { | ||
1784 | 166 | _beta = beta; | ||
1785 | 167 | } | ||
1786 | 168 | |||
1787 | 169 | double _beta; | ||
1788 | 170 | |||
1789 | 171 | private: | ||
1790 | 172 | CubicBezierSmooth(const CubicBezierSmooth&); | ||
1791 | 173 | CubicBezierSmooth& operator=(const CubicBezierSmooth&); | ||
1792 | 174 | }; | ||
1793 | 137 | 175 | ||
1794 | 138 | class SpiroInterpolator : public Interpolator { | 176 | class SpiroInterpolator : public Interpolator { |
1795 | 139 | public: | 177 | public: |
1796 | @@ -261,6 +299,8 @@ | |||
1797 | 261 | return new Geom::Interpolate::CubicBezierJohan(); | 299 | return new Geom::Interpolate::CubicBezierJohan(); |
1798 | 262 | case INTERP_SPIRO: | 300 | case INTERP_SPIRO: |
1799 | 263 | return new Geom::Interpolate::SpiroInterpolator(); | 301 | return new Geom::Interpolate::SpiroInterpolator(); |
1800 | 302 | case INTERP_CUBICBEZIER_SMOOTH: | ||
1801 | 303 | return new Geom::Interpolate::CubicBezierSmooth(); | ||
1802 | 264 | case INTERP_CENTRIPETAL_CATMULLROM: | 304 | case INTERP_CENTRIPETAL_CATMULLROM: |
1803 | 265 | return new Geom::Interpolate::CentripetalCatmullRomInterpolator(); | 305 | return new Geom::Interpolate::CentripetalCatmullRomInterpolator(); |
1804 | 266 | default: | 306 | default: |
1805 | 267 | 307 | ||
1806 | === modified file 'src/live_effects/lpe-powerstroke.cpp' | |||
1807 | --- src/live_effects/lpe-powerstroke.cpp 2014-08-23 16:39:36 +0000 | |||
1808 | +++ src/live_effects/lpe-powerstroke.cpp 2014-09-07 17:02:32 +0000 | |||
1809 | @@ -15,6 +15,11 @@ | |||
1810 | 15 | 15 | ||
1811 | 16 | #include "sp-shape.h" | 16 | #include "sp-shape.h" |
1812 | 17 | #include "style.h" | 17 | #include "style.h" |
1813 | 18 | #include "xml/repr.h" | ||
1814 | 19 | #include "sp-paint-server.h" | ||
1815 | 20 | #include "svg/svg-color.h" | ||
1816 | 21 | #include "desktop-style.h" | ||
1817 | 22 | #include "svg/css-ostringstream.h" | ||
1818 | 18 | #include "display/curve.h" | 23 | #include "display/curve.h" |
1819 | 19 | 24 | ||
1820 | 20 | #include <2geom/path.h> | 25 | #include <2geom/path.h> |
1821 | @@ -185,6 +190,7 @@ | |||
1822 | 185 | namespace LivePathEffect { | 190 | namespace LivePathEffect { |
1823 | 186 | 191 | ||
1824 | 187 | static const Util::EnumData<unsigned> InterpolatorTypeData[] = { | 192 | static const Util::EnumData<unsigned> InterpolatorTypeData[] = { |
1825 | 193 | {Geom::Interpolate::INTERP_CUBICBEZIER_SMOOTH, N_("CubicBezierSmooth"), "CubicBezierSmooth"}, | ||
1826 | 188 | {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, | 194 | {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, |
1827 | 189 | {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, | 195 | {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, |
1828 | 190 | {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, | 196 | {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, |
1829 | @@ -223,9 +229,7 @@ | |||
1830 | 223 | {LINEJOIN_EXTRP_MITER, N_("Extrapolated"), "extrapolated"}, | 229 | {LINEJOIN_EXTRP_MITER, N_("Extrapolated"), "extrapolated"}, |
1831 | 224 | {LINEJOIN_MITER, N_("Miter"), "miter"}, | 230 | {LINEJOIN_MITER, N_("Miter"), "miter"}, |
1832 | 225 | {LINEJOIN_SPIRO, N_("Spiro"), "spiro"}, | 231 | {LINEJOIN_SPIRO, N_("Spiro"), "spiro"}, |
1833 | 226 | #ifdef LPE_ENABLE_TEST_EFFECTS | ||
1834 | 227 | {LINEJOIN_EXTRP_MITER_ARC, N_("Extrapolated arc"), "extrp_arc"}, | 232 | {LINEJOIN_EXTRP_MITER_ARC, N_("Extrapolated arc"), "extrp_arc"}, |
1835 | 228 | #endif | ||
1836 | 229 | }; | 233 | }; |
1837 | 230 | static const Util::EnumDataConverter<unsigned> LineJoinTypeConverter(LineJoinTypeData, sizeof(LineJoinTypeData)/sizeof(*LineJoinTypeData)); | 234 | static const Util::EnumDataConverter<unsigned> LineJoinTypeConverter(LineJoinTypeData, sizeof(LineJoinTypeData)/sizeof(*LineJoinTypeData)); |
1838 | 231 | 235 | ||
1839 | @@ -233,12 +237,12 @@ | |||
1840 | 233 | Effect(lpeobject), | 237 | Effect(lpeobject), |
1841 | 234 | offset_points(_("Offset points"), _("Offset points"), "offset_points", &wr, this), | 238 | offset_points(_("Offset points"), _("Offset points"), "offset_points", &wr, this), |
1842 | 235 | sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve"), "sort_points", &wr, this, true), | 239 | sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve"), "sort_points", &wr, this, true), |
1844 | 236 | interpolator_type(_("Interpolator type:"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path"), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN), | 240 | interpolator_type(_("Interpolator type:"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path"), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER), |
1845 | 237 | interpolator_beta(_("Smoothness:"), _("Sets the smoothness for the CubicBezierJohan interpolator; 0 = linear interpolation, 1 = smooth"), "interpolator_beta", &wr, this, 0.2), | 241 | interpolator_beta(_("Smoothness:"), _("Sets the smoothness for the CubicBezierJohan interpolator; 0 = linear interpolation, 1 = smooth"), "interpolator_beta", &wr, this, 0.2), |
1848 | 238 | start_linecap_type(_("Start cap:"), _("Determines the shape of the path's start"), "start_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND), | 242 | start_linecap_type(_("Start cap:"), _("Determines the shape of the path's start"), "start_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_BUTT), |
1849 | 239 | linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", LineJoinTypeConverter, &wr, this, LINEJOIN_ROUND), | 243 | linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", LineJoinTypeConverter, &wr, this, LINEJOIN_EXTRP_MITER_ARC), |
1850 | 240 | miter_limit(_("Miter limit:"), _("Maximum length of the miter (in units of stroke width)"), "miter_limit", &wr, this, 4.), | 244 | miter_limit(_("Miter limit:"), _("Maximum length of the miter (in units of stroke width)"), "miter_limit", &wr, this, 4.), |
1852 | 241 | end_linecap_type(_("End cap:"), _("Determines the shape of the path's end"), "end_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND) | 245 | end_linecap_type(_("End cap:"), _("Determines the shape of the path's end"), "end_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_BUTT) |
1853 | 242 | { | 246 | { |
1854 | 243 | show_orig_path = true; | 247 | show_orig_path = true; |
1855 | 244 | 248 | ||
1856 | @@ -267,20 +271,52 @@ | |||
1857 | 267 | LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) | 271 | LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) |
1858 | 268 | { | 272 | { |
1859 | 269 | if (SP_IS_SHAPE(lpeitem)) { | 273 | if (SP_IS_SHAPE(lpeitem)) { |
1860 | 274 | SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem); | ||
1861 | 270 | std::vector<Geom::Point> points; | 275 | std::vector<Geom::Point> points; |
1862 | 271 | Geom::PathVector const &pathv = SP_SHAPE(lpeitem)->_curve->get_pathvector(); | 276 | Geom::PathVector const &pathv = SP_SHAPE(lpeitem)->_curve->get_pathvector(); |
1864 | 272 | double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; | 277 | double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed / 2 : 1.; |
1865 | 278 | |||
1866 | 279 | SPCSSAttr *css = sp_repr_css_attr_new (); | ||
1867 | 280 | if (true) { | ||
1868 | 281 | if (lpeitem->style->stroke.isPaintserver()) { | ||
1869 | 282 | SPPaintServer * server = lpeitem->style->getStrokePaintServer(); | ||
1870 | 283 | if (server) { | ||
1871 | 284 | Glib::ustring str; | ||
1872 | 285 | str += "url(#"; | ||
1873 | 286 | str += server->getId(); | ||
1874 | 287 | str += ")"; | ||
1875 | 288 | sp_repr_css_set_property (css, "fill", str.c_str()); | ||
1876 | 289 | } | ||
1877 | 290 | } else if (lpeitem->style->stroke.isColor()) { | ||
1878 | 291 | gchar c[64]; | ||
1879 | 292 | sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); | ||
1880 | 293 | sp_repr_css_set_property (css, "fill", c); | ||
1881 | 294 | } else { | ||
1882 | 295 | sp_repr_css_set_property (css, "fill", "none"); | ||
1883 | 296 | } | ||
1884 | 297 | } else { | ||
1885 | 298 | sp_repr_css_unset_property (css, "fill"); | ||
1886 | 299 | } | ||
1887 | 300 | |||
1888 | 301 | sp_repr_css_set_property(css, "stroke", "none"); | ||
1889 | 302 | |||
1890 | 303 | sp_desktop_apply_css_recursive(item, css, true); | ||
1891 | 304 | sp_repr_css_attr_unref (css); | ||
1892 | 305 | |||
1893 | 306 | item->updateRepr(); | ||
1894 | 273 | if (pathv.empty()) { | 307 | if (pathv.empty()) { |
1896 | 274 | points.push_back( Geom::Point(0.,width) ); | 308 | points.push_back( Geom::Point(0.2,width) ); |
1897 | 275 | points.push_back( Geom::Point(0.5,width) ); | 309 | points.push_back( Geom::Point(0.5,width) ); |
1899 | 276 | points.push_back( Geom::Point(1.,width) ); | 310 | points.push_back( Geom::Point(0.8,width) ); |
1900 | 277 | } else { | 311 | } else { |
1901 | 278 | Geom::Path const &path = pathv.front(); | 312 | Geom::Path const &path = pathv.front(); |
1902 | 279 | Geom::Path::size_type const size = path.size_default(); | 313 | Geom::Path::size_type const size = path.size_default(); |
1904 | 280 | points.push_back( Geom::Point(0.,width) ); | 314 | if (!path.closed()) { |
1905 | 315 | points.push_back( Geom::Point(0.2,width) ); | ||
1906 | 316 | } | ||
1907 | 281 | points.push_back( Geom::Point(0.5*size,width) ); | 317 | points.push_back( Geom::Point(0.5*size,width) ); |
1908 | 282 | if (!path.closed()) { | 318 | if (!path.closed()) { |
1910 | 283 | points.push_back( Geom::Point(size,width) ); | 319 | points.push_back( Geom::Point(size - 0.2,width) ); |
1911 | 284 | } | 320 | } |
1912 | 285 | } | 321 | } |
1913 | 286 | offset_points.param_set_and_write_new_value(points); | 322 | offset_points.param_set_and_write_new_value(points); |
1914 | @@ -289,6 +325,45 @@ | |||
1915 | 289 | } | 325 | } |
1916 | 290 | } | 326 | } |
1917 | 291 | 327 | ||
1918 | 328 | void LPEPowerStroke::doOnRemove(SPLPEItem const* lpeitem) | ||
1919 | 329 | { | ||
1920 | 330 | if (SP_IS_SHAPE(lpeitem)) { | ||
1921 | 331 | SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem); | ||
1922 | 332 | SPCSSAttr *css = sp_repr_css_attr_new (); | ||
1923 | 333 | if (true) { | ||
1924 | 334 | if (lpeitem->style->fill.isPaintserver()) { | ||
1925 | 335 | SPPaintServer * server = lpeitem->style->getFillPaintServer(); | ||
1926 | 336 | if (server) { | ||
1927 | 337 | Glib::ustring str; | ||
1928 | 338 | str += "url(#"; | ||
1929 | 339 | str += server->getId(); | ||
1930 | 340 | str += ")"; | ||
1931 | 341 | sp_repr_css_set_property (css, "stroke", str.c_str()); | ||
1932 | 342 | } | ||
1933 | 343 | } else if (lpeitem->style->fill.isColor()) { | ||
1934 | 344 | gchar c[64]; | ||
1935 | 345 | sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); | ||
1936 | 346 | sp_repr_css_set_property (css, "stroke", c); | ||
1937 | 347 | } else { | ||
1938 | 348 | sp_repr_css_set_property (css, "stroke", "none"); | ||
1939 | 349 | } | ||
1940 | 350 | } else { | ||
1941 | 351 | sp_repr_css_unset_property (css, "stroke"); | ||
1942 | 352 | } | ||
1943 | 353 | |||
1944 | 354 | Inkscape::CSSOStringStream os; | ||
1945 | 355 | os << offset_points.median_width() * 2; | ||
1946 | 356 | sp_repr_css_set_property (css, "stroke-width", os.str().c_str()); | ||
1947 | 357 | |||
1948 | 358 | sp_repr_css_set_property(css, "fill", "none"); | ||
1949 | 359 | |||
1950 | 360 | sp_desktop_apply_css_recursive(item, css, true); | ||
1951 | 361 | sp_repr_css_attr_unref (css); | ||
1952 | 362 | |||
1953 | 363 | item->updateRepr(); | ||
1954 | 364 | } | ||
1955 | 365 | } | ||
1956 | 366 | |||
1957 | 292 | void | 367 | void |
1958 | 293 | LPEPowerStroke::adjustForNewPath(std::vector<Geom::Path> const & path_in) | 368 | LPEPowerStroke::adjustForNewPath(std::vector<Geom::Path> const & path_in) |
1959 | 294 | { | 369 | { |
1960 | @@ -588,6 +663,9 @@ | |||
1961 | 588 | if (Geom::Interpolate::CubicBezierJohan *johan = dynamic_cast<Geom::Interpolate::CubicBezierJohan*>(interpolator)) { | 663 | if (Geom::Interpolate::CubicBezierJohan *johan = dynamic_cast<Geom::Interpolate::CubicBezierJohan*>(interpolator)) { |
1962 | 589 | johan->setBeta(interpolator_beta); | 664 | johan->setBeta(interpolator_beta); |
1963 | 590 | } | 665 | } |
1964 | 666 | if (Geom::Interpolate::CubicBezierSmooth *smooth = dynamic_cast<Geom::Interpolate::CubicBezierSmooth*>(interpolator)) { | ||
1965 | 667 | smooth->setBeta(interpolator_beta); | ||
1966 | 668 | } | ||
1967 | 591 | Geom::Path strokepath = interpolator->interpolateToPath(ts); | 669 | Geom::Path strokepath = interpolator->interpolateToPath(ts); |
1968 | 592 | delete interpolator; | 670 | delete interpolator; |
1969 | 593 | 671 | ||
1970 | 594 | 672 | ||
1971 | === modified file 'src/live_effects/lpe-powerstroke.h' | |||
1972 | --- src/live_effects/lpe-powerstroke.h 2014-03-27 01:33:44 +0000 | |||
1973 | +++ src/live_effects/lpe-powerstroke.h 2014-09-07 17:02:32 +0000 | |||
1974 | @@ -25,9 +25,11 @@ | |||
1975 | 25 | LPEPowerStroke(LivePathEffectObject *lpeobject); | 25 | LPEPowerStroke(LivePathEffectObject *lpeobject); |
1976 | 26 | virtual ~LPEPowerStroke(); | 26 | virtual ~LPEPowerStroke(); |
1977 | 27 | 27 | ||
1978 | 28 | |||
1979 | 28 | virtual std::vector<Geom::Path> doEffect_path (std::vector<Geom::Path> const & path_in); | 29 | virtual std::vector<Geom::Path> doEffect_path (std::vector<Geom::Path> const & path_in); |
1980 | 29 | 30 | ||
1981 | 30 | virtual void doOnApply(SPLPEItem const* lpeitem); | 31 | virtual void doOnApply(SPLPEItem const* lpeitem); |
1982 | 32 | virtual void doOnRemove(SPLPEItem const* lpeitem); | ||
1983 | 31 | 33 | ||
1984 | 32 | // methods called by path-manipulator upon edits | 34 | // methods called by path-manipulator upon edits |
1985 | 33 | void adjustForNewPath(std::vector<Geom::Path> const & path_in); | 35 | void adjustForNewPath(std::vector<Geom::Path> const & path_in); |
1986 | 34 | 36 | ||
1987 | === modified file 'src/live_effects/lpe-tangent_to_curve.cpp' | |||
1988 | --- src/live_effects/lpe-tangent_to_curve.cpp 2014-03-27 01:33:44 +0000 | |||
1989 | +++ src/live_effects/lpe-tangent_to_curve.cpp 2014-09-07 17:02:32 +0000 | |||
1990 | @@ -16,8 +16,6 @@ | |||
1991 | 16 | #include <glibmm/i18n.h> | 16 | #include <glibmm/i18n.h> |
1992 | 17 | 17 | ||
1993 | 18 | #include "live_effects/lpe-tangent_to_curve.h" | 18 | #include "live_effects/lpe-tangent_to_curve.h" |
1994 | 19 | // FIXME: The following are only needed to convert the path's SPCurve* to pwd2. | ||
1995 | 20 | // There must be a more convenient way to achieve this. | ||
1996 | 21 | #include "sp-path.h" | 19 | #include "sp-path.h" |
1997 | 22 | #include "display/curve.h" | 20 | #include "display/curve.h" |
1998 | 23 | 21 | ||
1999 | @@ -108,13 +106,13 @@ | |||
2000 | 108 | { | 106 | { |
2001 | 109 | KnotHolderEntity *e = new TtC::KnotHolderEntityLeftEnd(this); | 107 | KnotHolderEntity *e = new TtC::KnotHolderEntityLeftEnd(this); |
2002 | 110 | e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, | 108 | e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, |
2004 | 111 | _("Adjust the \"left\" end of the tangent") ); | 109 | _("Adjust the <b>left</b> end of the tangent") ); |
2005 | 112 | knotholder->add(e); | 110 | knotholder->add(e); |
2006 | 113 | } | 111 | } |
2007 | 114 | { | 112 | { |
2008 | 115 | KnotHolderEntity *e = new TtC::KnotHolderEntityRightEnd(this); | 113 | KnotHolderEntity *e = new TtC::KnotHolderEntityRightEnd(this); |
2009 | 116 | e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, | 114 | e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, |
2011 | 117 | _("Adjust the \"right\" end of the tangent") ); | 115 | _("Adjust the <b>right</b> end of the tangent") ); |
2012 | 118 | knotholder->add(e); | 116 | knotholder->add(e); |
2013 | 119 | } | 117 | } |
2014 | 120 | }; | 118 | }; |
2015 | @@ -130,14 +128,13 @@ | |||
2016 | 130 | 128 | ||
2017 | 131 | Geom::Point const s = snap_knot_position(p, state); | 129 | Geom::Point const s = snap_knot_position(p, state); |
2018 | 132 | 130 | ||
2025 | 133 | // FIXME: There must be a better way of converting the path's SPCurve* to pwd2. | 131 | if ( !SP_IS_SHAPE(lpe->sp_lpe_item) ) { |
2026 | 134 | SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); | 132 | //lpe->t_attach.param_set_value(0); |
2027 | 135 | Geom::PathVector pathv = curve->get_pathvector(); | 133 | g_warning("LPEItem is not a path! %s:%d\n", __FILE__, __LINE__); |
2028 | 136 | Piecewise<D2<SBasis> > pwd2; | 134 | return; |
2023 | 137 | for (unsigned int i=0; i < pathv.size(); i++) { | ||
2024 | 138 | pwd2.concat(pathv[i].toPwSb()); | ||
2029 | 139 | } | 135 | } |
2031 | 140 | 136 | Piecewise<D2<SBasis> > pwd2 = paths_to_pw( lpe->pathvector_before_effect ); | |
2032 | 137 | |||
2033 | 141 | double t0 = nearest_point(s, pwd2); | 138 | double t0 = nearest_point(s, pwd2); |
2034 | 142 | lpe->t_attach.param_set_value(t0); | 139 | lpe->t_attach.param_set_value(t0); |
2035 | 143 | 140 | ||
2036 | 144 | 141 | ||
2037 | === modified file 'src/live_effects/lpe-tangent_to_curve.h' | |||
2038 | --- src/live_effects/lpe-tangent_to_curve.h 2012-04-07 14:09:58 +0000 | |||
2039 | +++ src/live_effects/lpe-tangent_to_curve.h 2014-09-07 17:02:32 +0000 | |||
2040 | @@ -34,7 +34,6 @@ | |||
2041 | 34 | public: | 34 | public: |
2042 | 35 | LPETangentToCurve(LivePathEffectObject *lpeobject); | 35 | LPETangentToCurve(LivePathEffectObject *lpeobject); |
2043 | 36 | virtual ~LPETangentToCurve(); | 36 | virtual ~LPETangentToCurve(); |
2044 | 37 | |||
2045 | 38 | virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > | 37 | virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > |
2046 | 39 | doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); | 38 | doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); |
2047 | 40 | 39 | ||
2048 | 41 | 40 | ||
2049 | === added file 'src/live_effects/lpe-taperstroke.cpp' | |||
2050 | --- src/live_effects/lpe-taperstroke.cpp 1970-01-01 00:00:00 +0000 | |||
2051 | +++ src/live_effects/lpe-taperstroke.cpp 2014-09-07 17:02:32 +0000 | |||
2052 | @@ -0,0 +1,630 @@ | |||
2053 | 1 | /** | ||
2054 | 2 | * @file | ||
2055 | 3 | * Taper Stroke path effect, provided as an alternative to Power Strokes | ||
2056 | 4 | * for otherwise constant-width paths. | ||
2057 | 5 | * | ||
2058 | 6 | * Authors: | ||
2059 | 7 | * Liam P White <inkscapebrony@gmail.com> | ||
2060 | 8 | * | ||
2061 | 9 | * Copyright (C) 2014 Authors | ||
2062 | 10 | * | ||
2063 | 11 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
2064 | 12 | */ | ||
2065 | 13 | |||
2066 | 14 | #include "live_effects/lpe-taperstroke.h" | ||
2067 | 15 | |||
2068 | 16 | #include <2geom/path.h> | ||
2069 | 17 | #include <2geom/shape.h> | ||
2070 | 18 | #include <2geom/path.h> | ||
2071 | 19 | #include <2geom/circle.h> | ||
2072 | 20 | #include <2geom/sbasis-to-bezier.h> | ||
2073 | 21 | #include "pathoutlineprovider.h" | ||
2074 | 22 | #include "display/curve.h" | ||
2075 | 23 | #include "sp-shape.h" | ||
2076 | 24 | #include "style.h" | ||
2077 | 25 | #include "xml/repr.h" | ||
2078 | 26 | #include "sp-paint-server.h" | ||
2079 | 27 | #include "svg/svg-color.h" | ||
2080 | 28 | #include "desktop-style.h" | ||
2081 | 29 | #include "svg/css-ostringstream.h" | ||
2082 | 30 | #include "svg/svg.h" | ||
2083 | 31 | |||
2084 | 32 | //#include <glibmm/i18n.h> | ||
2085 | 33 | |||
2086 | 34 | #include "knot-holder-entity.h" | ||
2087 | 35 | #include "knotholder.h" | ||
2088 | 36 | |||
2089 | 37 | template<typename T> | ||
2090 | 38 | inline bool withinRange(T value, T low, T high) { | ||
2091 | 39 | return (value > low && value < high); | ||
2092 | 40 | } | ||
2093 | 41 | |||
2094 | 42 | namespace Inkscape { | ||
2095 | 43 | namespace LivePathEffect { | ||
2096 | 44 | |||
2097 | 45 | namespace TpS { | ||
2098 | 46 | class KnotHolderEntityAttachBegin : public LPEKnotHolderEntity { | ||
2099 | 47 | public: | ||
2100 | 48 | KnotHolderEntityAttachBegin(LPETaperStroke * effect) : LPEKnotHolderEntity(effect) {} | ||
2101 | 49 | virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); | ||
2102 | 50 | virtual Geom::Point knot_get() const; | ||
2103 | 51 | }; | ||
2104 | 52 | |||
2105 | 53 | class KnotHolderEntityAttachEnd : public LPEKnotHolderEntity { | ||
2106 | 54 | public: | ||
2107 | 55 | KnotHolderEntityAttachEnd(LPETaperStroke * effect) : LPEKnotHolderEntity(effect) {} | ||
2108 | 56 | virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); | ||
2109 | 57 | virtual Geom::Point knot_get() const; | ||
2110 | 58 | }; | ||
2111 | 59 | } // TpS | ||
2112 | 60 | |||
2113 | 61 | static const Util::EnumData<unsigned> JoinType[] = { | ||
2114 | 62 | {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, | ||
2115 | 63 | {LINEJOIN_ROUND, N_("Rounded"), "round"}, | ||
2116 | 64 | {LINEJOIN_REFLECTED, N_("Reflected"), "reflected"}, | ||
2117 | 65 | {LINEJOIN_POINTY, N_("Miter"), "miter"}, | ||
2118 | 66 | {LINEJOIN_EXTRAPOLATED, N_("Extrapolated"), "extrapolated"} | ||
2119 | 67 | }; | ||
2120 | 68 | |||
2121 | 69 | static const Util::EnumDataConverter<unsigned> JoinTypeConverter(JoinType, sizeof (JoinType)/sizeof(*JoinType)); | ||
2122 | 70 | |||
2123 | 71 | LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : | ||
2124 | 72 | Effect(lpeobject), | ||
2125 | 73 | line_width(_("Stroke width"), _("The (non-tapered) width of the path"), "stroke_width", &wr, this, 1.), | ||
2126 | 74 | attach_start(_("Start offset"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2), | ||
2127 | 75 | attach_end(_("End offset"), _("The ending position of the taper"), "end_offset", &wr, this, 0.2), | ||
2128 | 76 | smoothing(_("Taper smoothing"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.5), | ||
2129 | 77 | join_type(_("Join type"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), | ||
2130 | 78 | miter_limit(_("Miter limit"), _("Limit for miter joins"), "miter_limit", &wr, this, 100.) | ||
2131 | 79 | { | ||
2132 | 80 | show_orig_path = true; | ||
2133 | 81 | _provides_knotholder_entities = true; | ||
2134 | 82 | |||
2135 | 83 | attach_start.param_set_digits(3); | ||
2136 | 84 | attach_end.param_set_digits(3); | ||
2137 | 85 | |||
2138 | 86 | |||
2139 | 87 | registerParameter( dynamic_cast<Parameter *>(&line_width) ); | ||
2140 | 88 | registerParameter( dynamic_cast<Parameter *>(&attach_start) ); | ||
2141 | 89 | registerParameter( dynamic_cast<Parameter *>(&attach_end) ); | ||
2142 | 90 | registerParameter( dynamic_cast<Parameter *>(&smoothing) ); | ||
2143 | 91 | registerParameter( dynamic_cast<Parameter *>(&join_type) ); | ||
2144 | 92 | registerParameter( dynamic_cast<Parameter *>(&miter_limit) ); | ||
2145 | 93 | } | ||
2146 | 94 | |||
2147 | 95 | LPETaperStroke::~LPETaperStroke() | ||
2148 | 96 | { | ||
2149 | 97 | |||
2150 | 98 | } | ||
2151 | 99 | |||
2152 | 100 | //from LPEPowerStroke -- sets fill if stroke color because we will | ||
2153 | 101 | //be converting to a fill to make the new join. | ||
2154 | 102 | |||
2155 | 103 | void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) | ||
2156 | 104 | { | ||
2157 | 105 | if (SP_IS_SHAPE(lpeitem)) { | ||
2158 | 106 | SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem); | ||
2159 | 107 | double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; | ||
2160 | 108 | |||
2161 | 109 | SPCSSAttr *css = sp_repr_css_attr_new (); | ||
2162 | 110 | if (true) { | ||
2163 | 111 | if (lpeitem->style->stroke.isPaintserver()) { | ||
2164 | 112 | SPPaintServer * server = lpeitem->style->getStrokePaintServer(); | ||
2165 | 113 | if (server) { | ||
2166 | 114 | Glib::ustring str; | ||
2167 | 115 | str += "url(#"; | ||
2168 | 116 | str += server->getId(); | ||
2169 | 117 | str += ")"; | ||
2170 | 118 | sp_repr_css_set_property (css, "fill", str.c_str()); | ||
2171 | 119 | } | ||
2172 | 120 | } else if (lpeitem->style->stroke.isColor()) { | ||
2173 | 121 | gchar c[64]; | ||
2174 | 122 | sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); | ||
2175 | 123 | sp_repr_css_set_property (css, "fill", c); | ||
2176 | 124 | } else { | ||
2177 | 125 | sp_repr_css_set_property (css, "fill", "none"); | ||
2178 | 126 | } | ||
2179 | 127 | } else { | ||
2180 | 128 | sp_repr_css_unset_property (css, "fill"); | ||
2181 | 129 | } | ||
2182 | 130 | |||
2183 | 131 | sp_repr_css_set_property(css, "stroke", "none"); | ||
2184 | 132 | |||
2185 | 133 | sp_desktop_apply_css_recursive(item, css, true); | ||
2186 | 134 | sp_repr_css_attr_unref (css); | ||
2187 | 135 | |||
2188 | 136 | line_width.param_set_value(width); | ||
2189 | 137 | } else { | ||
2190 | 138 | g_warning("LPE Join Type can only be applied to paths (not groups)."); | ||
2191 | 139 | } | ||
2192 | 140 | } | ||
2193 | 141 | |||
2194 | 142 | //from LPEPowerStroke -- sets stroke color from existing fill color | ||
2195 | 143 | |||
2196 | 144 | void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem) | ||
2197 | 145 | { | ||
2198 | 146 | |||
2199 | 147 | if (SP_IS_SHAPE(lpeitem)) { | ||
2200 | 148 | SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem); | ||
2201 | 149 | |||
2202 | 150 | SPCSSAttr *css = sp_repr_css_attr_new (); | ||
2203 | 151 | if (true) { | ||
2204 | 152 | if (lpeitem->style->fill.isPaintserver()) { | ||
2205 | 153 | SPPaintServer * server = lpeitem->style->getFillPaintServer(); | ||
2206 | 154 | if (server) { | ||
2207 | 155 | Glib::ustring str; | ||
2208 | 156 | str += "url(#"; | ||
2209 | 157 | str += server->getId(); | ||
2210 | 158 | str += ")"; | ||
2211 | 159 | sp_repr_css_set_property (css, "stroke", str.c_str()); | ||
2212 | 160 | } | ||
2213 | 161 | } else if (lpeitem->style->fill.isColor()) { | ||
2214 | 162 | gchar c[64]; | ||
2215 | 163 | sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); | ||
2216 | 164 | sp_repr_css_set_property (css, "stroke", c); | ||
2217 | 165 | } else { | ||
2218 | 166 | sp_repr_css_set_property (css, "stroke", "none"); | ||
2219 | 167 | } | ||
2220 | 168 | } else { | ||
2221 | 169 | sp_repr_css_unset_property (css, "stroke"); | ||
2222 | 170 | } | ||
2223 | 171 | |||
2224 | 172 | Inkscape::CSSOStringStream os; | ||
2225 | 173 | os << fabs(line_width); | ||
2226 | 174 | sp_repr_css_set_property (css, "stroke-width", os.str().c_str()); | ||
2227 | 175 | |||
2228 | 176 | sp_repr_css_set_property(css, "fill", "none"); | ||
2229 | 177 | |||
2230 | 178 | sp_desktop_apply_css_recursive(item, css, true); | ||
2231 | 179 | sp_repr_css_attr_unref (css); | ||
2232 | 180 | item->updateRepr(); | ||
2233 | 181 | } | ||
2234 | 182 | } | ||
2235 | 183 | |||
2236 | 184 | //actual effect impl here | ||
2237 | 185 | |||
2238 | 186 | Geom::Path return_at_first_cusp (Geom::Path const & path_in, double /*smooth_tolerance*/ = 0.05) | ||
2239 | 187 | { | ||
2240 | 188 | return Geom::split_at_cusps(path_in)[0]; | ||
2241 | 189 | } | ||
2242 | 190 | |||
2243 | 191 | Geom::Piecewise<Geom::D2<Geom::SBasis> > stretch_along(Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in, Geom::Path pattern, double width); | ||
2244 | 192 | |||
2245 | 193 | //references to pointers, because magic | ||
2246 | 194 | void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second); | ||
2247 | 195 | |||
2248 | 196 | Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) | ||
2249 | 197 | { | ||
2250 | 198 | Geom::Path first_cusp = return_at_first_cusp(path_in[0]); | ||
2251 | 199 | Geom::Path last_cusp = return_at_first_cusp(path_in[0].reverse()); | ||
2252 | 200 | |||
2253 | 201 | bool zeroStart = false; | ||
2254 | 202 | bool zeroEnd = false; | ||
2255 | 203 | bool metInMiddle = false; | ||
2256 | 204 | |||
2257 | 205 | //there is a pretty good chance that people will try to drag the knots | ||
2258 | 206 | //on top of each other, so block it | ||
2259 | 207 | |||
2260 | 208 | unsigned size = path_in[0].size(); | ||
2261 | 209 | if (size == first_cusp.size()) { | ||
2262 | 210 | //check to see if the knots were dragged over each other | ||
2263 | 211 | //if so, reset the end offset, but still allow the start offset. | ||
2264 | 212 | if ( attach_start >= (size - attach_end) ) { | ||
2265 | 213 | attach_end.param_set_value( size - attach_start ); | ||
2266 | 214 | metInMiddle = true; | ||
2267 | 215 | } | ||
2268 | 216 | } | ||
2269 | 217 | |||
2270 | 218 | if (attach_start == size - attach_end) { | ||
2271 | 219 | metInMiddle = true; | ||
2272 | 220 | } | ||
2273 | 221 | if (attach_end == size - attach_start) { | ||
2274 | 222 | metInMiddle = true; | ||
2275 | 223 | } | ||
2276 | 224 | |||
2277 | 225 | //don't let it be integer | ||
2278 | 226 | { | ||
2279 | 227 | if (double(unsigned(attach_start)) == attach_start) { | ||
2280 | 228 | attach_start.param_set_value(attach_start - 0.00001); | ||
2281 | 229 | } | ||
2282 | 230 | if (double(unsigned(attach_end)) == attach_end) { | ||
2283 | 231 | attach_end.param_set_value(attach_end - 0.00001); | ||
2284 | 232 | } | ||
2285 | 233 | } | ||
2286 | 234 | |||
2287 | 235 | unsigned allowed_start = first_cusp.size(); | ||
2288 | 236 | unsigned allowed_end = last_cusp.size(); | ||
2289 | 237 | |||
2290 | 238 | //don't let the knots be farther than they are allowed to be | ||
2291 | 239 | { | ||
2292 | 240 | if ((unsigned)attach_start >= allowed_start) { | ||
2293 | 241 | attach_start.param_set_value((double)allowed_start - 0.00001); | ||
2294 | 242 | } | ||
2295 | 243 | if ((unsigned)attach_end >= allowed_end) { | ||
2296 | 244 | attach_end.param_set_value((double)allowed_end - 0.00001); | ||
2297 | 245 | } | ||
2298 | 246 | } | ||
2299 | 247 | |||
2300 | 248 | //don't let it be zero | ||
2301 | 249 | if (attach_start < 0.0000001 || withinRange(double(attach_start), 0.00000001, 0.000001)) { | ||
2302 | 250 | attach_start.param_set_value( 0.0000001 ); | ||
2303 | 251 | zeroStart = true; | ||
2304 | 252 | } | ||
2305 | 253 | if (attach_end < 0.0000001 || withinRange(double(attach_end), 0.00000001, 0.000001)) { | ||
2306 | 254 | attach_end.param_set_value( 0.0000001 ); | ||
2307 | 255 | zeroEnd = true; | ||
2308 | 256 | } | ||
2309 | 257 | |||
2310 | 258 | //remember, Path::operator () means get point at time t | ||
2311 | 259 | start_attach_point = first_cusp(attach_start); | ||
2312 | 260 | end_attach_point = last_cusp(attach_end); | ||
2313 | 261 | Geom::PathVector pathv_out; | ||
2314 | 262 | |||
2315 | 263 | //the following function just splits it up into three pieces. | ||
2316 | 264 | pathv_out = doEffect_simplePath(path_in); | ||
2317 | 265 | |||
2318 | 266 | //now for the actual tapering. We use the stretch_along method to get this done. | ||
2319 | 267 | |||
2320 | 268 | Geom::PathVector real_pathv; | ||
2321 | 269 | Geom::Path real_path; | ||
2322 | 270 | Geom::PathVector pat_vec; | ||
2323 | 271 | Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2; | ||
2324 | 272 | Geom::Path throwaway_path; | ||
2325 | 273 | |||
2326 | 274 | if (!zeroStart) { | ||
2327 | 275 | //Construct the pattern (pat_str stands for pattern string) (and yes, this is easier, trust me) | ||
2328 | 276 | std::stringstream pat_str; | ||
2329 | 277 | pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1"; | ||
2330 | 278 | |||
2331 | 279 | pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); | ||
2332 | 280 | pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], -fabs(line_width))); | ||
2333 | 281 | throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; | ||
2334 | 282 | |||
2335 | 283 | real_path.append(throwaway_path); | ||
2336 | 284 | } | ||
2337 | 285 | |||
2338 | 286 | if (!metInMiddle) { | ||
2339 | 287 | //append the outside outline of the path (with direction) | ||
2340 | 288 | throwaway_path = Outline::PathOutsideOutline(pathv_out[1], | ||
2341 | 289 | -fabs(line_width), static_cast<LineJoinType>(join_type.get_value()), miter_limit); | ||
2342 | 290 | if (!zeroStart && real_path.size() >= 1 && throwaway_path.size() >= 1) { | ||
2343 | 291 | if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001) { | ||
2344 | 292 | real_path.appendNew<Geom::LineSegment>(throwaway_path.initialPoint()); | ||
2345 | 293 | } else { | ||
2346 | 294 | real_path.setFinal(throwaway_path.initialPoint()); | ||
2347 | 295 | } | ||
2348 | 296 | } | ||
2349 | 297 | real_path.append(throwaway_path); | ||
2350 | 298 | } | ||
2351 | 299 | |||
2352 | 300 | if (!zeroEnd) { | ||
2353 | 301 | //append the ending taper | ||
2354 | 302 | std::stringstream pat_str_1; | ||
2355 | 303 | pat_str_1 << "M 0,1 C " << (double)smoothing << ",1 1,0.5 1,0.5 1,0.5 " << double(smoothing) << ",0 0,0"; | ||
2356 | 304 | pat_vec = sp_svg_read_pathv(pat_str_1.str().c_str()); | ||
2357 | 305 | |||
2358 | 306 | pwd2 = Geom::Piecewise<Geom::D2<Geom::SBasis> > (); | ||
2359 | 307 | pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); | ||
2360 | 308 | |||
2361 | 309 | throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; | ||
2362 | 310 | if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001 && real_path.size() >= 1) { | ||
2363 | 311 | real_path.appendNew<Geom::LineSegment>(throwaway_path.initialPoint()); | ||
2364 | 312 | } else { | ||
2365 | 313 | real_path.setFinal(throwaway_path.initialPoint()); | ||
2366 | 314 | } | ||
2367 | 315 | real_path.append(throwaway_path); | ||
2368 | 316 | } | ||
2369 | 317 | |||
2370 | 318 | if (!metInMiddle) { | ||
2371 | 319 | //append the inside outline of the path (against direction) | ||
2372 | 320 | throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), | ||
2373 | 321 | -fabs(line_width), static_cast<LineJoinType>(join_type.get_value()), miter_limit); | ||
2374 | 322 | |||
2375 | 323 | if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001 && real_path.size() >= 1) { | ||
2376 | 324 | real_path.appendNew<Geom::LineSegment>(throwaway_path.initialPoint()); | ||
2377 | 325 | } else { | ||
2378 | 326 | real_path.setFinal(throwaway_path.initialPoint()); | ||
2379 | 327 | } | ||
2380 | 328 | real_path.append(throwaway_path); | ||
2381 | 329 | } | ||
2382 | 330 | |||
2383 | 331 | if (Geom::distance(real_path.finalPoint(), real_path.initialPoint()) > 0.0000001) { | ||
2384 | 332 | real_path.appendNew<Geom::LineSegment>(real_path.initialPoint()); | ||
2385 | 333 | } else { | ||
2386 | 334 | real_path.setFinal(real_path.initialPoint()); | ||
2387 | 335 | } | ||
2388 | 336 | real_path.close(); | ||
2389 | 337 | |||
2390 | 338 | real_pathv.push_back(real_path); | ||
2391 | 339 | |||
2392 | 340 | return real_pathv; | ||
2393 | 341 | } | ||
2394 | 342 | |||
2395 | 343 | //in all cases, this should return a PathVector with three elements. | ||
2396 | 344 | Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & path_in) | ||
2397 | 345 | { | ||
2398 | 346 | unsigned size = path_in[0].size(); | ||
2399 | 347 | |||
2400 | 348 | //do subdivision and get out | ||
2401 | 349 | unsigned loc = (unsigned)attach_start; | ||
2402 | 350 | Geom::Curve * curve_start = path_in[0] [loc].duplicate(); | ||
2403 | 351 | |||
2404 | 352 | std::vector<Geom::Path> pathv_out; | ||
2405 | 353 | Geom::Path path_out = Geom::Path(); | ||
2406 | 354 | |||
2407 | 355 | Geom::Path trimmed_start = Geom::Path(); | ||
2408 | 356 | Geom::Path trimmed_end = Geom::Path(); | ||
2409 | 357 | |||
2410 | 358 | for (unsigned i = 0; i < loc; i++) { | ||
2411 | 359 | trimmed_start.append(path_in[0] [i]); | ||
2412 | 360 | } | ||
2413 | 361 | |||
2414 | 362 | Geom::Curve * temp; | ||
2415 | 363 | subdivideCurve(curve_start, attach_start - loc, temp, curve_start); | ||
2416 | 364 | trimmed_start.append(*temp); | ||
2417 | 365 | if (temp) delete temp; temp = 0; | ||
2418 | 366 | |||
2419 | 367 | //special case: path is one segment long | ||
2420 | 368 | //special case: what if the two knots occupy the same segment? | ||
2421 | 369 | if ((size == 1) || ( size - unsigned(attach_end) - 1 == loc )) { | ||
2422 | 370 | Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_start); | ||
2423 | 371 | |||
2424 | 372 | //it is just a dumb segment | ||
2425 | 373 | //we have to do some shifting here because the value changed when we reduced the length | ||
2426 | 374 | //of the previous segment. | ||
2427 | 375 | |||
2428 | 376 | subdivideCurve(curve_start, t, curve_start, temp); | ||
2429 | 377 | trimmed_end.append(*temp); | ||
2430 | 378 | if (temp) delete temp; temp = 0; | ||
2431 | 379 | |||
2432 | 380 | for (unsigned j = (size - attach_end) + 1; j < size; j++) { | ||
2433 | 381 | trimmed_end.append(path_in[0] [j]); | ||
2434 | 382 | } | ||
2435 | 383 | |||
2436 | 384 | path_out.append(*curve_start); | ||
2437 | 385 | pathv_out.push_back(trimmed_start); | ||
2438 | 386 | pathv_out.push_back(path_out); | ||
2439 | 387 | pathv_out.push_back(trimmed_end); | ||
2440 | 388 | return pathv_out; | ||
2441 | 389 | } | ||
2442 | 390 | |||
2443 | 391 | pathv_out.push_back(trimmed_start); | ||
2444 | 392 | |||
2445 | 393 | //append almost all of the rest of the path, ignore the curves that the knot is past (we'll get to it in a minute) | ||
2446 | 394 | path_out.append(*curve_start); | ||
2447 | 395 | |||
2448 | 396 | for (unsigned k = loc + 1; k < (size - unsigned(attach_end)) - 1; k++) { | ||
2449 | 397 | path_out.append(path_in[0] [k]); | ||
2450 | 398 | } | ||
2451 | 399 | |||
2452 | 400 | //deal with the last segment in a very similar fashion to the first | ||
2453 | 401 | loc = size - attach_end; | ||
2454 | 402 | |||
2455 | 403 | Geom::Curve * curve_end = path_in[0] [loc].duplicate(); | ||
2456 | 404 | |||
2457 | 405 | Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_end); | ||
2458 | 406 | |||
2459 | 407 | subdivideCurve(curve_end, t, curve_end, temp); | ||
2460 | 408 | trimmed_end.append(*temp); | ||
2461 | 409 | if (temp) delete temp; temp = 0; | ||
2462 | 410 | |||
2463 | 411 | for (unsigned j = (size - attach_end) + 1; j < size; j++) { | ||
2464 | 412 | trimmed_end.append(path_in[0] [j]); | ||
2465 | 413 | } | ||
2466 | 414 | |||
2467 | 415 | path_out.append(*curve_end); | ||
2468 | 416 | pathv_out.push_back(path_out); | ||
2469 | 417 | |||
2470 | 418 | pathv_out.push_back(trimmed_end); | ||
2471 | 419 | |||
2472 | 420 | if (curve_end) delete curve_end; | ||
2473 | 421 | if (curve_start) delete curve_start; | ||
2474 | 422 | return pathv_out; | ||
2475 | 423 | } | ||
2476 | 424 | |||
2477 | 425 | |||
2478 | 426 | //most of the below code is verbatim from Pattern Along Path. However, it needed a little | ||
2479 | 427 | //tweaking to get it to work right in this case. | ||
2480 | 428 | Geom::Piecewise<Geom::D2<Geom::SBasis> > stretch_along(Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in, Geom::Path pattern, double prop_scale) | ||
2481 | 429 | { | ||
2482 | 430 | using namespace Geom; | ||
2483 | 431 | |||
2484 | 432 | // Don't allow empty path parameter: | ||
2485 | 433 | if ( pattern.empty() ) { | ||
2486 | 434 | return pwd2_in; | ||
2487 | 435 | } | ||
2488 | 436 | |||
2489 | 437 | /* Much credit should go to jfb and mgsloan of lib2geom development for the code below! */ | ||
2490 | 438 | Piecewise<D2<SBasis> > output; | ||
2491 | 439 | std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > pre_output; | ||
2492 | 440 | |||
2493 | 441 | D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(pattern.toPwSb()); | ||
2494 | 442 | Piecewise<SBasis> x0 = Piecewise<SBasis>(patternd2[0]); | ||
2495 | 443 | Piecewise<SBasis> y0 = Piecewise<SBasis>(patternd2[1]); | ||
2496 | 444 | OptInterval pattBndsX = bounds_exact(x0); | ||
2497 | 445 | OptInterval pattBndsY = bounds_exact(y0); | ||
2498 | 446 | if (pattBndsX && pattBndsY) { | ||
2499 | 447 | x0 -= pattBndsX->min(); | ||
2500 | 448 | y0 -= pattBndsY->middle(); | ||
2501 | 449 | |||
2502 | 450 | double xspace = 0; | ||
2503 | 451 | double noffset = 0; | ||
2504 | 452 | double toffset = 0; | ||
2505 | 453 | //Prevent more than 90% overlap... | ||
2506 | 454 | if (xspace < -pattBndsX->extent()*.9) { | ||
2507 | 455 | xspace = -pattBndsX->extent()*.9; | ||
2508 | 456 | } | ||
2509 | 457 | |||
2510 | 458 | y0+=noffset; | ||
2511 | 459 | |||
2512 | 460 | std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > paths_in; | ||
2513 | 461 | paths_in = split_at_discontinuities(pwd2_in); | ||
2514 | 462 | |||
2515 | 463 | for (unsigned idx = 0; idx < paths_in.size(); idx++) { | ||
2516 | 464 | Geom::Piecewise<Geom::D2<Geom::SBasis> > path_i = paths_in[idx]; | ||
2517 | 465 | Piecewise<SBasis> x = x0; | ||
2518 | 466 | Piecewise<SBasis> y = y0; | ||
2519 | 467 | Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(path_i,2,.1); | ||
2520 | 468 | uskeleton = remove_short_cuts(uskeleton,.01); | ||
2521 | 469 | Piecewise<D2<SBasis> > n = rot90(derivative(uskeleton)); | ||
2522 | 470 | n = force_continuity(remove_short_cuts(n,.1)); | ||
2523 | 471 | |||
2524 | 472 | int nbCopies = 0; | ||
2525 | 473 | double scaling = 1; | ||
2526 | 474 | nbCopies = 1; | ||
2527 | 475 | scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent(); | ||
2528 | 476 | |||
2529 | 477 | double pattWidth = pattBndsX->extent() * scaling; | ||
2530 | 478 | |||
2531 | 479 | if (scaling != 1.0) { | ||
2532 | 480 | x*=scaling; | ||
2533 | 481 | } | ||
2534 | 482 | if ( false ) { | ||
2535 | 483 | y*=(scaling*prop_scale); | ||
2536 | 484 | } else { | ||
2537 | 485 | if (prop_scale != 1.0) y *= prop_scale; | ||
2538 | 486 | } | ||
2539 | 487 | x += toffset; | ||
2540 | 488 | |||
2541 | 489 | double offs = 0; | ||
2542 | 490 | for (int i=0; i<nbCopies; i++) { | ||
2543 | 491 | if (false) { | ||
2544 | 492 | Geom::Piecewise<Geom::D2<Geom::SBasis> > output_piece = compose(uskeleton,x+offs)+y*compose(n,x+offs); | ||
2545 | 493 | std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > splited_output_piece = split_at_discontinuities(output_piece); | ||
2546 | 494 | pre_output.insert(pre_output.end(), splited_output_piece.begin(), splited_output_piece.end() ); | ||
2547 | 495 | } else { | ||
2548 | 496 | output.concat(compose(uskeleton,x+offs)+y*compose(n,x+offs)); | ||
2549 | 497 | } | ||
2550 | 498 | offs+=pattWidth; | ||
2551 | 499 | } | ||
2552 | 500 | } | ||
2553 | 501 | return output; | ||
2554 | 502 | } else { | ||
2555 | 503 | return pwd2_in; | ||
2556 | 504 | } | ||
2557 | 505 | } | ||
2558 | 506 | |||
2559 | 507 | void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second) | ||
2560 | 508 | { | ||
2561 | 509 | if (Geom::LineSegment* linear = dynamic_cast<Geom::LineSegment*>(curve_in)) { | ||
2562 | 510 | //special case for line segments | ||
2563 | 511 | std::pair<Geom::LineSegment, Geom::LineSegment> seg_pair = linear->subdivide(t); | ||
2564 | 512 | val_first = seg_pair.first.duplicate(); | ||
2565 | 513 | val_second = seg_pair.second.duplicate(); | ||
2566 | 514 | } else { | ||
2567 | 515 | //all other cases: | ||
2568 | 516 | Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(curve_in->toSBasis()); | ||
2569 | 517 | std::pair<Geom::CubicBezier, Geom::CubicBezier> cubic_pair = cubic.subdivide(t); | ||
2570 | 518 | val_first = cubic_pair.first.duplicate(); | ||
2571 | 519 | val_second = cubic_pair.second.duplicate(); | ||
2572 | 520 | } | ||
2573 | 521 | } | ||
2574 | 522 | |||
2575 | 523 | |||
2576 | 524 | void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) | ||
2577 | 525 | { | ||
2578 | 526 | { | ||
2579 | 527 | KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this); | ||
2580 | 528 | e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, | ||
2581 | 529 | _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE ); | ||
2582 | 530 | knotholder->add(e); | ||
2583 | 531 | } | ||
2584 | 532 | { | ||
2585 | 533 | KnotHolderEntity *e = new TpS::KnotHolderEntityAttachEnd(this); | ||
2586 | 534 | e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, | ||
2587 | 535 | _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE ); | ||
2588 | 536 | knotholder->add(e); | ||
2589 | 537 | } | ||
2590 | 538 | } | ||
2591 | 539 | |||
2592 | 540 | namespace TpS { | ||
2593 | 541 | void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) | ||
2594 | 542 | { | ||
2595 | 543 | using namespace Geom; | ||
2596 | 544 | |||
2597 | 545 | LPETaperStroke* lpe = dynamic_cast<LPETaperStroke *>(_effect); | ||
2598 | 546 | |||
2599 | 547 | Geom::Point const s = snap_knot_position(p, state); | ||
2600 | 548 | |||
2601 | 549 | if (!SP_IS_SHAPE(lpe->sp_lpe_item) ) { | ||
2602 | 550 | g_warning("LPEItem is not a path! %s:%d\n", __FILE__, __LINE__); | ||
2603 | 551 | return; | ||
2604 | 552 | } | ||
2605 | 553 | |||
2606 | 554 | SPCurve* curve; | ||
2607 | 555 | if ( !(curve = SP_SHAPE(lpe->sp_lpe_item)->getCurve()) ) { | ||
2608 | 556 | //oops | ||
2609 | 557 | //lpe->attach_start.param_set_value(0); | ||
2610 | 558 | return; | ||
2611 | 559 | } | ||
2612 | 560 | //in case you are wondering, the above are simply sanity checks. we never want to actually | ||
2613 | 561 | //use that object. | ||
2614 | 562 | |||
2615 | 563 | Geom::PathVector pathv = lpe->pathvector_before_effect; | ||
2616 | 564 | |||
2617 | 565 | Piecewise<D2<SBasis> > pwd2; | ||
2618 | 566 | Geom::Path p_in = return_at_first_cusp(pathv[0]); | ||
2619 | 567 | pwd2.concat(p_in.toPwSb()); | ||
2620 | 568 | |||
2621 | 569 | double t0 = nearest_point(s, pwd2); | ||
2622 | 570 | lpe->attach_start.param_set_value(t0); | ||
2623 | 571 | |||
2624 | 572 | // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. | ||
2625 | 573 | sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); | ||
2626 | 574 | } | ||
2627 | 575 | void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const& /*origin*/, guint state) | ||
2628 | 576 | { | ||
2629 | 577 | using namespace Geom; | ||
2630 | 578 | |||
2631 | 579 | LPETaperStroke* lpe = dynamic_cast<LPETaperStroke *>(_effect); | ||
2632 | 580 | |||
2633 | 581 | Geom::Point const s = snap_knot_position(p, state); | ||
2634 | 582 | |||
2635 | 583 | if (!SP_IS_SHAPE(lpe->sp_lpe_item) ) { | ||
2636 | 584 | g_warning("LPEItem is not a path! %s:%d\n", __FILE__, __LINE__); | ||
2637 | 585 | return; | ||
2638 | 586 | } | ||
2639 | 587 | |||
2640 | 588 | SPCurve* curve; | ||
2641 | 589 | if ( !(curve = SP_SHAPE(lpe->sp_lpe_item)->getCurve()) ) { | ||
2642 | 590 | //oops | ||
2643 | 591 | //lpe->attach_end.param_set_value(0); | ||
2644 | 592 | return; | ||
2645 | 593 | } | ||
2646 | 594 | Geom::PathVector pathv = lpe->pathvector_before_effect; | ||
2647 | 595 | Geom::Path p_in = return_at_first_cusp(pathv[0].reverse()); | ||
2648 | 596 | Piecewise<D2<SBasis> > pwd2 = p_in.toPwSb(); | ||
2649 | 597 | |||
2650 | 598 | double t0 = nearest_point(s, pwd2); | ||
2651 | 599 | lpe->attach_end.param_set_value(t0); | ||
2652 | 600 | |||
2653 | 601 | sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); | ||
2654 | 602 | } | ||
2655 | 603 | Geom::Point KnotHolderEntityAttachBegin::knot_get() const | ||
2656 | 604 | { | ||
2657 | 605 | LPETaperStroke const * lpe = dynamic_cast<LPETaperStroke const*> (_effect); | ||
2658 | 606 | return lpe->start_attach_point; | ||
2659 | 607 | } | ||
2660 | 608 | Geom::Point KnotHolderEntityAttachEnd::knot_get() const | ||
2661 | 609 | { | ||
2662 | 610 | LPETaperStroke const * lpe = dynamic_cast<LPETaperStroke const*> (_effect); | ||
2663 | 611 | return lpe->end_attach_point; | ||
2664 | 612 | } | ||
2665 | 613 | } | ||
2666 | 614 | |||
2667 | 615 | |||
2668 | 616 | /* ######################## */ | ||
2669 | 617 | |||
2670 | 618 | } //namespace LivePathEffect | ||
2671 | 619 | } /* namespace Inkscape */ | ||
2672 | 620 | |||
2673 | 621 | /* | ||
2674 | 622 | Local Variables: | ||
2675 | 623 | mode:c++ | ||
2676 | 624 | c-file-style:"stroustrup" | ||
2677 | 625 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
2678 | 626 | indent-tabs-mode:nil | ||
2679 | 627 | fill-column:99 | ||
2680 | 628 | End: | ||
2681 | 629 | */ | ||
2682 | 630 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : | ||
2683 | 0 | 631 | ||
2684 | === added file 'src/live_effects/lpe-taperstroke.h' | |||
2685 | --- src/live_effects/lpe-taperstroke.h 1970-01-01 00:00:00 +0000 | |||
2686 | +++ src/live_effects/lpe-taperstroke.h 2014-09-07 17:02:32 +0000 | |||
2687 | @@ -0,0 +1,72 @@ | |||
2688 | 1 | /** @file | ||
2689 | 2 | * @brief Taper Stroke path effect (meant as a replacement for using Power Strokes for tapering) | ||
2690 | 3 | */ | ||
2691 | 4 | /* Authors: | ||
2692 | 5 | * Liam P White <inkscapebrony@gmail.com> | ||
2693 | 6 | * Copyright (C) 2014 Authors | ||
2694 | 7 | * | ||
2695 | 8 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
2696 | 9 | */ | ||
2697 | 10 | |||
2698 | 11 | #ifndef INKSCAPE_LPE_TAPERSTROKE_H | ||
2699 | 12 | #define INKSCAPE_LPE_TAPERSTROKE_H | ||
2700 | 13 | |||
2701 | 14 | #include "live_effects/parameter/enum.h" | ||
2702 | 15 | #include "live_effects/effect.h" | ||
2703 | 16 | #include "live_effects/parameter/parameter.h" | ||
2704 | 17 | #include "live_effects/parameter/vector.h" | ||
2705 | 18 | |||
2706 | 19 | namespace Inkscape { | ||
2707 | 20 | namespace LivePathEffect { | ||
2708 | 21 | |||
2709 | 22 | namespace TpS { | ||
2710 | 23 | // we need a separate namespace to avoid clashes with other LPEs | ||
2711 | 24 | class KnotHolderEntityAttachBegin; | ||
2712 | 25 | class KnotHolderEntityAttachEnd; | ||
2713 | 26 | } | ||
2714 | 27 | |||
2715 | 28 | class LPETaperStroke : public Effect { | ||
2716 | 29 | public: | ||
2717 | 30 | LPETaperStroke(LivePathEffectObject *lpeobject); | ||
2718 | 31 | virtual ~LPETaperStroke(); | ||
2719 | 32 | |||
2720 | 33 | virtual void doOnApply(SPLPEItem const* lpeitem); | ||
2721 | 34 | virtual void doOnRemove(SPLPEItem const* lpeitem); | ||
2722 | 35 | |||
2723 | 36 | virtual Geom::PathVector doEffect_path (Geom::PathVector const& path_in); | ||
2724 | 37 | Geom::PathVector doEffect_simplePath(Geom::PathVector const& path_in); | ||
2725 | 38 | |||
2726 | 39 | virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item); | ||
2727 | 40 | |||
2728 | 41 | friend class TpS::KnotHolderEntityAttachBegin; | ||
2729 | 42 | friend class TpS::KnotHolderEntityAttachEnd; | ||
2730 | 43 | private: | ||
2731 | 44 | ScalarParam line_width; | ||
2732 | 45 | ScalarParam attach_start; | ||
2733 | 46 | ScalarParam attach_end; | ||
2734 | 47 | ScalarParam smoothing; | ||
2735 | 48 | EnumParam<unsigned> join_type; | ||
2736 | 49 | ScalarParam miter_limit; | ||
2737 | 50 | |||
2738 | 51 | Geom::Point start_attach_point; | ||
2739 | 52 | Geom::Point end_attach_point; | ||
2740 | 53 | |||
2741 | 54 | LPETaperStroke(const LPETaperStroke&); | ||
2742 | 55 | LPETaperStroke& operator=(const LPETaperStroke&); | ||
2743 | 56 | }; | ||
2744 | 57 | |||
2745 | 58 | } //namespace LivePathEffect | ||
2746 | 59 | } //namespace Inkscape | ||
2747 | 60 | |||
2748 | 61 | #endif | ||
2749 | 62 | |||
2750 | 63 | /* | ||
2751 | 64 | Local Variables: | ||
2752 | 65 | mode:c++ | ||
2753 | 66 | c-file-style:"stroustrup" | ||
2754 | 67 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
2755 | 68 | indent-tabs-mode:nil | ||
2756 | 69 | fill-column:99 | ||
2757 | 70 | End: | ||
2758 | 71 | */ | ||
2759 | 72 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : | ||
2760 | 0 | 73 | ||
2761 | === modified file 'src/live_effects/parameter/Makefile_insert' | |||
2762 | --- src/live_effects/parameter/Makefile_insert 2014-07-02 11:14:35 +0000 | |||
2763 | +++ src/live_effects/parameter/Makefile_insert 2014-09-07 17:02:32 +0000 | |||
2764 | @@ -20,12 +20,16 @@ | |||
2765 | 20 | live_effects/parameter/path.h \ | 20 | live_effects/parameter/path.h \ |
2766 | 21 | live_effects/parameter/originalpath.cpp \ | 21 | live_effects/parameter/originalpath.cpp \ |
2767 | 22 | live_effects/parameter/originalpath.h \ | 22 | live_effects/parameter/originalpath.h \ |
2768 | 23 | live_effects/parameter/originalpatharray.cpp \ | ||
2769 | 24 | live_effects/parameter/originalpatharray.h \ | ||
2770 | 23 | live_effects/parameter/powerstrokepointarray.cpp \ | 25 | live_effects/parameter/powerstrokepointarray.cpp \ |
2771 | 24 | live_effects/parameter/powerstrokepointarray.h \ | 26 | live_effects/parameter/powerstrokepointarray.h \ |
2772 | 25 | live_effects/parameter/filletchamferpointarray.cpp \ | 27 | live_effects/parameter/filletchamferpointarray.cpp \ |
2773 | 26 | live_effects/parameter/filletchamferpointarray.h \ | 28 | live_effects/parameter/filletchamferpointarray.h \ |
2774 | 27 | live_effects/parameter/text.cpp \ | 29 | live_effects/parameter/text.cpp \ |
2775 | 28 | live_effects/parameter/text.h \ | 30 | live_effects/parameter/text.h \ |
2776 | 31 | live_effects/parameter/transformedpoint.cpp \ | ||
2777 | 32 | live_effects/parameter/transformedpoint.h \ | ||
2778 | 29 | live_effects/parameter/togglebutton.cpp \ | 33 | live_effects/parameter/togglebutton.cpp \ |
2779 | 30 | live_effects/parameter/togglebutton.h \ | 34 | live_effects/parameter/togglebutton.h \ |
2780 | 31 | live_effects/parameter/unit.cpp \ | 35 | live_effects/parameter/unit.cpp \ |
2781 | 32 | 36 | ||
2782 | === modified file 'src/live_effects/parameter/filletchamferpointarray.cpp' | |||
2783 | --- src/live_effects/parameter/filletchamferpointarray.cpp 2014-08-24 10:37:18 +0000 | |||
2784 | +++ src/live_effects/parameter/filletchamferpointarray.cpp 2014-09-07 17:02:32 +0000 | |||
2785 | @@ -8,11 +8,14 @@ | |||
2786 | 8 | * Released under GNU GPL, read the file 'COPYING' for more information | 8 | * Released under GNU GPL, read the file 'COPYING' for more information |
2787 | 9 | */ | 9 | */ |
2788 | 10 | 10 | ||
2789 | 11 | #include <glibmm.h> | ||
2790 | 12 | |||
2791 | 11 | #include "ui/dialog/lpe-fillet-chamfer-properties.h" | 13 | #include "ui/dialog/lpe-fillet-chamfer-properties.h" |
2792 | 12 | #include "live_effects/parameter/filletchamferpointarray.h" | 14 | #include "live_effects/parameter/filletchamferpointarray.h" |
2793 | 13 | #include <2geom/piecewise.h> | 15 | #include <2geom/piecewise.h> |
2794 | 14 | #include <2geom/sbasis-to-bezier.h> | 16 | #include <2geom/sbasis-to-bezier.h> |
2795 | 15 | #include <2geom/sbasis-geometric.h> | 17 | #include <2geom/sbasis-geometric.h> |
2796 | 18 | #include <gtkmm.h> | ||
2797 | 16 | 19 | ||
2798 | 17 | #include "live_effects/effect.h" | 20 | #include "live_effects/effect.h" |
2799 | 18 | #include "svg/svg.h" | 21 | #include "svg/svg.h" |
2800 | 19 | 22 | ||
2801 | === added file 'src/live_effects/parameter/originalpatharray.cpp' | |||
2802 | --- src/live_effects/parameter/originalpatharray.cpp 1970-01-01 00:00:00 +0000 | |||
2803 | +++ src/live_effects/parameter/originalpatharray.cpp 2014-09-07 17:02:32 +0000 | |||
2804 | @@ -0,0 +1,497 @@ | |||
2805 | 1 | /* | ||
2806 | 2 | * Copyright (C) Johan Engelen 2008 <j.b.c.engelen@utwente.nl> | ||
2807 | 3 | * | ||
2808 | 4 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
2809 | 5 | */ | ||
2810 | 6 | |||
2811 | 7 | #ifdef HAVE_CONFIG_H | ||
2812 | 8 | # include "config.h" | ||
2813 | 9 | #endif | ||
2814 | 10 | |||
2815 | 11 | #if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H | ||
2816 | 12 | #include <glibmm/threads.h> | ||
2817 | 13 | #endif | ||
2818 | 14 | |||
2819 | 15 | #include "live_effects/parameter/originalpatharray.h" | ||
2820 | 16 | |||
2821 | 17 | #include <gtkmm/widget.h> | ||
2822 | 18 | #include <gtkmm/icontheme.h> | ||
2823 | 19 | #include <gtkmm/imagemenuitem.h> | ||
2824 | 20 | #include <gtkmm/separatormenuitem.h> | ||
2825 | 21 | #include <gtkmm/scrolledwindow.h> | ||
2826 | 22 | |||
2827 | 23 | #include <glibmm/i18n.h> | ||
2828 | 24 | |||
2829 | 25 | #include "inkscape.h" | ||
2830 | 26 | #include "icon-size.h" | ||
2831 | 27 | #include "widgets/icon.h" | ||
2832 | 28 | #include "ui/clipboard.h" | ||
2833 | 29 | #include "svg/svg.h" | ||
2834 | 30 | #include "svg/stringstream.h" | ||
2835 | 31 | #include "originalpath.h" | ||
2836 | 32 | #include "uri.h" | ||
2837 | 33 | #include "display/curve.h" | ||
2838 | 34 | |||
2839 | 35 | #include <2geom/coord.h> | ||
2840 | 36 | #include <2geom/point.h> | ||
2841 | 37 | #include "sp-shape.h" | ||
2842 | 38 | #include "sp-text.h" | ||
2843 | 39 | #include "live_effects/effect.h" | ||
2844 | 40 | |||
2845 | 41 | #include "verbs.h" | ||
2846 | 42 | #include "document-undo.h" | ||
2847 | 43 | #include "document.h" | ||
2848 | 44 | |||
2849 | 45 | namespace Inkscape { | ||
2850 | 46 | |||
2851 | 47 | namespace LivePathEffect { | ||
2852 | 48 | |||
2853 | 49 | class OriginalPathArrayParam::ModelColumns : public Gtk::TreeModel::ColumnRecord | ||
2854 | 50 | { | ||
2855 | 51 | public: | ||
2856 | 52 | |||
2857 | 53 | ModelColumns() | ||
2858 | 54 | { | ||
2859 | 55 | add(_colObject); | ||
2860 | 56 | add(_colLabel); | ||
2861 | 57 | add(_colReverse); | ||
2862 | 58 | } | ||
2863 | 59 | virtual ~ModelColumns() {} | ||
2864 | 60 | |||
2865 | 61 | Gtk::TreeModelColumn<PathAndDirection*> _colObject; | ||
2866 | 62 | Gtk::TreeModelColumn<Glib::ustring> _colLabel; | ||
2867 | 63 | Gtk::TreeModelColumn<bool> _colReverse; | ||
2868 | 64 | }; | ||
2869 | 65 | |||
2870 | 66 | OriginalPathArrayParam::OriginalPathArrayParam( const Glib::ustring& label, | ||
2871 | 67 | const Glib::ustring& tip, | ||
2872 | 68 | const Glib::ustring& key, | ||
2873 | 69 | Inkscape::UI::Widget::Registry* wr, | ||
2874 | 70 | Effect* effect ) | ||
2875 | 71 | : Parameter(label, tip, key, wr, effect), | ||
2876 | 72 | _vector(), | ||
2877 | 73 | _tree(), | ||
2878 | 74 | _text_renderer(), | ||
2879 | 75 | _toggle_renderer(), | ||
2880 | 76 | _scroller() | ||
2881 | 77 | { | ||
2882 | 78 | _model = new ModelColumns(); | ||
2883 | 79 | _store = Gtk::TreeStore::create(*_model); | ||
2884 | 80 | _tree.set_model(_store); | ||
2885 | 81 | |||
2886 | 82 | _tree.set_reorderable(true); | ||
2887 | 83 | _tree.enable_model_drag_dest (Gdk::ACTION_MOVE); | ||
2888 | 84 | |||
2889 | 85 | _text_renderer = manage(new Gtk::CellRendererText()); | ||
2890 | 86 | int nameColNum = _tree.append_column(_("Name"), *_text_renderer) - 1; | ||
2891 | 87 | _name_column = _tree.get_column(nameColNum); | ||
2892 | 88 | _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel); | ||
2893 | 89 | |||
2894 | 90 | _tree.set_expander_column( *_tree.get_column(nameColNum) ); | ||
2895 | 91 | _tree.set_search_column(_model->_colLabel); | ||
2896 | 92 | |||
2897 | 93 | Gtk::CellRendererToggle * _toggle_renderer = manage(new Gtk::CellRendererToggle()); | ||
2898 | 94 | int toggleColNum = _tree.append_column(_("Reverse"), *_toggle_renderer) - 1; | ||
2899 | 95 | Gtk::TreeViewColumn* col = _tree.get_column(toggleColNum); | ||
2900 | 96 | _toggle_renderer->set_activatable(true); | ||
2901 | 97 | _toggle_renderer->signal_toggled().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_reverse_toggled)); | ||
2902 | 98 | col->add_attribute(_toggle_renderer->property_active(), _model->_colReverse); | ||
2903 | 99 | |||
2904 | 100 | //quick little hack -- newer versions of gtk gave the item zero space allotment | ||
2905 | 101 | _scroller.set_size_request(-1, 120); | ||
2906 | 102 | |||
2907 | 103 | _scroller.add(_tree); | ||
2908 | 104 | _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); | ||
2909 | 105 | //_scroller.set_shadow_type(Gtk::SHADOW_IN); | ||
2910 | 106 | |||
2911 | 107 | oncanvas_editable = true; | ||
2912 | 108 | |||
2913 | 109 | } | ||
2914 | 110 | |||
2915 | 111 | OriginalPathArrayParam::~OriginalPathArrayParam() | ||
2916 | 112 | { | ||
2917 | 113 | while (!_vector.empty()) { | ||
2918 | 114 | PathAndDirection *w = _vector.back(); | ||
2919 | 115 | _vector.pop_back(); | ||
2920 | 116 | unlink(w); | ||
2921 | 117 | delete w; | ||
2922 | 118 | } | ||
2923 | 119 | delete _model; | ||
2924 | 120 | } | ||
2925 | 121 | |||
2926 | 122 | void OriginalPathArrayParam::on_reverse_toggled(const Glib::ustring& path) | ||
2927 | 123 | { | ||
2928 | 124 | Gtk::TreeModel::iterator iter = _store->get_iter(path); | ||
2929 | 125 | Gtk::TreeModel::Row row = *iter; | ||
2930 | 126 | PathAndDirection *w = row[_model->_colObject]; | ||
2931 | 127 | row[_model->_colReverse] = !row[_model->_colReverse]; | ||
2932 | 128 | w->reversed = row[_model->_colReverse]; | ||
2933 | 129 | |||
2934 | 130 | gchar * full = param_getSVGValue(); | ||
2935 | 131 | param_write_to_repr(full); | ||
2936 | 132 | g_free(full); | ||
2937 | 133 | DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, | ||
2938 | 134 | _("Link path parameter to path")); | ||
2939 | 135 | } | ||
2940 | 136 | |||
2941 | 137 | void OriginalPathArrayParam::param_set_default() | ||
2942 | 138 | { | ||
2943 | 139 | |||
2944 | 140 | } | ||
2945 | 141 | |||
2946 | 142 | Gtk::Widget* OriginalPathArrayParam::param_newWidget() | ||
2947 | 143 | { | ||
2948 | 144 | Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox()); | ||
2949 | 145 | Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox()); | ||
2950 | 146 | |||
2951 | 147 | vbox->pack_start(_scroller, Gtk::PACK_EXPAND_WIDGET); | ||
2952 | 148 | |||
2953 | 149 | |||
2954 | 150 | { // Paste path to link button | ||
2955 | 151 | Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_PASTE, Inkscape::ICON_SIZE_BUTTON) ); | ||
2956 | 152 | Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); | ||
2957 | 153 | pButton->set_relief(Gtk::RELIEF_NONE); | ||
2958 | 154 | pIcon->show(); | ||
2959 | 155 | pButton->add(*pIcon); | ||
2960 | 156 | pButton->show(); | ||
2961 | 157 | pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_link_button_click)); | ||
2962 | 158 | hbox->pack_start(*pButton, Gtk::PACK_SHRINK); | ||
2963 | 159 | pButton->set_tooltip_text(_("Link to path")); | ||
2964 | 160 | } | ||
2965 | 161 | |||
2966 | 162 | { // Remove linked path | ||
2967 | 163 | Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_REMOVE, Inkscape::ICON_SIZE_BUTTON) ); | ||
2968 | 164 | Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); | ||
2969 | 165 | pButton->set_relief(Gtk::RELIEF_NONE); | ||
2970 | 166 | pIcon->show(); | ||
2971 | 167 | pButton->add(*pIcon); | ||
2972 | 168 | pButton->show(); | ||
2973 | 169 | pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_remove_button_click)); | ||
2974 | 170 | hbox->pack_start(*pButton, Gtk::PACK_SHRINK); | ||
2975 | 171 | pButton->set_tooltip_text(_("Remove Path")); | ||
2976 | 172 | } | ||
2977 | 173 | |||
2978 | 174 | { // Move Down | ||
2979 | 175 | Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_GO_DOWN, Inkscape::ICON_SIZE_BUTTON) ); | ||
2980 | 176 | Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); | ||
2981 | 177 | pButton->set_relief(Gtk::RELIEF_NONE); | ||
2982 | 178 | pIcon->show(); | ||
2983 | 179 | pButton->add(*pIcon); | ||
2984 | 180 | pButton->show(); | ||
2985 | 181 | pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_down_button_click)); | ||
2986 | 182 | hbox->pack_end(*pButton, Gtk::PACK_SHRINK); | ||
2987 | 183 | pButton->set_tooltip_text(_("Move Down")); | ||
2988 | 184 | } | ||
2989 | 185 | |||
2990 | 186 | { // Move Down | ||
2991 | 187 | Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_GO_UP, Inkscape::ICON_SIZE_BUTTON) ); | ||
2992 | 188 | Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); | ||
2993 | 189 | pButton->set_relief(Gtk::RELIEF_NONE); | ||
2994 | 190 | pIcon->show(); | ||
2995 | 191 | pButton->add(*pIcon); | ||
2996 | 192 | pButton->show(); | ||
2997 | 193 | pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_up_button_click)); | ||
2998 | 194 | hbox->pack_end(*pButton, Gtk::PACK_SHRINK); | ||
2999 | 195 | pButton->set_tooltip_text(_("Move Up")); | ||
3000 | 196 | } | ||
3001 | 197 | |||
3002 | 198 | vbox->pack_end(*hbox, Gtk::PACK_SHRINK); | ||
3003 | 199 | |||
3004 | 200 | vbox->show_all_children(true); | ||
3005 | 201 | |||
3006 | 202 | return vbox; | ||
3007 | 203 | } | ||
3008 | 204 | |||
3009 | 205 | bool OriginalPathArrayParam::_selectIndex(const Gtk::TreeIter& iter, int* i) | ||
3010 | 206 | { | ||
3011 | 207 | if ((*i)-- <= 0) { | ||
3012 | 208 | _tree.get_selection()->select(iter); | ||
3013 | 209 | return true; | ||
3014 | 210 | } | ||
3015 | 211 | return false; | ||
3016 | 212 | } | ||
3017 | 213 | |||
3018 | 214 | void OriginalPathArrayParam::on_up_button_click() | ||
3019 | 215 | { | ||
3020 | 216 | Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); | ||
3021 | 217 | if (iter) { | ||
3022 | 218 | Gtk::TreeModel::Row row = *iter; | ||
3023 | 219 | |||
3024 | 220 | int i = -1; | ||
3025 | 221 | std::vector<PathAndDirection*>::iterator piter = _vector.begin(); | ||
3026 | 222 | for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); piter = iter, i++, iter++) { | ||
3027 | 223 | if (*iter == row[_model->_colObject]) { | ||
3028 | 224 | _vector.erase(iter); | ||
3029 | 225 | _vector.insert(piter, row[_model->_colObject]); | ||
3030 | 226 | break; | ||
3031 | 227 | } | ||
3032 | 228 | } | ||
3033 | 229 | |||
3034 | 230 | gchar * full = param_getSVGValue(); | ||
3035 | 231 | param_write_to_repr(full); | ||
3036 | 232 | g_free(full); | ||
3037 | 233 | |||
3038 | 234 | DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, | ||
3039 | 235 | _("Move path up")); | ||
3040 | 236 | |||
3041 | 237 | _store->foreach_iter(sigc::bind<int*>(sigc::mem_fun(*this, &OriginalPathArrayParam::_selectIndex), &i)); | ||
3042 | 238 | } | ||
3043 | 239 | } | ||
3044 | 240 | |||
3045 | 241 | void OriginalPathArrayParam::on_down_button_click() | ||
3046 | 242 | { | ||
3047 | 243 | Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); | ||
3048 | 244 | if (iter) { | ||
3049 | 245 | Gtk::TreeModel::Row row = *iter; | ||
3050 | 246 | |||
3051 | 247 | int i = 0; | ||
3052 | 248 | for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); i++, iter++) { | ||
3053 | 249 | if (*iter == row[_model->_colObject]) { | ||
3054 | 250 | std::vector<PathAndDirection*>::iterator niter = _vector.erase(iter); | ||
3055 | 251 | if (niter != _vector.end()) { | ||
3056 | 252 | niter++; | ||
3057 | 253 | i++; | ||
3058 | 254 | } | ||
3059 | 255 | _vector.insert(niter, row[_model->_colObject]); | ||
3060 | 256 | break; | ||
3061 | 257 | } | ||
3062 | 258 | } | ||
3063 | 259 | |||
3064 | 260 | gchar * full = param_getSVGValue(); | ||
3065 | 261 | param_write_to_repr(full); | ||
3066 | 262 | g_free(full); | ||
3067 | 263 | |||
3068 | 264 | DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, | ||
3069 | 265 | _("Move path down")); | ||
3070 | 266 | |||
3071 | 267 | _store->foreach_iter(sigc::bind<int*>(sigc::mem_fun(*this, &OriginalPathArrayParam::_selectIndex), &i)); | ||
3072 | 268 | } | ||
3073 | 269 | } | ||
3074 | 270 | |||
3075 | 271 | void OriginalPathArrayParam::on_remove_button_click() | ||
3076 | 272 | { | ||
3077 | 273 | Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); | ||
3078 | 274 | if (iter) { | ||
3079 | 275 | Gtk::TreeModel::Row row = *iter; | ||
3080 | 276 | remove_link(row[_model->_colObject]); | ||
3081 | 277 | |||
3082 | 278 | gchar * full = param_getSVGValue(); | ||
3083 | 279 | param_write_to_repr(full); | ||
3084 | 280 | g_free(full); | ||
3085 | 281 | |||
3086 | 282 | DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, | ||
3087 | 283 | _("Remove path")); | ||
3088 | 284 | } | ||
3089 | 285 | |||
3090 | 286 | } | ||
3091 | 287 | |||
3092 | 288 | void | ||
3093 | 289 | OriginalPathArrayParam::on_link_button_click() | ||
3094 | 290 | { | ||
3095 | 291 | Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get(); | ||
3096 | 292 | Glib::ustring pathid = cm->getShapeOrTextObjectId(SP_ACTIVE_DESKTOP); | ||
3097 | 293 | |||
3098 | 294 | if (pathid == "") { | ||
3099 | 295 | return; | ||
3100 | 296 | } | ||
3101 | 297 | // add '#' at start to make it an uri. | ||
3102 | 298 | pathid.insert(pathid.begin(), '#'); | ||
3103 | 299 | |||
3104 | 300 | Inkscape::SVGOStringStream os; | ||
3105 | 301 | bool foundOne = false; | ||
3106 | 302 | for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) { | ||
3107 | 303 | if (foundOne) { | ||
3108 | 304 | os << "|"; | ||
3109 | 305 | } else { | ||
3110 | 306 | foundOne = true; | ||
3111 | 307 | } | ||
3112 | 308 | os << (*iter)->href << "," << ((*iter)->reversed ? "1" : "0"); | ||
3113 | 309 | } | ||
3114 | 310 | |||
3115 | 311 | if (foundOne) { | ||
3116 | 312 | os << "|"; | ||
3117 | 313 | } | ||
3118 | 314 | |||
3119 | 315 | os << pathid.c_str() << ",0"; | ||
3120 | 316 | |||
3121 | 317 | param_write_to_repr(os.str().c_str()); | ||
3122 | 318 | DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, | ||
3123 | 319 | _("Link path parameter to path")); | ||
3124 | 320 | } | ||
3125 | 321 | |||
3126 | 322 | void OriginalPathArrayParam::unlink(PathAndDirection* to) | ||
3127 | 323 | { | ||
3128 | 324 | to->linked_modified_connection.disconnect(); | ||
3129 | 325 | to->linked_delete_connection.disconnect(); | ||
3130 | 326 | to->ref.detach(); | ||
3131 | 327 | to->_pathvector = Geom::PathVector(); | ||
3132 | 328 | if (to->href) { | ||
3133 | 329 | g_free(to->href); | ||
3134 | 330 | to->href = NULL; | ||
3135 | 331 | } | ||
3136 | 332 | } | ||
3137 | 333 | |||
3138 | 334 | void OriginalPathArrayParam::remove_link(PathAndDirection* to) | ||
3139 | 335 | { | ||
3140 | 336 | unlink(to); | ||
3141 | 337 | for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); iter++) { | ||
3142 | 338 | if (*iter == to) { | ||
3143 | 339 | PathAndDirection *w = *iter; | ||
3144 | 340 | _vector.erase(iter); | ||
3145 | 341 | delete w; | ||
3146 | 342 | return; | ||
3147 | 343 | } | ||
3148 | 344 | } | ||
3149 | 345 | } | ||
3150 | 346 | |||
3151 | 347 | void OriginalPathArrayParam::linked_delete(SPObject */*deleted*/, PathAndDirection* to) | ||
3152 | 348 | { | ||
3153 | 349 | //remove_link(to); | ||
3154 | 350 | |||
3155 | 351 | gchar * full = param_getSVGValue(); | ||
3156 | 352 | param_write_to_repr(full); | ||
3157 | 353 | g_free(full); | ||
3158 | 354 | } | ||
3159 | 355 | |||
3160 | 356 | bool OriginalPathArrayParam::_updateLink(const Gtk::TreeIter& iter, PathAndDirection* pd) | ||
3161 | 357 | { | ||
3162 | 358 | Gtk::TreeModel::Row row = *iter; | ||
3163 | 359 | if (row[_model->_colObject] == pd) { | ||
3164 | 360 | SPObject *obj = pd->ref.getObject(); | ||
3165 | 361 | row[_model->_colLabel] = obj && obj->getId() ? ( obj->label() ? obj->label() : obj->getId() ) : pd->href; | ||
3166 | 362 | return true; | ||
3167 | 363 | } | ||
3168 | 364 | return false; | ||
3169 | 365 | } | ||
3170 | 366 | |||
3171 | 367 | void OriginalPathArrayParam::linked_changed(SPObject */*old_obj*/, SPObject *new_obj, PathAndDirection* to) | ||
3172 | 368 | { | ||
3173 | 369 | to->linked_delete_connection.disconnect(); | ||
3174 | 370 | to->linked_modified_connection.disconnect(); | ||
3175 | 371 | to->linked_transformed_connection.disconnect(); | ||
3176 | 372 | |||
3177 | 373 | if (new_obj && SP_IS_ITEM(new_obj)) { | ||
3178 | 374 | to->linked_delete_connection = new_obj->connectDelete(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_delete), to)); | ||
3179 | 375 | to->linked_modified_connection = new_obj->connectModified(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_modified), to)); | ||
3180 | 376 | to->linked_transformed_connection = SP_ITEM(new_obj)->connectTransformed(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_transformed), to)); | ||
3181 | 377 | |||
3182 | 378 | linked_modified(new_obj, SP_OBJECT_MODIFIED_FLAG, to); | ||
3183 | 379 | } else { | ||
3184 | 380 | to->_pathvector = Geom::PathVector(); | ||
3185 | 381 | SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); | ||
3186 | 382 | _store->foreach_iter(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to)); | ||
3187 | 383 | } | ||
3188 | 384 | } | ||
3189 | 385 | |||
3190 | 386 | void OriginalPathArrayParam::linked_transformed(Geom::Affine const *mp, SPItem* original, PathAndDirection* to) | ||
3191 | 387 | { | ||
3192 | 388 | |||
3193 | 389 | } | ||
3194 | 390 | |||
3195 | 391 | void OriginalPathArrayParam::setPathVector(SPObject *linked_obj, guint flags, PathAndDirection* to) | ||
3196 | 392 | { | ||
3197 | 393 | if (!to) { | ||
3198 | 394 | return; | ||
3199 | 395 | } | ||
3200 | 396 | SPCurve *curve = NULL; | ||
3201 | 397 | if (SP_IS_SHAPE(linked_obj)) { | ||
3202 | 398 | curve = SP_SHAPE(linked_obj)->getCurveBeforeLPE(); | ||
3203 | 399 | } | ||
3204 | 400 | if (SP_IS_TEXT(linked_obj)) { | ||
3205 | 401 | curve = SP_TEXT(linked_obj)->getNormalizedBpath(); | ||
3206 | 402 | } | ||
3207 | 403 | |||
3208 | 404 | if (curve == NULL) { | ||
3209 | 405 | // curve invalid, set empty pathvector | ||
3210 | 406 | to->_pathvector = Geom::PathVector(); | ||
3211 | 407 | } else { | ||
3212 | 408 | to->_pathvector = curve->get_pathvector(); | ||
3213 | 409 | curve->unref(); | ||
3214 | 410 | } | ||
3215 | 411 | } | ||
3216 | 412 | |||
3217 | 413 | void OriginalPathArrayParam::linked_modified(SPObject *linked_obj, guint flags, PathAndDirection* to) | ||
3218 | 414 | { | ||
3219 | 415 | if (!to) { | ||
3220 | 416 | return; | ||
3221 | 417 | } | ||
3222 | 418 | setPathVector(linked_obj, flags, to); | ||
3223 | 419 | SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); | ||
3224 | 420 | _store->foreach_iter(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to)); | ||
3225 | 421 | } | ||
3226 | 422 | |||
3227 | 423 | //void PathParam::linked_transformed(Geom::Affine const *rel_transf, SPItem *moved_item) | ||
3228 | 424 | //{ | ||
3229 | 425 | // linked_transformed_callback(rel_transf, moved_item); | ||
3230 | 426 | //} | ||
3231 | 427 | |||
3232 | 428 | bool OriginalPathArrayParam::param_readSVGValue(const gchar* strvalue) | ||
3233 | 429 | { | ||
3234 | 430 | if (strvalue) { | ||
3235 | 431 | while (!_vector.empty()) { | ||
3236 | 432 | PathAndDirection *w = _vector.back(); | ||
3237 | 433 | unlink(w); | ||
3238 | 434 | _vector.pop_back(); | ||
3239 | 435 | delete w; | ||
3240 | 436 | } | ||
3241 | 437 | _store->clear(); | ||
3242 | 438 | |||
3243 | 439 | gchar ** strarray = g_strsplit(strvalue, "|", 0); | ||
3244 | 440 | for (gchar ** iter = strarray; *iter != NULL; iter++) { | ||
3245 | 441 | if ((*iter)[0] == '#') { | ||
3246 | 442 | gchar ** substrarray = g_strsplit(*iter, ",", 0); | ||
3247 | 443 | PathAndDirection* w = new PathAndDirection((SPObject *)param_effect->getLPEObj()); | ||
3248 | 444 | w->href = g_strdup(*substrarray); | ||
3249 | 445 | w->reversed = *(substrarray+1) != NULL && (*(substrarray+1))[0] == '1'; | ||
3250 | 446 | |||
3251 | 447 | w->linked_changed_connection = w->ref.changedSignal().connect(sigc::bind<PathAndDirection *>(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_changed), w)); | ||
3252 | 448 | w->ref.attach(URI(w->href)); | ||
3253 | 449 | |||
3254 | 450 | _vector.push_back(w); | ||
3255 | 451 | |||
3256 | 452 | Gtk::TreeModel::iterator iter = _store->append(); | ||
3257 | 453 | Gtk::TreeModel::Row row = *iter; | ||
3258 | 454 | SPObject *obj = w->ref.getObject(); | ||
3259 | 455 | |||
3260 | 456 | row[_model->_colObject] = w; | ||
3261 | 457 | row[_model->_colLabel] = obj ? ( obj->label() ? obj->label() : obj->getId() ) : w->href; | ||
3262 | 458 | row[_model->_colReverse] = w->reversed; | ||
3263 | 459 | g_strfreev (substrarray); | ||
3264 | 460 | } | ||
3265 | 461 | } | ||
3266 | 462 | g_strfreev (strarray); | ||
3267 | 463 | return true; | ||
3268 | 464 | } | ||
3269 | 465 | return false; | ||
3270 | 466 | } | ||
3271 | 467 | |||
3272 | 468 | gchar * OriginalPathArrayParam::param_getSVGValue() const | ||
3273 | 469 | { | ||
3274 | 470 | Inkscape::SVGOStringStream os; | ||
3275 | 471 | bool foundOne = false; | ||
3276 | 472 | for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) { | ||
3277 | 473 | if (foundOne) { | ||
3278 | 474 | os << "|"; | ||
3279 | 475 | } else { | ||
3280 | 476 | foundOne = true; | ||
3281 | 477 | } | ||
3282 | 478 | os << (*iter)->href << "," << ((*iter)->reversed ? "1" : "0"); | ||
3283 | 479 | } | ||
3284 | 480 | gchar * str = g_strdup(os.str().c_str()); | ||
3285 | 481 | return str; | ||
3286 | 482 | } | ||
3287 | 483 | |||
3288 | 484 | } /* namespace LivePathEffect */ | ||
3289 | 485 | |||
3290 | 486 | } /* namespace Inkscape */ | ||
3291 | 487 | |||
3292 | 488 | /* | ||
3293 | 489 | Local Variables: | ||
3294 | 490 | mode:c++ | ||
3295 | 491 | c-file-style:"stroustrup" | ||
3296 | 492 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
3297 | 493 | indent-tabs-mode:nil | ||
3298 | 494 | fill-column:99 | ||
3299 | 495 | End: | ||
3300 | 496 | */ | ||
3301 | 497 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : | ||
3302 | 0 | 498 | ||
3303 | === added file 'src/live_effects/parameter/originalpatharray.h' | |||
3304 | --- src/live_effects/parameter/originalpatharray.h 1970-01-01 00:00:00 +0000 | |||
3305 | +++ src/live_effects/parameter/originalpatharray.h 2014-09-07 17:02:32 +0000 | |||
3306 | @@ -0,0 +1,123 @@ | |||
3307 | 1 | #ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALPATHARRAY_H | ||
3308 | 2 | #define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALPATHARRAY_H | ||
3309 | 3 | |||
3310 | 4 | /* | ||
3311 | 5 | * Inkscape::LivePathEffectParameters | ||
3312 | 6 | * | ||
3313 | 7 | * Copyright (C) Johan Engelen 2008 <j.b.c.engelen@utwente.nl> | ||
3314 | 8 | * | ||
3315 | 9 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
3316 | 10 | */ | ||
3317 | 11 | |||
3318 | 12 | #include <vector> | ||
3319 | 13 | |||
3320 | 14 | #include <gtkmm/box.h> | ||
3321 | 15 | #include <gtkmm/treeview.h> | ||
3322 | 16 | #include <gtkmm/treestore.h> | ||
3323 | 17 | #include <gtkmm/scrolledwindow.h> | ||
3324 | 18 | |||
3325 | 19 | #include "live_effects/parameter/parameter.h" | ||
3326 | 20 | #include "live_effects/parameter/path-reference.h" | ||
3327 | 21 | |||
3328 | 22 | #include "svg/svg.h" | ||
3329 | 23 | #include "svg/stringstream.h" | ||
3330 | 24 | #include "path-reference.h" | ||
3331 | 25 | #include "sp-object.h" | ||
3332 | 26 | |||
3333 | 27 | namespace Inkscape { | ||
3334 | 28 | |||
3335 | 29 | namespace LivePathEffect { | ||
3336 | 30 | |||
3337 | 31 | class PathAndDirection { | ||
3338 | 32 | public: | ||
3339 | 33 | PathAndDirection(SPObject *owner) | ||
3340 | 34 | : href(NULL), | ||
3341 | 35 | ref(owner), | ||
3342 | 36 | _pathvector(Geom::PathVector()), | ||
3343 | 37 | reversed(false) | ||
3344 | 38 | { | ||
3345 | 39 | |||
3346 | 40 | } | ||
3347 | 41 | gchar *href; | ||
3348 | 42 | URIReference ref; | ||
3349 | 43 | //SPItem *obj; | ||
3350 | 44 | std::vector<Geom::Path> _pathvector; | ||
3351 | 45 | bool reversed; | ||
3352 | 46 | |||
3353 | 47 | sigc::connection linked_changed_connection; | ||
3354 | 48 | sigc::connection linked_delete_connection; | ||
3355 | 49 | sigc::connection linked_modified_connection; | ||
3356 | 50 | sigc::connection linked_transformed_connection; | ||
3357 | 51 | }; | ||
3358 | 52 | |||
3359 | 53 | class OriginalPathArrayParam : public Parameter { | ||
3360 | 54 | public: | ||
3361 | 55 | class ModelColumns; | ||
3362 | 56 | |||
3363 | 57 | OriginalPathArrayParam( const Glib::ustring& label, | ||
3364 | 58 | const Glib::ustring& tip, | ||
3365 | 59 | const Glib::ustring& key, | ||
3366 | 60 | Inkscape::UI::Widget::Registry* wr, | ||
3367 | 61 | Effect* effect); | ||
3368 | 62 | |||
3369 | 63 | virtual ~OriginalPathArrayParam(); | ||
3370 | 64 | |||
3371 | 65 | virtual Gtk::Widget * param_newWidget(); | ||
3372 | 66 | virtual bool param_readSVGValue(const gchar * strvalue); | ||
3373 | 67 | virtual gchar * param_getSVGValue() const; | ||
3374 | 68 | virtual void param_set_default(); | ||
3375 | 69 | |||
3376 | 70 | /** Disable the canvas indicators of parent class by overriding this method */ | ||
3377 | 71 | virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {}; | ||
3378 | 72 | /** Disable the canvas indicators of parent class by overriding this method */ | ||
3379 | 73 | virtual void addCanvasIndicators(SPLPEItem const* /*lpeitem*/, std::vector<Geom::PathVector> & /*hp_vec*/) {}; | ||
3380 | 74 | |||
3381 | 75 | std::vector<PathAndDirection*> _vector; | ||
3382 | 76 | |||
3383 | 77 | protected: | ||
3384 | 78 | bool _updateLink(const Gtk::TreeIter& iter, PathAndDirection* pd); | ||
3385 | 79 | bool _selectIndex(const Gtk::TreeIter& iter, int* i); | ||
3386 | 80 | void unlink(PathAndDirection* to); | ||
3387 | 81 | void remove_link(PathAndDirection* to); | ||
3388 | 82 | void setPathVector(SPObject *linked_obj, guint flags, PathAndDirection* to); | ||
3389 | 83 | |||
3390 | 84 | void linked_changed(SPObject *old_obj, SPObject *new_obj, PathAndDirection* to); | ||
3391 | 85 | void linked_modified(SPObject *linked_obj, guint flags, PathAndDirection* to); | ||
3392 | 86 | void linked_transformed(Geom::Affine const *mp, SPItem *original, PathAndDirection* to); | ||
3393 | 87 | void linked_delete(SPObject *deleted, PathAndDirection* to); | ||
3394 | 88 | |||
3395 | 89 | ModelColumns *_model; | ||
3396 | 90 | Glib::RefPtr<Gtk::TreeStore> _store; | ||
3397 | 91 | Gtk::TreeView _tree; | ||
3398 | 92 | Gtk::CellRendererText *_text_renderer; | ||
3399 | 93 | Gtk::CellRendererToggle *_toggle_renderer; | ||
3400 | 94 | Gtk::TreeView::Column *_name_column; | ||
3401 | 95 | Gtk::ScrolledWindow _scroller; | ||
3402 | 96 | |||
3403 | 97 | void on_link_button_click(); | ||
3404 | 98 | void on_remove_button_click(); | ||
3405 | 99 | void on_up_button_click(); | ||
3406 | 100 | void on_down_button_click(); | ||
3407 | 101 | void on_reverse_toggled(const Glib::ustring& path); | ||
3408 | 102 | |||
3409 | 103 | private: | ||
3410 | 104 | OriginalPathArrayParam(const OriginalPathArrayParam&); | ||
3411 | 105 | OriginalPathArrayParam& operator=(const OriginalPathArrayParam&); | ||
3412 | 106 | }; | ||
3413 | 107 | |||
3414 | 108 | } //namespace LivePathEffect | ||
3415 | 109 | |||
3416 | 110 | } //namespace Inkscape | ||
3417 | 111 | |||
3418 | 112 | #endif | ||
3419 | 113 | |||
3420 | 114 | /* | ||
3421 | 115 | Local Variables: | ||
3422 | 116 | mode:c++ | ||
3423 | 117 | c-file-style:"stroustrup" | ||
3424 | 118 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
3425 | 119 | indent-tabs-mode:nil | ||
3426 | 120 | fill-column:99 | ||
3427 | 121 | End: | ||
3428 | 122 | */ | ||
3429 | 123 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : | ||
3430 | 0 | 124 | ||
3431 | === modified file 'src/live_effects/parameter/powerstrokepointarray.cpp' | |||
3432 | --- src/live_effects/parameter/powerstrokepointarray.cpp 2014-07-27 01:17:50 +0000 | |||
3433 | +++ src/live_effects/parameter/powerstrokepointarray.cpp 2014-09-07 17:02:32 +0000 | |||
3434 | @@ -4,8 +4,7 @@ | |||
3435 | 4 | * Released under GNU GPL, read the file 'COPYING' for more information | 4 | * Released under GNU GPL, read the file 'COPYING' for more information |
3436 | 5 | */ | 5 | */ |
3437 | 6 | 6 | ||
3440 | 7 | #include <glibmm/i18n.h> | 7 | #include "ui/dialog/lpe-powerstroke-properties.h" |
3439 | 8 | |||
3441 | 9 | #include "live_effects/parameter/powerstrokepointarray.h" | 8 | #include "live_effects/parameter/powerstrokepointarray.h" |
3442 | 10 | 9 | ||
3443 | 11 | #include "live_effects/effect.h" | 10 | #include "live_effects/effect.h" |
3444 | @@ -21,6 +20,8 @@ | |||
3445 | 21 | #include "desktop.h" | 20 | #include "desktop.h" |
3446 | 22 | #include "live_effects/lpeobject.h" | 21 | #include "live_effects/lpeobject.h" |
3447 | 23 | 22 | ||
3448 | 23 | #include <glibmm/i18n.h> | ||
3449 | 24 | |||
3450 | 24 | namespace Inkscape { | 25 | namespace Inkscape { |
3451 | 25 | 26 | ||
3452 | 26 | namespace LivePathEffect { | 27 | namespace LivePathEffect { |
3453 | @@ -102,6 +103,23 @@ | |||
3454 | 102 | } | 103 | } |
3455 | 103 | } | 104 | } |
3456 | 104 | 105 | ||
3457 | 106 | float PowerStrokePointArrayParam::median_width() | ||
3458 | 107 | { | ||
3459 | 108 | size_t size = _vector.size(); | ||
3460 | 109 | if (size > 0) | ||
3461 | 110 | { | ||
3462 | 111 | if (size % 2 == 0) | ||
3463 | 112 | { | ||
3464 | 113 | return (_vector[size / 2 - 1].y() + _vector[size / 2].y()) / 2; | ||
3465 | 114 | } | ||
3466 | 115 | else | ||
3467 | 116 | { | ||
3468 | 117 | return _vector[size / 2].y(); | ||
3469 | 118 | } | ||
3470 | 119 | } | ||
3471 | 120 | return 1; | ||
3472 | 121 | } | ||
3473 | 122 | |||
3474 | 105 | void | 123 | void |
3475 | 106 | PowerStrokePointArrayParam::set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in, Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_normal_in) | 124 | PowerStrokePointArrayParam::set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in, Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_normal_in) |
3476 | 107 | { | 125 | { |
3477 | @@ -117,7 +135,7 @@ | |||
3478 | 117 | knot_mode = mode; | 135 | knot_mode = mode; |
3479 | 118 | knot_color = color; | 136 | knot_color = color; |
3480 | 119 | } | 137 | } |
3482 | 120 | 138 | /* | |
3483 | 121 | class PowerStrokePointArrayParamKnotHolderEntity : public KnotHolderEntity { | 139 | class PowerStrokePointArrayParamKnotHolderEntity : public KnotHolderEntity { |
3484 | 122 | public: | 140 | public: |
3485 | 123 | PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index); | 141 | PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index); |
3486 | @@ -127,7 +145,7 @@ | |||
3487 | 127 | virtual Geom::Point knot_get() const; | 145 | virtual Geom::Point knot_get() const; |
3488 | 128 | virtual void knot_click(guint state); | 146 | virtual void knot_click(guint state); |
3489 | 129 | 147 | ||
3491 | 130 | /** Checks whether the index falls within the size of the parameter's vector */ | 148 | // Checks whether the index falls within the size of the parameter's vector |
3492 | 131 | bool valid_index(unsigned int index) const { | 149 | bool valid_index(unsigned int index) const { |
3493 | 132 | return (_pparam->_vector.size() > index); | 150 | return (_pparam->_vector.size() > index); |
3494 | 133 | }; | 151 | }; |
3495 | @@ -135,7 +153,7 @@ | |||
3496 | 135 | private: | 153 | private: |
3497 | 136 | PowerStrokePointArrayParam *_pparam; | 154 | PowerStrokePointArrayParam *_pparam; |
3498 | 137 | unsigned int _index; | 155 | unsigned int _index; |
3500 | 138 | }; | 156 | };*/ |
3501 | 139 | 157 | ||
3502 | 140 | PowerStrokePointArrayParamKnotHolderEntity::PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index) | 158 | PowerStrokePointArrayParamKnotHolderEntity::PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index) |
3503 | 141 | : _pparam(p), | 159 | : _pparam(p), |
3504 | @@ -184,6 +202,12 @@ | |||
3505 | 184 | return canvas_point; | 202 | return canvas_point; |
3506 | 185 | } | 203 | } |
3507 | 186 | 204 | ||
3508 | 205 | void PowerStrokePointArrayParamKnotHolderEntity::knot_set_offset(Geom::Point offset) | ||
3509 | 206 | { | ||
3510 | 207 | _pparam->_vector.at(_index) = Geom::Point(offset.x(), offset.y() / 2); | ||
3511 | 208 | this->parent_holder->knot_ungrabbed_handler(this->knot, 0); | ||
3512 | 209 | } | ||
3513 | 210 | |||
3514 | 187 | void | 211 | void |
3515 | 188 | PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state) | 212 | PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state) |
3516 | 189 | { | 213 | { |
3517 | @@ -226,10 +250,15 @@ | |||
3518 | 226 | // add knot to knotholder | 250 | // add knot to knotholder |
3519 | 227 | PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(_pparam, _index+1); | 251 | PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(_pparam, _index+1); |
3520 | 228 | e->create( this->desktop, this->item, parent_holder, Inkscape::CTRL_TYPE_UNKNOWN, | 252 | e->create( this->desktop, this->item, parent_holder, Inkscape::CTRL_TYPE_UNKNOWN, |
3522 | 229 | _("<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."), | 253 | _("<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."), |
3523 | 230 | _pparam->knot_shape, _pparam->knot_mode, _pparam->knot_color); | 254 | _pparam->knot_shape, _pparam->knot_mode, _pparam->knot_color); |
3524 | 231 | parent_holder->add(e); | 255 | parent_holder->add(e); |
3525 | 232 | } | 256 | } |
3526 | 257 | } | ||
3527 | 258 | else if ((state & GDK_MOD1_MASK) || (state & GDK_SHIFT_MASK)) | ||
3528 | 259 | { | ||
3529 | 260 | Geom::Point offset = Geom::Point(_pparam->_vector.at(_index).x(), _pparam->_vector.at(_index).y() * 2); | ||
3530 | 261 | Inkscape::UI::Dialogs::PowerstrokePropertiesDialog::showDialog(this->desktop, offset, this); | ||
3531 | 233 | } | 262 | } |
3532 | 234 | } | 263 | } |
3533 | 235 | 264 | ||
3534 | @@ -238,7 +267,7 @@ | |||
3535 | 238 | for (unsigned int i = 0; i < _vector.size(); ++i) { | 267 | for (unsigned int i = 0; i < _vector.size(); ++i) { |
3536 | 239 | PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(this, i); | 268 | PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(this, i); |
3537 | 240 | e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, | 269 | e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, |
3539 | 241 | _("<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."), | 270 | _("<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."), |
3540 | 242 | knot_shape, knot_mode, knot_color); | 271 | knot_shape, knot_mode, knot_color); |
3541 | 243 | knotholder->add(e); | 272 | knotholder->add(e); |
3542 | 244 | } | 273 | } |
3543 | 245 | 274 | ||
3544 | === modified file 'src/live_effects/parameter/powerstrokepointarray.h' | |||
3545 | --- src/live_effects/parameter/powerstrokepointarray.h 2014-03-27 01:33:44 +0000 | |||
3546 | +++ src/live_effects/parameter/powerstrokepointarray.h 2014-09-07 17:02:32 +0000 | |||
3547 | @@ -20,8 +20,6 @@ | |||
3548 | 20 | 20 | ||
3549 | 21 | namespace LivePathEffect { | 21 | namespace LivePathEffect { |
3550 | 22 | 22 | ||
3551 | 23 | class PowerStrokePointArrayParamKnotHolderEntity; | ||
3552 | 24 | |||
3553 | 25 | class PowerStrokePointArrayParam : public ArrayParam<Geom::Point> { | 23 | class PowerStrokePointArrayParam : public ArrayParam<Geom::Point> { |
3554 | 26 | public: | 24 | public: |
3555 | 27 | PowerStrokePointArrayParam( const Glib::ustring& label, | 25 | PowerStrokePointArrayParam( const Glib::ustring& label, |
3556 | @@ -37,6 +35,8 @@ | |||
3557 | 37 | 35 | ||
3558 | 38 | void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); | 36 | void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); |
3559 | 39 | 37 | ||
3560 | 38 | float median_width(); | ||
3561 | 39 | |||
3562 | 40 | virtual bool providesKnotHolderEntities() const { return true; } | 40 | virtual bool providesKnotHolderEntities() const { return true; } |
3563 | 41 | virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); | 41 | virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); |
3564 | 42 | 42 | ||
3565 | @@ -60,6 +60,25 @@ | |||
3566 | 60 | Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal; | 60 | Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal; |
3567 | 61 | }; | 61 | }; |
3568 | 62 | 62 | ||
3569 | 63 | class PowerStrokePointArrayParamKnotHolderEntity : public KnotHolderEntity { | ||
3570 | 64 | public: | ||
3571 | 65 | PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index); | ||
3572 | 66 | virtual ~PowerStrokePointArrayParamKnotHolderEntity() {} | ||
3573 | 67 | |||
3574 | 68 | virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); | ||
3575 | 69 | virtual Geom::Point knot_get() const; | ||
3576 | 70 | virtual void knot_set_offset(Geom::Point offset); | ||
3577 | 71 | virtual void knot_click(guint state); | ||
3578 | 72 | |||
3579 | 73 | /** Checks whether the index falls within the size of the parameter's vector */ | ||
3580 | 74 | bool valid_index(unsigned int index) const { | ||
3581 | 75 | return (_pparam->_vector.size() > index); | ||
3582 | 76 | }; | ||
3583 | 77 | |||
3584 | 78 | private: | ||
3585 | 79 | PowerStrokePointArrayParam *_pparam; | ||
3586 | 80 | unsigned int _index; | ||
3587 | 81 | }; | ||
3588 | 63 | 82 | ||
3589 | 64 | } //namespace LivePathEffect | 83 | } //namespace LivePathEffect |
3590 | 65 | 84 | ||
3591 | 66 | 85 | ||
3592 | === added file 'src/live_effects/parameter/transformedpoint.cpp' | |||
3593 | --- src/live_effects/parameter/transformedpoint.cpp 1970-01-01 00:00:00 +0000 | |||
3594 | +++ src/live_effects/parameter/transformedpoint.cpp 2014-09-07 17:02:32 +0000 | |||
3595 | @@ -0,0 +1,182 @@ | |||
3596 | 1 | /* | ||
3597 | 2 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
3598 | 3 | * | ||
3599 | 4 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
3600 | 5 | */ | ||
3601 | 6 | |||
3602 | 7 | #include "ui/widget/registered-widget.h" | ||
3603 | 8 | #include "live_effects/parameter/transformedpoint.h" | ||
3604 | 9 | #include "sp-lpe-item.h" | ||
3605 | 10 | #include "knotholder.h" | ||
3606 | 11 | #include "svg/svg.h" | ||
3607 | 12 | #include "svg/stringstream.h" | ||
3608 | 13 | |||
3609 | 14 | #include "live_effects/effect.h" | ||
3610 | 15 | #include "desktop.h" | ||
3611 | 16 | #include "verbs.h" | ||
3612 | 17 | |||
3613 | 18 | #include <glibmm/i18n.h> | ||
3614 | 19 | |||
3615 | 20 | namespace Inkscape { | ||
3616 | 21 | |||
3617 | 22 | namespace LivePathEffect { | ||
3618 | 23 | |||
3619 | 24 | TransformedPointParam::TransformedPointParam( const Glib::ustring& label, const Glib::ustring& tip, | ||
3620 | 25 | const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, | ||
3621 | 26 | Effect* effect, Geom::Point default_vector, | ||
3622 | 27 | bool dontTransform) | ||
3623 | 28 | : Parameter(label, tip, key, wr, effect), | ||
3624 | 29 | defvalue(default_vector), | ||
3625 | 30 | origin(0.,0.), | ||
3626 | 31 | vector(default_vector), | ||
3627 | 32 | noTransform(dontTransform) | ||
3628 | 33 | { | ||
3629 | 34 | vec_knot_shape = SP_KNOT_SHAPE_DIAMOND; | ||
3630 | 35 | vec_knot_mode = SP_KNOT_MODE_XOR; | ||
3631 | 36 | vec_knot_color = 0xffffb500; | ||
3632 | 37 | } | ||
3633 | 38 | |||
3634 | 39 | TransformedPointParam::~TransformedPointParam() | ||
3635 | 40 | { | ||
3636 | 41 | |||
3637 | 42 | } | ||
3638 | 43 | |||
3639 | 44 | void | ||
3640 | 45 | TransformedPointParam::param_set_default() | ||
3641 | 46 | { | ||
3642 | 47 | setOrigin(Geom::Point(0.,0.)); | ||
3643 | 48 | setVector(defvalue); | ||
3644 | 49 | } | ||
3645 | 50 | |||
3646 | 51 | bool | ||
3647 | 52 | TransformedPointParam::param_readSVGValue(const gchar * strvalue) | ||
3648 | 53 | { | ||
3649 | 54 | gchar ** strarray = g_strsplit(strvalue, ",", 4); | ||
3650 | 55 | if (!strarray) { | ||
3651 | 56 | return false; | ||
3652 | 57 | } | ||
3653 | 58 | double val[4]; | ||
3654 | 59 | unsigned int i = 0; | ||
3655 | 60 | while (i < 4 && strarray[i]) { | ||
3656 | 61 | if (sp_svg_number_read_d(strarray[i], &val[i]) != 0) { | ||
3657 | 62 | i++; | ||
3658 | 63 | } else { | ||
3659 | 64 | break; | ||
3660 | 65 | } | ||
3661 | 66 | } | ||
3662 | 67 | g_strfreev (strarray); | ||
3663 | 68 | if (i == 4) { | ||
3664 | 69 | setOrigin( Geom::Point(val[0], val[1]) ); | ||
3665 | 70 | setVector( Geom::Point(val[2], val[3]) ); | ||
3666 | 71 | return true; | ||
3667 | 72 | } | ||
3668 | 73 | return false; | ||
3669 | 74 | } | ||
3670 | 75 | |||
3671 | 76 | gchar * | ||
3672 | 77 | TransformedPointParam::param_getSVGValue() const | ||
3673 | 78 | { | ||
3674 | 79 | Inkscape::SVGOStringStream os; | ||
3675 | 80 | os << origin << " , " << vector; | ||
3676 | 81 | gchar * str = g_strdup(os.str().c_str()); | ||
3677 | 82 | return str; | ||
3678 | 83 | } | ||
3679 | 84 | |||
3680 | 85 | Gtk::Widget * | ||
3681 | 86 | TransformedPointParam::param_newWidget() | ||
3682 | 87 | { | ||
3683 | 88 | Inkscape::UI::Widget::RegisteredVector * pointwdg = Gtk::manage( | ||
3684 | 89 | new Inkscape::UI::Widget::RegisteredVector( param_label, | ||
3685 | 90 | param_tooltip, | ||
3686 | 91 | param_key, | ||
3687 | 92 | *param_wr, | ||
3688 | 93 | param_effect->getRepr(), | ||
3689 | 94 | param_effect->getSPDoc() ) ); | ||
3690 | 95 | pointwdg->setPolarCoords(); | ||
3691 | 96 | pointwdg->setValue( vector, origin ); | ||
3692 | 97 | pointwdg->clearProgrammatically(); | ||
3693 | 98 | pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change vector parameter")); | ||
3694 | 99 | |||
3695 | 100 | Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); | ||
3696 | 101 | static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true); | ||
3697 | 102 | static_cast<Gtk::HBox*>(hbox)->show_all_children(); | ||
3698 | 103 | |||
3699 | 104 | return dynamic_cast<Gtk::Widget *> (hbox); | ||
3700 | 105 | } | ||
3701 | 106 | |||
3702 | 107 | void | ||
3703 | 108 | TransformedPointParam::set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector) | ||
3704 | 109 | { | ||
3705 | 110 | setValues(new_origin, new_vector); | ||
3706 | 111 | gchar * str = param_getSVGValue(); | ||
3707 | 112 | param_write_to_repr(str); | ||
3708 | 113 | g_free(str); | ||
3709 | 114 | } | ||
3710 | 115 | |||
3711 | 116 | void | ||
3712 | 117 | TransformedPointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) | ||
3713 | 118 | { | ||
3714 | 119 | if (!noTransform) { | ||
3715 | 120 | set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() ); | ||
3716 | 121 | } | ||
3717 | 122 | } | ||
3718 | 123 | |||
3719 | 124 | |||
3720 | 125 | void | ||
3721 | 126 | TransformedPointParam::set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) | ||
3722 | 127 | { | ||
3723 | 128 | vec_knot_shape = shape; | ||
3724 | 129 | vec_knot_mode = mode; | ||
3725 | 130 | vec_knot_color = color; | ||
3726 | 131 | } | ||
3727 | 132 | |||
3728 | 133 | void | ||
3729 | 134 | TransformedPointParam::set_oncanvas_color(guint32 color) | ||
3730 | 135 | { | ||
3731 | 136 | vec_knot_color = color; | ||
3732 | 137 | } | ||
3733 | 138 | |||
3734 | 139 | class TransformedPointParamKnotHolderEntity_Vector : public KnotHolderEntity { | ||
3735 | 140 | public: | ||
3736 | 141 | TransformedPointParamKnotHolderEntity_Vector(TransformedPointParam *p) : param(p) { } | ||
3737 | 142 | virtual ~TransformedPointParamKnotHolderEntity_Vector() {} | ||
3738 | 143 | |||
3739 | 144 | virtual void knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint /*state*/) { | ||
3740 | 145 | Geom::Point const s = p - param->origin; | ||
3741 | 146 | /// @todo implement angle snapping when holding CTRL | ||
3742 | 147 | param->setVector(s); | ||
3743 | 148 | sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); | ||
3744 | 149 | }; | ||
3745 | 150 | virtual Geom::Point knot_get() const{ | ||
3746 | 151 | return param->origin + param->vector; | ||
3747 | 152 | }; | ||
3748 | 153 | virtual void knot_click(guint /*state*/){ | ||
3749 | 154 | g_print ("This is the vector handle associated to parameter '%s'\n", param->param_key.c_str()); | ||
3750 | 155 | }; | ||
3751 | 156 | |||
3752 | 157 | private: | ||
3753 | 158 | TransformedPointParam *param; | ||
3754 | 159 | }; | ||
3755 | 160 | |||
3756 | 161 | void | ||
3757 | 162 | TransformedPointParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) | ||
3758 | 163 | { | ||
3759 | 164 | TransformedPointParamKnotHolderEntity_Vector *vector_e = new TransformedPointParamKnotHolderEntity_Vector(this); | ||
3760 | 165 | vector_e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color); | ||
3761 | 166 | knotholder->add(vector_e); | ||
3762 | 167 | } | ||
3763 | 168 | |||
3764 | 169 | } /* namespace LivePathEffect */ | ||
3765 | 170 | |||
3766 | 171 | } /* namespace Inkscape */ | ||
3767 | 172 | |||
3768 | 173 | /* | ||
3769 | 174 | Local Variables: | ||
3770 | 175 | mode:c++ | ||
3771 | 176 | c-file-style:"stroustrup" | ||
3772 | 177 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
3773 | 178 | indent-tabs-mode:nil | ||
3774 | 179 | fill-column:99 | ||
3775 | 180 | End: | ||
3776 | 181 | */ | ||
3777 | 182 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : | ||
3778 | 0 | 183 | ||
3779 | === added file 'src/live_effects/parameter/transformedpoint.h' | |||
3780 | --- src/live_effects/parameter/transformedpoint.h 1970-01-01 00:00:00 +0000 | |||
3781 | +++ src/live_effects/parameter/transformedpoint.h 2014-09-07 17:02:32 +0000 | |||
3782 | @@ -0,0 +1,87 @@ | |||
3783 | 1 | #ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_TRANSFORMED_POINT_H | ||
3784 | 2 | #define INKSCAPE_LIVEPATHEFFECT_PARAMETER_TRANSFORMED_POINT_H | ||
3785 | 3 | |||
3786 | 4 | /* | ||
3787 | 5 | * Inkscape::LivePathEffectParameters | ||
3788 | 6 | * | ||
3789 | 7 | * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> | ||
3790 | 8 | * | ||
3791 | 9 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
3792 | 10 | */ | ||
3793 | 11 | |||
3794 | 12 | #include <glib.h> | ||
3795 | 13 | #include <2geom/point.h> | ||
3796 | 14 | |||
3797 | 15 | #include "live_effects/parameter/parameter.h" | ||
3798 | 16 | |||
3799 | 17 | #include "knot-holder-entity.h" | ||
3800 | 18 | |||
3801 | 19 | namespace Inkscape { | ||
3802 | 20 | |||
3803 | 21 | namespace LivePathEffect { | ||
3804 | 22 | |||
3805 | 23 | |||
3806 | 24 | class TransformedPointParam : public Parameter { | ||
3807 | 25 | public: | ||
3808 | 26 | TransformedPointParam( const Glib::ustring& label, | ||
3809 | 27 | const Glib::ustring& tip, | ||
3810 | 28 | const Glib::ustring& key, | ||
3811 | 29 | Inkscape::UI::Widget::Registry* wr, | ||
3812 | 30 | Effect* effect, | ||
3813 | 31 | Geom::Point default_vector = Geom::Point(1,0), | ||
3814 | 32 | bool dontTransform = false); | ||
3815 | 33 | virtual ~TransformedPointParam(); | ||
3816 | 34 | |||
3817 | 35 | virtual Gtk::Widget * param_newWidget(); | ||
3818 | 36 | inline const gchar *handleTip() const { return param_tooltip.c_str(); } | ||
3819 | 37 | |||
3820 | 38 | virtual bool param_readSVGValue(const gchar * strvalue); | ||
3821 | 39 | virtual gchar * param_getSVGValue() const; | ||
3822 | 40 | |||
3823 | 41 | Geom::Point getVector() const { return vector; }; | ||
3824 | 42 | Geom::Point getOrigin() const { return origin; }; | ||
3825 | 43 | void setValues(Geom::Point const &new_origin, Geom::Point const &new_vector) { setVector(new_vector); setOrigin(new_origin); }; | ||
3826 | 44 | void setVector(Geom::Point const &new_vector) { vector = new_vector; }; | ||
3827 | 45 | void setOrigin(Geom::Point const &new_origin) { origin = new_origin; }; | ||
3828 | 46 | virtual void param_set_default(); | ||
3829 | 47 | |||
3830 | 48 | void set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector); | ||
3831 | 49 | |||
3832 | 50 | virtual void param_transform_multiply(Geom::Affine const &postmul, bool set); | ||
3833 | 51 | |||
3834 | 52 | void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); | ||
3835 | 53 | //void set_origin_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); | ||
3836 | 54 | void set_oncanvas_color(guint32 color); | ||
3837 | 55 | |||
3838 | 56 | virtual bool providesKnotHolderEntities() const { return true; } | ||
3839 | 57 | virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); | ||
3840 | 58 | |||
3841 | 59 | private: | ||
3842 | 60 | TransformedPointParam(const TransformedPointParam&); | ||
3843 | 61 | TransformedPointParam& operator=(const TransformedPointParam&); | ||
3844 | 62 | |||
3845 | 63 | Geom::Point defvalue; | ||
3846 | 64 | |||
3847 | 65 | Geom::Point origin; | ||
3848 | 66 | Geom::Point vector; | ||
3849 | 67 | |||
3850 | 68 | bool noTransform; | ||
3851 | 69 | |||
3852 | 70 | /// The looks of the vector and origin knots oncanvas | ||
3853 | 71 | SPKnotShapeType vec_knot_shape; | ||
3854 | 72 | SPKnotModeType vec_knot_mode; | ||
3855 | 73 | guint32 vec_knot_color; | ||
3856 | 74 | // SPKnotShapeType ori_knot_shape; | ||
3857 | 75 | // SPKnotModeType ori_knot_mode; | ||
3858 | 76 | // guint32 ori_knot_color; | ||
3859 | 77 | |||
3860 | 78 | // friend class VectorParamKnotHolderEntity_Origin; | ||
3861 | 79 | friend class TransformedPointParamKnotHolderEntity_Vector; | ||
3862 | 80 | }; | ||
3863 | 81 | |||
3864 | 82 | |||
3865 | 83 | } //namespace LivePathEffect | ||
3866 | 84 | |||
3867 | 85 | } //namespace Inkscape | ||
3868 | 86 | |||
3869 | 87 | #endif | ||
3870 | 0 | 88 | ||
3871 | === added file 'src/live_effects/pathoutlineprovider.cpp' | |||
3872 | --- src/live_effects/pathoutlineprovider.cpp 1970-01-01 00:00:00 +0000 | |||
3873 | +++ src/live_effects/pathoutlineprovider.cpp 2014-09-07 17:02:32 +0000 | |||
3874 | @@ -0,0 +1,795 @@ | |||
3875 | 1 | #include <glib.h> //g_critical | ||
3876 | 2 | |||
3877 | 3 | #include "pathoutlineprovider.h" | ||
3878 | 4 | #include "livarot/path-description.h" | ||
3879 | 5 | #include <2geom/angle.h> | ||
3880 | 6 | #include <2geom/path.h> | ||
3881 | 7 | #include <2geom/circle.h> | ||
3882 | 8 | #include <2geom/sbasis-to-bezier.h> | ||
3883 | 9 | #include <2geom/shape.h> | ||
3884 | 10 | #include <2geom/transforms.h> | ||
3885 | 11 | #include <2geom/path-sink.h> | ||
3886 | 12 | #include "helper/geom-nodetype.h" | ||
3887 | 13 | #include <svg/svg.h> | ||
3888 | 14 | |||
3889 | 15 | namespace Geom { | ||
3890 | 16 | /** | ||
3891 | 17 | * Refer to: Weisstein, Eric W. "Circle-Circle Intersection." | ||
3892 | 18 | From MathWorld--A Wolfram Web Resource. | ||
3893 | 19 | http://mathworld.wolfram.com/Circle-CircleIntersection.html | ||
3894 | 20 | * | ||
3895 | 21 | * @return 0 if no intersection | ||
3896 | 22 | * @return 1 if one circle is contained in the other | ||
3897 | 23 | * @return 2 if intersections are found (they are written to p0 and p1) | ||
3898 | 24 | */ | ||
3899 | 25 | static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, | ||
3900 | 26 | Point & p0, Point & p1) | ||
3901 | 27 | { | ||
3902 | 28 | Point X0 = circle0.center(); | ||
3903 | 29 | double r0 = circle0.ray(); | ||
3904 | 30 | Point X1 = circle1.center(); | ||
3905 | 31 | double r1 = circle1.ray(); | ||
3906 | 32 | |||
3907 | 33 | /* dx and dy are the vertical and horizontal distances between | ||
3908 | 34 | * the circle centers. | ||
3909 | 35 | */ | ||
3910 | 36 | Point D = X1 - X0; | ||
3911 | 37 | |||
3912 | 38 | /* Determine the straight-line distance between the centers. */ | ||
3913 | 39 | double d = L2(D); | ||
3914 | 40 | |||
3915 | 41 | /* Check for solvability. */ | ||
3916 | 42 | if (d > (r0 + r1)) { | ||
3917 | 43 | /* no solution. circles do not intersect. */ | ||
3918 | 44 | return 0; | ||
3919 | 45 | } | ||
3920 | 46 | if (d <= fabs(r0 - r1)) { | ||
3921 | 47 | /* no solution. one circle is contained in the other */ | ||
3922 | 48 | return 1; | ||
3923 | 49 | } | ||
3924 | 50 | |||
3925 | 51 | /* 'point 2' is the point where the line through the circle | ||
3926 | 52 | * intersection points crosses the line between the circle | ||
3927 | 53 | * centers. | ||
3928 | 54 | */ | ||
3929 | 55 | |||
3930 | 56 | /* Determine the distance from point 0 to point 2. */ | ||
3931 | 57 | double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; | ||
3932 | 58 | |||
3933 | 59 | /* Determine the coordinates of point 2. */ | ||
3934 | 60 | Point p2 = X0 + D * (a/d); | ||
3935 | 61 | |||
3936 | 62 | /* Determine the distance from point 2 to either of the | ||
3937 | 63 | * intersection points. | ||
3938 | 64 | */ | ||
3939 | 65 | double h = std::sqrt((r0*r0) - (a*a)); | ||
3940 | 66 | |||
3941 | 67 | /* Now determine the offsets of the intersection points from | ||
3942 | 68 | * point 2. | ||
3943 | 69 | */ | ||
3944 | 70 | Point r = (h/d)*rot90(D); | ||
3945 | 71 | |||
3946 | 72 | /* Determine the absolute intersection points. */ | ||
3947 | 73 | p0 = p2 + r; | ||
3948 | 74 | p1 = p2 - r; | ||
3949 | 75 | |||
3950 | 76 | return 2; | ||
3951 | 77 | } | ||
3952 | 78 | /** | ||
3953 | 79 | * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. | ||
3954 | 80 | * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). | ||
3955 | 81 | */ | ||
3956 | 82 | static Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.01 ) | ||
3957 | 83 | { | ||
3958 | 84 | D2<SBasis> dM=derivative(curve); | ||
3959 | 85 | if ( are_near(L2sq(dM(t)),0.) ) { | ||
3960 | 86 | dM=derivative(dM); | ||
3961 | 87 | } | ||
3962 | 88 | if ( are_near(L2sq(dM(t)),0.) ) { // try second time | ||
3963 | 89 | dM=derivative(dM); | ||
3964 | 90 | } | ||
3965 | 91 | Piecewise<D2<SBasis> > unitv = unitVector(dM,tol); | ||
3966 | 92 | Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv); | ||
3967 | 93 | Piecewise<SBasis> k = cross(derivative(unitv),unitv); | ||
3968 | 94 | k = divide(k,dMlength,tol,3); | ||
3969 | 95 | double curv = k(t); // note that this value is signed | ||
3970 | 96 | |||
3971 | 97 | Geom::Point normal = unitTangentAt(curve, t).cw(); | ||
3972 | 98 | double radius = 1/curv; | ||
3973 | 99 | Geom::Point center = curve(t) + radius*normal; | ||
3974 | 100 | return Geom::Circle(center, fabs(radius)); | ||
3975 | 101 | } | ||
3976 | 102 | |||
3977 | 103 | std::vector<Geom::Path> split_at_cusps(const Geom::Path& in) | ||
3978 | 104 | { | ||
3979 | 105 | PathVector out = PathVector(); | ||
3980 | 106 | Path temp = Path(); | ||
3981 | 107 | |||
3982 | 108 | for (unsigned i = 0; i < in.size(); i++) { | ||
3983 | 109 | temp.append(in[i]); | ||
3984 | 110 | if ( get_nodetype(in[i], in[i + 1]) != Geom::NODE_SMOOTH ) { | ||
3985 | 111 | out.push_back(temp); | ||
3986 | 112 | temp = Path(); | ||
3987 | 113 | } | ||
3988 | 114 | } | ||
3989 | 115 | if (temp.size() > 0) { | ||
3990 | 116 | out.push_back(temp); | ||
3991 | 117 | } | ||
3992 | 118 | return out; | ||
3993 | 119 | } | ||
3994 | 120 | |||
3995 | 121 | Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2<Geom::SBasis> const & sbasis_in) | ||
3996 | 122 | { | ||
3997 | 123 | std::vector<Geom::Point> temp; | ||
3998 | 124 | sbasis_to_bezier(temp, sbasis_in, 4); | ||
3999 | 125 | return Geom::CubicBezier( temp ); | ||
4000 | 126 | } | ||
4001 | 127 | |||
4002 | 128 | static boost::optional<Geom::Point> intersection_point(Geom::Point const & origin_a, Geom::Point const & vector_a, Geom::Point const & origin_b, Geom::Point const & vector_b) | ||
4003 | 129 | { | ||
4004 | 130 | Geom::Coord denom = cross(vector_b, vector_a); | ||
4005 | 131 | if (!Geom::are_near(denom,0.)) { | ||
4006 | 132 | Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; | ||
4007 | 133 | return origin_a + t * vector_a; | ||
4008 | 134 | } | ||
4009 | 135 | return boost::none; | ||
4010 | 136 | } | ||
4011 | 137 | |||
4012 | 138 | } // namespace Geom | ||
4013 | 139 | |||
4014 | 140 | namespace Outline { | ||
4015 | 141 | |||
4016 | 142 | typedef Geom::D2<Geom::SBasis> D2SB; | ||
4017 | 143 | typedef Geom::Piecewise<D2SB> PWD2; | ||
4018 | 144 | |||
4019 | 145 | // UTILITY | ||
4020 | 146 | |||
4021 | 147 | unsigned bezierOrder (const Geom::Curve* curve_in) | ||
4022 | 148 | { | ||
4023 | 149 | using namespace Geom; | ||
4024 | 150 | if ( const BezierCurve* bz = dynamic_cast<const BezierCurve*>(curve_in) ) { | ||
4025 | 151 | return bz->order(); | ||
4026 | 152 | } | ||
4027 | 153 | return 0; | ||
4028 | 154 | } | ||
4029 | 155 | |||
4030 | 156 | /** | ||
4031 | 157 | * @return true if the angle formed by the curves and their handles is greater than 180 degrees clockwise, otherwise false. | ||
4032 | 158 | */ | ||
4033 | 159 | bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) | ||
4034 | 160 | { | ||
4035 | 161 | Geom::Point start_point; | ||
4036 | 162 | Geom::Point cross_point = cbc1.finalPoint(); | ||
4037 | 163 | Geom::Point end_point; | ||
4038 | 164 | |||
4039 | 165 | if (cross_point != cbc2.initialPoint()) { | ||
4040 | 166 | g_warning("Non-contiguous path in Outline::outside_angle()"); | ||
4041 | 167 | return false; | ||
4042 | 168 | } | ||
4043 | 169 | |||
4044 | 170 | Geom::CubicBezier cubicBezier = Geom::sbasis_to_cubicbezier(cbc1.toSBasis()); | ||
4045 | 171 | start_point = cubicBezier [2]; | ||
4046 | 172 | |||
4047 | 173 | /* | ||
4048 | 174 | * Because the node editor does not yet support true quadratics, paths are converted to | ||
4049 | 175 | * cubic beziers in the node tool with degenerate handles on one side. | ||
4050 | 176 | */ | ||
4051 | 177 | |||
4052 | 178 | if (are_near(start_point, cross_point, 0.0000001)) { | ||
4053 | 179 | start_point = cubicBezier [1]; | ||
4054 | 180 | } | ||
4055 | 181 | cubicBezier = Geom::sbasis_to_cubicbezier(cbc2.toSBasis()); | ||
4056 | 182 | end_point = cubicBezier [1]; | ||
4057 | 183 | if (are_near(end_point, cross_point, 0.0000001)) { | ||
4058 | 184 | end_point = cubicBezier [2]; | ||
4059 | 185 | } | ||
4060 | 186 | |||
4061 | 187 | // got our three points, now let's see what their clockwise angle is | ||
4062 | 188 | |||
4063 | 189 | // Definition of a Graham scan | ||
4064 | 190 | |||
4065 | 191 | /******************************************************************** | ||
4066 | 192 | # Three points are a counter-clockwise turn if ccw > 0, clockwise if | ||
4067 | 193 | # ccw < 0, and collinear if ccw = 0 because ccw is a determinant that | ||
4068 | 194 | # gives the signed area of the triangle formed by p1, p2 and p3. | ||
4069 | 195 | function ccw(p1, p2, p3): | ||
4070 | 196 | return (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x) | ||
4071 | 197 | *********************************************************************/ | ||
4072 | 198 | |||
4073 | 199 | double ccw = ( (cross_point.x() - start_point.x()) * (end_point.y() - start_point.y()) ) - | ||
4074 | 200 | ( (cross_point.y() - start_point.y()) * (end_point.x() - start_point.x()) ); | ||
4075 | 201 | return ccw > 0; | ||
4076 | 202 | } | ||
4077 | 203 | |||
4078 | 204 | // LINE JOINS | ||
4079 | 205 | |||
4080 | 206 | typedef Geom::BezierCurveN<1u> BezierLine; | ||
4081 | 207 | |||
4082 | 208 | /** | ||
4083 | 209 | * Removes the crossings on an interior join. | ||
4084 | 210 | * @param path_builder Contains the incoming segment; result is appended to this | ||
4085 | 211 | * @param outgoing The outgoing segment | ||
4086 | 212 | */ | ||
4087 | 213 | void joinInside(Geom::Path& path_builder, Geom::Curve const& outgoing) { | ||
4088 | 214 | Geom::Curve const& incoming = path_builder.back(); | ||
4089 | 215 | |||
4090 | 216 | // Using Geom::crossings to find intersections between two curves | ||
4091 | 217 | Geom::Crossings cross = Geom::crossings(incoming, outgoing); | ||
4092 | 218 | if (!cross.empty()) { | ||
4093 | 219 | // Crossings found, create the join | ||
4094 | 220 | Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(incoming.toSBasis()); | ||
4095 | 221 | cubic = cubic.subdivide(cross[0].ta).first; | ||
4096 | 222 | // erase the last segment, as we're going to overwrite it now | ||
4097 | 223 | path_builder.erase_last(); | ||
4098 | 224 | path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); | ||
4099 | 225 | |||
4100 | 226 | cubic = Geom::sbasis_to_cubicbezier(outgoing.toSBasis()); | ||
4101 | 227 | cubic = cubic.subdivide(cross[0].tb).second; | ||
4102 | 228 | path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); | ||
4103 | 229 | } else { | ||
4104 | 230 | // No crossings occurred, or Geom::crossings() failed; default to bevel | ||
4105 | 231 | if (Geom::are_near(incoming.finalPoint(), outgoing.initialPoint())) { | ||
4106 | 232 | path_builder.appendNew<BezierLine>(outgoing.initialPoint()); | ||
4107 | 233 | } else { | ||
4108 | 234 | path_builder.setFinal(outgoing.initialPoint()); | ||
4109 | 235 | } | ||
4110 | 236 | } | ||
4111 | 237 | } | ||
4112 | 238 | |||
4113 | 239 | /** | ||
4114 | 240 | * Try to create a miter join. Falls back to bevel if no miter can be created. | ||
4115 | 241 | * @param path_builder Path to append curves to; back() is the incoming curve | ||
4116 | 242 | * @param outgoing Outgoing curve. | ||
4117 | 243 | * @param miter_limit When mitering, don't exceed this length | ||
4118 | 244 | * @param line_width The thickness of the line. | ||
4119 | 245 | */ | ||
4120 | 246 | void miter_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) { | ||
4121 | 247 | using namespace Geom; | ||
4122 | 248 | Curve const& incoming = path_builder.back(); | ||
4123 | 249 | Point tang1 = unitTangentAt(Geom::reverse(incoming.toSBasis()), 0.); | ||
4124 | 250 | Point tang2 = unitTangentAt(outgoing.toSBasis(), 0); | ||
4125 | 251 | |||
4126 | 252 | boost::optional <Point> p = intersection_point (incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2); | ||
4127 | 253 | if (p) { | ||
4128 | 254 | // check size of miter | ||
4129 | 255 | Point point_on_path = incoming.finalPoint() - rot90(tang1) * line_width; | ||
4130 | 256 | Coord len = distance(*p, point_on_path); | ||
4131 | 257 | if (len <= miter_limit) { | ||
4132 | 258 | // miter OK | ||
4133 | 259 | path_builder.appendNew<BezierLine>(*p); | ||
4134 | 260 | } | ||
4135 | 261 | } | ||
4136 | 262 | path_builder.appendNew<BezierLine>(outgoing.initialPoint()); | ||
4137 | 263 | } | ||
4138 | 264 | |||
4139 | 265 | /** | ||
4140 | 266 | * Smoothly extrapolate curves along a circular route. Falls back to miter if necessary. | ||
4141 | 267 | * @param path_builder Path to append curves to; back() is the incoming curve | ||
4142 | 268 | * @param outgoing Outgoing curve. | ||
4143 | 269 | * @param miter_limit When mitering, don't exceed this length | ||
4144 | 270 | * @param line_width The thickness of the line. Used for miter fallback. | ||
4145 | 271 | */ | ||
4146 | 272 | void extrapolate_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) { | ||
4147 | 273 | Geom::Curve const& incoming = path_builder.back(); | ||
4148 | 274 | Geom::Point endPt = outgoing.initialPoint(); | ||
4149 | 275 | |||
4150 | 276 | // The method used when extrapolating curves fails to work when either side of the join to be extrapolated | ||
4151 | 277 | // is a line segment. When this situation is encountered, fall back to a regular miter join. | ||
4152 | 278 | bool lineProblem = (dynamic_cast<const BezierLine *>(&incoming)) || (dynamic_cast<const BezierLine *>(&outgoing)); | ||
4153 | 279 | if (lineProblem == false) { | ||
4154 | 280 | // Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(incoming.toSBasis()), 0.); | ||
4155 | 281 | Geom::Point tang2 = Geom::unitTangentAt(outgoing.toSBasis(), 0); | ||
4156 | 282 | |||
4157 | 283 | Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.); | ||
4158 | 284 | Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0); | ||
4159 | 285 | |||
4160 | 286 | Geom::Point points[2]; | ||
4161 | 287 | int solutions = Geom::circle_circle_intersection(circle1, circle2, points[0], points[1]); | ||
4162 | 288 | if (solutions == 2) { | ||
4163 | 289 | Geom::Point sol(0,0); | ||
4164 | 290 | if ( dot(tang2,points[0]-endPt) > 0 ) { | ||
4165 | 291 | // points[0] is bad, choose points[1] | ||
4166 | 292 | sol = points[1]; | ||
4167 | 293 | } else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1] | ||
4168 | 294 | // points[1] is bad, choose points[0] | ||
4169 | 295 | sol = points[0]; | ||
4170 | 296 | } else { | ||
4171 | 297 | // both points are good, choose nearest | ||
4172 | 298 | sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? points[0] : points[1]; | ||
4173 | 299 | } | ||
4174 | 300 | |||
4175 | 301 | Geom::EllipticalArc *arc0 = circle1.arc(incoming.finalPoint(), 0.5*(incoming.finalPoint()+sol), sol, true); | ||
4176 | 302 | Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); | ||
4177 | 303 | try { | ||
4178 | 304 | if (arc0) { | ||
4179 | 305 | path_builder.append (arc0->toSBasis()); | ||
4180 | 306 | delete arc0; | ||
4181 | 307 | arc0 = NULL; | ||
4182 | 308 | } else { | ||
4183 | 309 | throw std::exception(); | ||
4184 | 310 | } | ||
4185 | 311 | |||
4186 | 312 | if (arc1) { | ||
4187 | 313 | path_builder.append (arc1->toSBasis()); | ||
4188 | 314 | delete arc1; | ||
4189 | 315 | arc1 = NULL; | ||
4190 | 316 | } else { | ||
4191 | 317 | throw std::exception(); | ||
4192 | 318 | } | ||
4193 | 319 | |||
4194 | 320 | } catch (std::exception const & ex) { | ||
4195 | 321 | g_warning("Error extrapolating line join: %s\n", ex.what()); | ||
4196 | 322 | path_builder.appendNew<Geom::LineSegment>(endPt); | ||
4197 | 323 | } | ||
4198 | 324 | } else { | ||
4199 | 325 | // 1 or no solutions found, default to miter | ||
4200 | 326 | miter_curves(path_builder, outgoing, miter_limit, line_width); | ||
4201 | 327 | } | ||
4202 | 328 | } else { | ||
4203 | 329 | // Line segments exist | ||
4204 | 330 | miter_curves(path_builder, outgoing, miter_limit, line_width); | ||
4205 | 331 | } | ||
4206 | 332 | } | ||
4207 | 333 | |||
4208 | 334 | /** | ||
4209 | 335 | * Extrapolate curves by reflecting them along the line that would be given by beveling the join. | ||
4210 | 336 | * @param path_builder Path to append curves to; back() is the incoming curve | ||
4211 | 337 | * @param outgoing Outgoing curve. | ||
4212 | 338 | * @param miter_limit When mitering, don't exceed this length | ||
4213 | 339 | * @param line_width The thickness of the line. Used for miter fallback. | ||
4214 | 340 | */ | ||
4215 | 341 | void reflect_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) | ||
4216 | 342 | { | ||
4217 | 343 | using namespace Geom; | ||
4218 | 344 | Curve const& incoming = path_builder.back(); | ||
4219 | 345 | // On the outside, we'll take the incoming curve, the outgoing curve, and | ||
4220 | 346 | // reflect them over the line formed by taking the unit tangent vector at times | ||
4221 | 347 | // 0 and 1, respectively, rotated by 90 degrees. | ||
4222 | 348 | Crossings cross; | ||
4223 | 349 | |||
4224 | 350 | // reflect curves along the line that would be given by beveling the join | ||
4225 | 351 | Point tang1 = unitTangentAt(reverse(incoming.toSBasis()), 0.); | ||
4226 | 352 | D2SB newcurve1 = incoming.toSBasis() * reflection(-rot90(tang1), incoming.finalPoint()); | ||
4227 | 353 | CubicBezier bzr1 = sbasis_to_cubicbezier(reverse(newcurve1)); | ||
4228 | 354 | |||
4229 | 355 | Point tang2 = Geom::unitTangentAt(outgoing.toSBasis(), 0.); | ||
4230 | 356 | D2SB newcurve2 = outgoing.toSBasis() * reflection(-rot90(tang2), outgoing.initialPoint()); | ||
4231 | 357 | CubicBezier bzr2 = sbasis_to_cubicbezier(reverse(newcurve2)); | ||
4232 | 358 | |||
4233 | 359 | cross = crossings(bzr1, bzr2); | ||
4234 | 360 | if (cross.empty()) { | ||
4235 | 361 | // paths don't cross, fall back to miter | ||
4236 | 362 | miter_curves(path_builder, outgoing, miter_limit, line_width); | ||
4237 | 363 | } else { | ||
4238 | 364 | // reflected join | ||
4239 | 365 | std::pair<CubicBezier, CubicBezier> sub1 = bzr1.subdivide(cross[0].ta); | ||
4240 | 366 | std::pair<CubicBezier, CubicBezier> sub2 = bzr2.subdivide(cross[0].tb); | ||
4241 | 367 | |||
4242 | 368 | // TODO it seems as if a bug in 2geom sometimes doesn't catch the first | ||
4243 | 369 | // crossing of paths, but the second instead; but only sometimes. | ||
4244 | 370 | path_builder.appendNew <CubicBezier> (sub1.first[1], sub1.first[2], sub2.second[0]); | ||
4245 | 371 | path_builder.appendNew <CubicBezier> (sub2.second[1], sub2.second[2], outgoing.initialPoint()); | ||
4246 | 372 | } | ||
4247 | 373 | } | ||
4248 | 374 | |||
4249 | 375 | // Ideal function pointer we want to pass | ||
4250 | 376 | typedef void JoinFunc(Geom::Path& /*path_builder*/, Geom::Curve const& /*outgoing*/, double /*miter_limit*/, double /*line_width*/); | ||
4251 | 377 | |||
4252 | 378 | /** | ||
4253 | 379 | * Helper function for repeated logic in outlineHalf. | ||
4254 | 380 | */ | ||
4255 | 381 | static void outlineHelper(Geom::Path& path_builder, Geom::PathVector* path_vec, bool outside, double width, double miter, JoinFunc func) { | ||
4256 | 382 | Geom::Curve * cbc2 = path_vec->front()[0].duplicate(); | ||
4257 | 383 | |||
4258 | 384 | if (outside) { | ||
4259 | 385 | func(path_builder, *cbc2, miter, width); | ||
4260 | 386 | } else { | ||
4261 | 387 | joinInside(path_builder, *cbc2); | ||
4262 | 388 | } | ||
4263 | 389 | |||
4264 | 390 | // store it | ||
4265 | 391 | Geom::Path temp_path = path_vec->front(); | ||
4266 | 392 | if (!outside) { | ||
4267 | 393 | // erase the first segment since the inside join code already appended it | ||
4268 | 394 | temp_path.erase(temp_path.begin()); | ||
4269 | 395 | } | ||
4270 | 396 | |||
4271 | 397 | if (temp_path.initialPoint() != path_builder.finalPoint()) { | ||
4272 | 398 | temp_path.setInitial(path_builder.finalPoint()); | ||
4273 | 399 | } | ||
4274 | 400 | |||
4275 | 401 | path_builder.append(temp_path); | ||
4276 | 402 | |||
4277 | 403 | delete cbc2; | ||
4278 | 404 | } | ||
4279 | 405 | |||
4280 | 406 | /** | ||
4281 | 407 | * Offsets exactly one half of a bezier spline (path). | ||
4282 | 408 | * @param path_in The input path to use. (To create the other side use path_in.reverse() ) | ||
4283 | 409 | * @param line_width the line width to use (usually you want to divide this by 2) | ||
4284 | 410 | * @param miter_limit the miter parameter | ||
4285 | 411 | * @param func Join function to apply at each join. | ||
4286 | 412 | */ | ||
4287 | 413 | |||
4288 | 414 | Geom::Path outlineHalf(const Geom::Path& path_in, double line_width, double miter_limit, JoinFunc func) { | ||
4289 | 415 | // NOTE: it is important to notice the distinction between a Geom::Path and a livarot ::Path here! | ||
4290 | 416 | // if you do not see "Geom::" there is a different function set! | ||
4291 | 417 | |||
4292 | 418 | Geom::PathVector pv = split_at_cusps(path_in); | ||
4293 | 419 | |||
4294 | 420 | ::Path to_outline; | ||
4295 | 421 | ::Path outlined_result; | ||
4296 | 422 | |||
4297 | 423 | Geom::Path path_builder = Geom::Path(); // the path to store the result in | ||
4298 | 424 | Geom::PathVector* path_vec; // needed because livarot returns a pointer (TODO make this not a pointer) | ||
4299 | 425 | |||
4300 | 426 | // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well | ||
4301 | 427 | const size_t k = pv.size(); | ||
4302 | 428 | for (size_t u = 0; u < k; u += 2) { | ||
4303 | 429 | to_outline = Path(); | ||
4304 | 430 | outlined_result = Path(); | ||
4305 | 431 | |||
4306 | 432 | to_outline.LoadPath(pv[u], Geom::identity(), false, false); | ||
4307 | 433 | to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); | ||
4308 | 434 | // now a curve has been outside outlined and loaded into outlined_result | ||
4309 | 435 | |||
4310 | 436 | // get the Geom::Path | ||
4311 | 437 | path_vec = outlined_result.MakePathVector(); | ||
4312 | 438 | |||
4313 | 439 | // on the first run through, there is no join | ||
4314 | 440 | if (u == 0) { | ||
4315 | 441 | path_builder.start(path_vec->front().initialPoint()); | ||
4316 | 442 | path_builder.append(path_vec->front()); | ||
4317 | 443 | } else { | ||
4318 | 444 | outlineHelper(path_builder, path_vec, outside_angle(pv[u-1][pv[u-1].size()-1], pv[u][0]), line_width, miter_limit, func); | ||
4319 | 445 | } | ||
4320 | 446 | |||
4321 | 447 | // outline the next segment, but don't store it yet | ||
4322 | 448 | if (path_vec) | ||
4323 | 449 | delete path_vec; | ||
4324 | 450 | path_vec = NULL; | ||
4325 | 451 | |||
4326 | 452 | // odd number of paths | ||
4327 | 453 | if (u < k - 1) { | ||
4328 | 454 | outlined_result = Path(); | ||
4329 | 455 | to_outline = Path(); | ||
4330 | 456 | |||
4331 | 457 | to_outline.LoadPath(pv[u+1], Geom::Affine(), false, false); | ||
4332 | 458 | to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); | ||
4333 | 459 | |||
4334 | 460 | path_vec = outlined_result.MakePathVector(); | ||
4335 | 461 | outlineHelper(path_builder, path_vec, outside_angle(pv[u][pv[u].size()-1], pv[u+1][0]), line_width, miter_limit, func); | ||
4336 | 462 | |||
4337 | 463 | if (path_vec) | ||
4338 | 464 | delete path_vec; | ||
4339 | 465 | path_vec = NULL; | ||
4340 | 466 | } | ||
4341 | 467 | } | ||
4342 | 468 | |||
4343 | 469 | if (path_in.closed()) { | ||
4344 | 470 | Geom::Curve * cbc1; | ||
4345 | 471 | Geom::Curve * cbc2; | ||
4346 | 472 | |||
4347 | 473 | if ( path_in[path_in.size()].isDegenerate() ) { | ||
4348 | 474 | // handle case for last segment curved | ||
4349 | 475 | outlined_result = Path(); | ||
4350 | 476 | to_outline = Path(); | ||
4351 | 477 | |||
4352 | 478 | Geom::Path oneCurve; oneCurve.append(path_in[0]); | ||
4353 | 479 | |||
4354 | 480 | to_outline.LoadPath(oneCurve, Geom::Affine(), false, false); | ||
4355 | 481 | to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); | ||
4356 | 482 | |||
4357 | 483 | path_vec = outlined_result.MakePathVector(); | ||
4358 | 484 | |||
4359 | 485 | cbc1 = path_builder[path_builder.size() - 1].duplicate(); | ||
4360 | 486 | cbc2 = path_vec->front()[0].duplicate(); | ||
4361 | 487 | |||
4362 | 488 | delete path_vec; | ||
4363 | 489 | } else { | ||
4364 | 490 | // handle case for last segment straight | ||
4365 | 491 | // since the path doesn't actually give us access to it, we'll do it ourselves | ||
4366 | 492 | outlined_result = Path(); | ||
4367 | 493 | to_outline = Path(); | ||
4368 | 494 | |||
4369 | 495 | Geom::Path oneCurve; oneCurve.append(Geom::LineSegment(path_in.finalPoint(), path_in.initialPoint())); | ||
4370 | 496 | |||
4371 | 497 | to_outline.LoadPath(oneCurve, Geom::Affine(), false, false); | ||
4372 | 498 | to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); | ||
4373 | 499 | |||
4374 | 500 | path_vec = outlined_result.MakePathVector(); | ||
4375 | 501 | |||
4376 | 502 | cbc1 = path_builder[path_builder.size() - 1].duplicate(); | ||
4377 | 503 | cbc2 = (*path_vec)[0] [0].duplicate(); | ||
4378 | 504 | |||
4379 | 505 | outlineHelper(path_builder, path_vec, outside_angle(path_in[path_in.size()-1], oneCurve[0]), line_width, miter_limit, func); | ||
4380 | 506 | |||
4381 | 507 | delete cbc1; | ||
4382 | 508 | cbc1 = cbc2->duplicate(); | ||
4383 | 509 | delete path_vec; | ||
4384 | 510 | |||
4385 | 511 | oneCurve = Geom::Path(); oneCurve.append(path_in[0]); | ||
4386 | 512 | |||
4387 | 513 | to_outline.LoadPath(oneCurve, Geom::Affine(), false, false); | ||
4388 | 514 | to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); | ||
4389 | 515 | |||
4390 | 516 | path_vec = outlined_result.MakePathVector(); | ||
4391 | 517 | delete cbc2; cbc2 = (*path_vec)[0] [0].duplicate(); | ||
4392 | 518 | delete path_vec; | ||
4393 | 519 | } | ||
4394 | 520 | |||
4395 | 521 | Geom::Path temporary; | ||
4396 | 522 | temporary.append(*cbc1); | ||
4397 | 523 | |||
4398 | 524 | Geom::Curve const & prev_curve = path_in[path_in.size()].isDegenerate() ? path_in[path_in.size() - 1] : path_in[path_in.size()]; | ||
4399 | 525 | Geom::Path isStraight; | ||
4400 | 526 | isStraight.append(prev_curve); | ||
4401 | 527 | isStraight.append(path_in[0]); | ||
4402 | 528 | // does closing path require a join? | ||
4403 | 529 | if (Geom::split_at_cusps(isStraight).size() > 1) { | ||
4404 | 530 | bool outside = outside_angle(prev_curve, path_in[0]); | ||
4405 | 531 | if (outside) { | ||
4406 | 532 | func(temporary, *cbc2, miter_limit, line_width); | ||
4407 | 533 | } else { | ||
4408 | 534 | joinInside(temporary, *cbc2); | ||
4409 | 535 | path_builder.erase(path_builder.begin()); | ||
4410 | 536 | } | ||
4411 | 537 | |||
4412 | 538 | // extract the appended curves | ||
4413 | 539 | path_builder.erase_last(); | ||
4414 | 540 | if (Geom::are_near(path_builder.finalPoint(), temporary.initialPoint())) { | ||
4415 | 541 | path_builder.setFinal(temporary.initialPoint()); | ||
4416 | 542 | } else { | ||
4417 | 543 | path_builder.appendNew<BezierLine>(temporary.initialPoint()); | ||
4418 | 544 | } | ||
4419 | 545 | path_builder.append(temporary); | ||
4420 | 546 | } else { | ||
4421 | 547 | // closing path does not require a join | ||
4422 | 548 | path_builder.setFinal(path_builder.initialPoint()); | ||
4423 | 549 | } | ||
4424 | 550 | path_builder.close(); | ||
4425 | 551 | |||
4426 | 552 | if (cbc1) delete cbc1; | ||
4427 | 553 | if (cbc2) delete cbc2; | ||
4428 | 554 | } | ||
4429 | 555 | |||
4430 | 556 | return path_builder; | ||
4431 | 557 | } | ||
4432 | 558 | |||
4433 | 559 | Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtTypeMod butt, double miter_lim, bool extrapolate, double start_lean, double end_lean) | ||
4434 | 560 | { | ||
4435 | 561 | Geom::PathVector path_out; | ||
4436 | 562 | |||
4437 | 563 | unsigned pv_size = path_in.size(); | ||
4438 | 564 | for (unsigned i = 0; i < pv_size; i++) { | ||
4439 | 565 | |||
4440 | 566 | if (path_in[i].size() > 1) { | ||
4441 | 567 | Geom::Path with_direction; | ||
4442 | 568 | Geom::Path against_direction; | ||
4443 | 569 | |||
4444 | 570 | with_direction = Outline::outlineHalf(path_in[i], -line_width, miter_lim, extrapolate ? extrapolate_curves : reflect_curves); | ||
4445 | 571 | against_direction = Outline::outlineHalf(path_in[i].reverse(), -line_width, miter_lim, extrapolate ? extrapolate_curves : reflect_curves); | ||
4446 | 572 | |||
4447 | 573 | Geom::PathBuilder pb; | ||
4448 | 574 | |||
4449 | 575 | pb.moveTo(with_direction.initialPoint()); | ||
4450 | 576 | pb.append(with_direction); | ||
4451 | 577 | |||
4452 | 578 | //add in our line caps | ||
4453 | 579 | if (!path_in[i].closed()) { | ||
4454 | 580 | switch (butt) { | ||
4455 | 581 | case BUTT_STRAIGHT: | ||
4456 | 582 | pb.lineTo(against_direction.initialPoint()); | ||
4457 | 583 | break; | ||
4458 | 584 | case BUTT_ROUND: | ||
4459 | 585 | pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, against_direction.initialPoint() ); | ||
4460 | 586 | break; | ||
4461 | 587 | case BUTT_POINTY: { | ||
4462 | 588 | Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.); | ||
4463 | 589 | double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); | ||
4464 | 590 | Geom::Point midpoint = 0.5 * (with_direction.finalPoint() + against_direction.initialPoint()) + radius*end_deriv; | ||
4465 | 591 | pb.lineTo(midpoint); | ||
4466 | 592 | pb.lineTo(against_direction.initialPoint()); | ||
4467 | 593 | break; | ||
4468 | 594 | } | ||
4469 | 595 | case BUTT_SQUARE: { | ||
4470 | 596 | Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.); | ||
4471 | 597 | double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); | ||
4472 | 598 | pb.lineTo(with_direction.finalPoint() + radius*end_deriv); | ||
4473 | 599 | pb.lineTo(against_direction.initialPoint() + radius*end_deriv); | ||
4474 | 600 | pb.lineTo(against_direction.initialPoint()); | ||
4475 | 601 | break; | ||
4476 | 602 | } | ||
4477 | 603 | case BUTT_LEANED: { | ||
4478 | 604 | Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.); | ||
4479 | 605 | double maxRadius = (end_lean+0.5) * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); | ||
4480 | 606 | double minRadius = ((end_lean*-1)+0.5) * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); | ||
4481 | 607 | pb.lineTo(with_direction.finalPoint() + maxRadius*end_deriv); | ||
4482 | 608 | pb.lineTo(against_direction.initialPoint() + minRadius*end_deriv); | ||
4483 | 609 | pb.lineTo(against_direction.initialPoint()); | ||
4484 | 610 | break; | ||
4485 | 611 | } | ||
4486 | 612 | } | ||
4487 | 613 | } else { | ||
4488 | 614 | pb.moveTo(against_direction.initialPoint()); | ||
4489 | 615 | } | ||
4490 | 616 | |||
4491 | 617 | pb.append(against_direction); | ||
4492 | 618 | |||
4493 | 619 | //cap (if necessary) | ||
4494 | 620 | if (!path_in[i].closed()) { | ||
4495 | 621 | switch (butt) { | ||
4496 | 622 | case BUTT_STRAIGHT: | ||
4497 | 623 | pb.lineTo(with_direction.initialPoint()); | ||
4498 | 624 | break; | ||
4499 | 625 | case BUTT_ROUND: | ||
4500 | 626 | pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, with_direction.initialPoint() ); | ||
4501 | 627 | break; | ||
4502 | 628 | case BUTT_POINTY: { | ||
4503 | 629 | Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.); | ||
4504 | 630 | double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); | ||
4505 | 631 | Geom::Point midpoint = 0.5 * (against_direction.finalPoint() + with_direction.initialPoint()) + radius*end_deriv; | ||
4506 | 632 | pb.lineTo(midpoint); | ||
4507 | 633 | pb.lineTo(with_direction.initialPoint()); | ||
4508 | 634 | break; | ||
4509 | 635 | } | ||
4510 | 636 | case BUTT_SQUARE: { | ||
4511 | 637 | Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.); | ||
4512 | 638 | double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); | ||
4513 | 639 | pb.lineTo(against_direction.finalPoint() + radius*end_deriv); | ||
4514 | 640 | pb.lineTo(with_direction.initialPoint() + radius*end_deriv); | ||
4515 | 641 | pb.lineTo(with_direction.initialPoint()); | ||
4516 | 642 | break; | ||
4517 | 643 | } | ||
4518 | 644 | case BUTT_LEANED: { | ||
4519 | 645 | Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.); | ||
4520 | 646 | double maxRadius = (start_lean+0.5) * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); | ||
4521 | 647 | double minRadius = ((start_lean*-1)+0.5) * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); | ||
4522 | 648 | pb.lineTo(against_direction.finalPoint() + minRadius*end_deriv); | ||
4523 | 649 | pb.lineTo(with_direction.initialPoint() + maxRadius*end_deriv); | ||
4524 | 650 | pb.lineTo(with_direction.initialPoint()); | ||
4525 | 651 | break; | ||
4526 | 652 | } | ||
4527 | 653 | } | ||
4528 | 654 | } | ||
4529 | 655 | pb.flush(); | ||
4530 | 656 | path_out.push_back(pb.peek()[0]); | ||
4531 | 657 | if (path_in[i].closed()) { | ||
4532 | 658 | path_out.push_back(pb.peek()[1]); | ||
4533 | 659 | } | ||
4534 | 660 | } else { | ||
4535 | 661 | Path p = Path(); | ||
4536 | 662 | Path outlinepath = Path(); | ||
4537 | 663 | ButtType original_butt; | ||
4538 | 664 | switch (butt) { | ||
4539 | 665 | case BUTT_STRAIGHT: | ||
4540 | 666 | original_butt = butt_straight; | ||
4541 | 667 | break; | ||
4542 | 668 | case BUTT_ROUND: | ||
4543 | 669 | original_butt = butt_round; | ||
4544 | 670 | break; | ||
4545 | 671 | case butt_pointy: { | ||
4546 | 672 | original_butt = butt_pointy; | ||
4547 | 673 | break; | ||
4548 | 674 | } | ||
4549 | 675 | case BUTT_SQUARE: { | ||
4550 | 676 | original_butt = butt_square; | ||
4551 | 677 | break; | ||
4552 | 678 | } | ||
4553 | 679 | case BUTT_LEANED: { | ||
4554 | 680 | original_butt = butt_straight; | ||
4555 | 681 | break; | ||
4556 | 682 | } | ||
4557 | 683 | } | ||
4558 | 684 | p.LoadPath(path_in[i], Geom::Affine(), false, false); | ||
4559 | 685 | p.Outline(&outlinepath, line_width / 2, static_cast<join_typ>(join), original_butt, miter_lim); | ||
4560 | 686 | Geom::PathVector *pv_p = outlinepath.MakePathVector(); | ||
4561 | 687 | //somewhat hack-ish | ||
4562 | 688 | path_out.push_back( (*pv_p)[0].reverse() ); | ||
4563 | 689 | if (pv_p) delete pv_p; | ||
4564 | 690 | } | ||
4565 | 691 | } | ||
4566 | 692 | return path_out; | ||
4567 | 693 | } | ||
4568 | 694 | |||
4569 | 695 | Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtTypeMod linecap_type, LineJoinType linejoin_type, double miter_limit, double start_lean, double end_lean) | ||
4570 | 696 | { | ||
4571 | 697 | std::vector<Geom::Path> path_out = std::vector<Geom::Path>(); | ||
4572 | 698 | if (path_in.empty()) { | ||
4573 | 699 | return path_out; | ||
4574 | 700 | } | ||
4575 | 701 | Path p = Path(); | ||
4576 | 702 | Path outlinepath = Path(); | ||
4577 | 703 | for (unsigned i = 0; i < path_in.size(); i++) { | ||
4578 | 704 | p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); | ||
4579 | 705 | } | ||
4580 | 706 | |||
4581 | 707 | #define miter_lim fabs(line_width * miter_limit) | ||
4582 | 708 | |||
4583 | 709 | //magic! | ||
4584 | 710 | ButtType original_butt; | ||
4585 | 711 | switch (linecap_type) { | ||
4586 | 712 | case BUTT_STRAIGHT: | ||
4587 | 713 | original_butt = butt_straight; | ||
4588 | 714 | break; | ||
4589 | 715 | case BUTT_ROUND: | ||
4590 | 716 | original_butt = butt_round; | ||
4591 | 717 | break; | ||
4592 | 718 | case butt_pointy: { | ||
4593 | 719 | original_butt = butt_pointy; | ||
4594 | 720 | break; | ||
4595 | 721 | } | ||
4596 | 722 | case BUTT_SQUARE: { | ||
4597 | 723 | original_butt = butt_square; | ||
4598 | 724 | break; | ||
4599 | 725 | } | ||
4600 | 726 | case BUTT_LEANED: { | ||
4601 | 727 | original_butt = butt_straight; | ||
4602 | 728 | break; | ||
4603 | 729 | } | ||
4604 | 730 | } | ||
4605 | 731 | if (linejoin_type <= LINEJOIN_POINTY) { | ||
4606 | 732 | p.Outline(&outlinepath, line_width / 2, static_cast<join_typ>(linejoin_type), | ||
4607 | 733 | original_butt, miter_lim); | ||
4608 | 734 | // fix memory leak | ||
4609 | 735 | std::vector<Geom::Path> *pv_p = outlinepath.MakePathVector(); | ||
4610 | 736 | path_out = *pv_p; | ||
4611 | 737 | delete pv_p; | ||
4612 | 738 | |||
4613 | 739 | } else if (linejoin_type == LINEJOIN_REFLECTED) { | ||
4614 | 740 | // reflected arc join | ||
4615 | 741 | path_out = outlinePath(path_in, line_width, static_cast<LineJoinType>(linejoin_type), | ||
4616 | 742 | linecap_type , miter_lim, false, start_lean, end_lean); | ||
4617 | 743 | |||
4618 | 744 | } else if (linejoin_type == LINEJOIN_EXTRAPOLATED) { | ||
4619 | 745 | // extrapolated arc join | ||
4620 | 746 | path_out = outlinePath(path_in, line_width, LINEJOIN_STRAIGHT, linecap_type, miter_lim, true, start_lean, end_lean); | ||
4621 | 747 | } | ||
4622 | 748 | |||
4623 | 749 | #undef miter_lim | ||
4624 | 750 | return path_out; | ||
4625 | 751 | } | ||
4626 | 752 | |||
4627 | 753 | Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit) | ||
4628 | 754 | { | ||
4629 | 755 | |||
4630 | 756 | #define miter_lim fabs(line_width * miter_limit) | ||
4631 | 757 | |||
4632 | 758 | Geom::Path path_out; | ||
4633 | 759 | |||
4634 | 760 | if (linejoin_type <= LINEJOIN_POINTY || path_in.size() <= 1) { | ||
4635 | 761 | |||
4636 | 762 | Geom::PathVector * pathvec; | ||
4637 | 763 | |||
4638 | 764 | Path path_tangent = Path(); | ||
4639 | 765 | Path path_outline = Path(); | ||
4640 | 766 | path_outline.LoadPath(path_in, Geom::Affine(), false, false); | ||
4641 | 767 | path_outline.OutsideOutline(&path_tangent, line_width / 2, static_cast<join_typ>(linejoin_type), butt_straight, miter_lim); | ||
4642 | 768 | |||
4643 | 769 | pathvec = path_tangent.MakePathVector(); | ||
4644 | 770 | path_out = pathvec->front(); | ||
4645 | 771 | delete pathvec; | ||
4646 | 772 | return path_out; | ||
4647 | 773 | } else if (linejoin_type == LINEJOIN_REFLECTED) { | ||
4648 | 774 | path_out = outlineHalf(path_in, line_width, miter_lim, reflect_curves); | ||
4649 | 775 | return path_out; | ||
4650 | 776 | } else if (linejoin_type == LINEJOIN_EXTRAPOLATED) { | ||
4651 | 777 | path_out = outlineHalf(path_in, line_width, miter_lim, extrapolate_curves); | ||
4652 | 778 | return path_out; | ||
4653 | 779 | } | ||
4654 | 780 | #undef miter_lim | ||
4655 | 781 | return path_out; | ||
4656 | 782 | } | ||
4657 | 783 | |||
4658 | 784 | } // namespace Outline | ||
4659 | 785 | |||
4660 | 786 | /* | ||
4661 | 787 | Local Variables: | ||
4662 | 788 | mode:c++ | ||
4663 | 789 | c-file-style:"stroustrup" | ||
4664 | 790 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
4665 | 791 | indent-tabs-mode:nil | ||
4666 | 792 | fill-column:99 | ||
4667 | 793 | End: | ||
4668 | 794 | */ | ||
4669 | 795 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8 : | ||
4670 | 0 | 796 | ||
4671 | === added file 'src/live_effects/pathoutlineprovider.h' | |||
4672 | --- src/live_effects/pathoutlineprovider.h 1970-01-01 00:00:00 +0000 | |||
4673 | +++ src/live_effects/pathoutlineprovider.h 2014-09-07 17:02:32 +0000 | |||
4674 | @@ -0,0 +1,55 @@ | |||
4675 | 1 | #ifndef SEEN_PATH_OUTLINE_H | ||
4676 | 2 | #define SEEN_PATH_OUTLINE_H | ||
4677 | 3 | |||
4678 | 4 | /* Author: | ||
4679 | 5 | * Liam P. White <inkscapebrony@gmail.com> | ||
4680 | 6 | * | ||
4681 | 7 | * Copyright (C) 2014 Author | ||
4682 | 8 | * | ||
4683 | 9 | * Released under GNU GPL, read the file 'COPYING' for more information | ||
4684 | 10 | */ | ||
4685 | 11 | |||
4686 | 12 | #include <livarot/Path.h> | ||
4687 | 13 | #include <livarot/LivarotDefs.h> | ||
4688 | 14 | |||
4689 | 15 | enum LineJoinType { | ||
4690 | 16 | LINEJOIN_STRAIGHT, | ||
4691 | 17 | LINEJOIN_ROUND, | ||
4692 | 18 | LINEJOIN_POINTY, | ||
4693 | 19 | LINEJOIN_REFLECTED, | ||
4694 | 20 | LINEJOIN_EXTRAPOLATED | ||
4695 | 21 | }; | ||
4696 | 22 | enum ButtTypeMod { | ||
4697 | 23 | BUTT_STRAIGHT, | ||
4698 | 24 | BUTT_ROUND, | ||
4699 | 25 | BUTT_SQUARE, | ||
4700 | 26 | BUTT_POINTY, | ||
4701 | 27 | BUTT_LEANED | ||
4702 | 28 | }; | ||
4703 | 29 | |||
4704 | 30 | namespace Geom | ||
4705 | 31 | { | ||
4706 | 32 | Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2<Geom::SBasis> const & sbasis_in); | ||
4707 | 33 | std::vector<Geom::Path> split_at_cusps(const Geom::Path& in); | ||
4708 | 34 | } | ||
4709 | 35 | |||
4710 | 36 | namespace Outline | ||
4711 | 37 | { | ||
4712 | 38 | unsigned bezierOrder (const Geom::Curve* curve_in); | ||
4713 | 39 | std::vector<Geom::Path> PathVectorOutline(std::vector<Geom::Path> const & path_in, double line_width, ButtTypeMod linecap_type, | ||
4714 | 40 | LineJoinType linejoin_type, double miter_limit, double start_lean = 0, double end_lean = 0); | ||
4715 | 41 | Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit); | ||
4716 | 42 | } | ||
4717 | 43 | |||
4718 | 44 | #endif // SEEN_PATH_OUTLINE_H | ||
4719 | 45 | |||
4720 | 46 | /* | ||
4721 | 47 | Local Variables: | ||
4722 | 48 | mode:c++ | ||
4723 | 49 | c-file-style:"stroustrup" | ||
4724 | 50 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
4725 | 51 | indent-tabs-mode:nil | ||
4726 | 52 | fill-column:99 | ||
4727 | 53 | End: | ||
4728 | 54 | */ | ||
4729 | 55 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : | ||
4730 | 0 | 56 | ||
4731 | === modified file 'src/menus-skeleton.h' | |||
4732 | --- src/menus-skeleton.h 2014-03-30 22:08:13 +0000 | |||
4733 | +++ src/menus-skeleton.h 2014-09-07 17:02:32 +0000 | |||
4734 | @@ -178,6 +178,9 @@ | |||
4735 | 178 | " <verb verb-id=\"DialogLayers\" />\n" | 178 | " <verb verb-id=\"DialogLayers\" />\n" |
4736 | 179 | " </submenu>\n" | 179 | " </submenu>\n" |
4737 | 180 | " <submenu name=\"" N_("_Object") "\">\n" | 180 | " <submenu name=\"" N_("_Object") "\">\n" |
4738 | 181 | " <verb verb-id=\"DialogObjects\" />\n" | ||
4739 | 182 | " <verb verb-id=\"DialogTags\" />\n" | ||
4740 | 183 | " <separator/>\n" | ||
4741 | 181 | " <verb verb-id=\"DialogFillStroke\" />\n" | 184 | " <verb verb-id=\"DialogFillStroke\" />\n" |
4742 | 182 | " <verb verb-id=\"DialogObjectProperties\" />\n" | 185 | " <verb verb-id=\"DialogObjectProperties\" />\n" |
4743 | 183 | " <verb verb-id=\"DialogSymbols\" />\n" | 186 | " <verb verb-id=\"DialogSymbols\" />\n" |
4744 | 184 | 187 | ||
4745 | === modified file 'src/path-chemistry.cpp' | |||
4746 | --- src/path-chemistry.cpp 2014-03-27 01:33:44 +0000 | |||
4747 | +++ src/path-chemistry.cpp 2014-09-07 17:02:32 +0000 | |||
4748 | @@ -22,6 +22,7 @@ | |||
4749 | 22 | #include "xml/repr.h" | 22 | #include "xml/repr.h" |
4750 | 23 | #include "svg/svg.h" | 23 | #include "svg/svg.h" |
4751 | 24 | #include "display/curve.h" | 24 | #include "display/curve.h" |
4752 | 25 | #include "color.h" | ||
4753 | 25 | #include <glib.h> | 26 | #include <glib.h> |
4754 | 26 | #include <glibmm/i18n.h> | 27 | #include <glibmm/i18n.h> |
4755 | 27 | #include "sp-path.h" | 28 | #include "sp-path.h" |
4756 | @@ -433,6 +434,10 @@ | |||
4757 | 433 | gchar *title = item->title(); | 434 | gchar *title = item->title(); |
4758 | 434 | // remember description | 435 | // remember description |
4759 | 435 | gchar *desc = item->desc(); | 436 | gchar *desc = item->desc(); |
4760 | 437 | // remember highlight color | ||
4761 | 438 | guint32 highlight_color = 0; | ||
4762 | 439 | if (item->isHighlightSet()) | ||
4763 | 440 | highlight_color = item->highlight_color(); | ||
4764 | 436 | 441 | ||
4765 | 437 | // It's going to resurrect, so we delete without notifying listeners. | 442 | // It's going to resurrect, so we delete without notifying listeners. |
4766 | 438 | item->deleteObject(false); | 443 | item->deleteObject(false); |
4767 | @@ -450,6 +455,9 @@ | |||
4768 | 450 | newObj->setDesc(desc); | 455 | newObj->setDesc(desc); |
4769 | 451 | g_free(desc); | 456 | g_free(desc); |
4770 | 452 | } | 457 | } |
4771 | 458 | if (highlight_color && newObj) { | ||
4772 | 459 | SP_ITEM(newObj)->setHighlightColor( highlight_color ); | ||
4773 | 460 | } | ||
4774 | 453 | 461 | ||
4775 | 454 | // move to the saved position | 462 | // move to the saved position |
4776 | 455 | repr->setPosition(pos > 0 ? pos : 0); | 463 | repr->setPosition(pos > 0 ? pos : 0); |
4777 | 456 | 464 | ||
4778 | === modified file 'src/selection-chemistry.cpp' | |||
4779 | --- src/selection-chemistry.cpp 2014-08-17 14:46:20 +0000 | |||
4780 | +++ src/selection-chemistry.cpp 2014-09-07 17:02:32 +0000 | |||
4781 | @@ -2792,54 +2792,53 @@ | |||
4782 | 2792 | if (desktop == NULL) { | 2792 | if (desktop == NULL) { |
4783 | 2793 | return; | 2793 | return; |
4784 | 2794 | } | 2794 | } |
4833 | 2795 | 2795 | ||
4834 | 2796 | Inkscape::Selection *selection = sp_desktop_selection(desktop); | 2796 | Inkscape::SVGOStringStream os; |
4835 | 2797 | SPItem *item = selection->singleItem(); | 2797 | SPObject * firstItem = NULL; |
4836 | 2798 | if (g_slist_length(const_cast<GSList *>(selection->itemList())) != 1 || !item) { | 2798 | for (const GSList * item = desktop->selection->itemList(); item != NULL; item = item->next) { |
4837 | 2799 | desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>one</b> path to clone.")); | 2799 | if (SP_IS_SHAPE(item->data) || SP_IS_TEXT(item->data)) { |
4838 | 2800 | return; | 2800 | if (firstItem) { |
4839 | 2801 | } | 2801 | os << "|"; |
4840 | 2802 | if ( !(SP_IS_SHAPE(item) || SP_IS_TEXT(item)) ) { | 2802 | } else { |
4841 | 2803 | desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select one <b>path</b> to clone.")); | 2803 | firstItem = SP_ITEM(item->data); |
4842 | 2804 | return; | 2804 | } |
4843 | 2805 | } | 2805 | os << "#" << SP_ITEM(item->data)->getId() << ",0"; |
4844 | 2806 | 2806 | } | |
4845 | 2807 | Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); | 2807 | } |
4846 | 2808 | Inkscape::XML::Node *parent = item->getRepr()->parent(); | 2808 | if (firstItem) { |
4847 | 2809 | 2809 | Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); | |
4848 | 2810 | // create the LPE | 2810 | SPObject *parent = firstItem->parent; |
4849 | 2811 | Inkscape::XML::Node *lpe_repr = xml_doc->createElement("inkscape:path-effect"); | 2811 | |
4850 | 2812 | { | 2812 | // create the LPE |
4851 | 2813 | lpe_repr->setAttribute("effect", "clone_original"); | 2813 | Inkscape::XML::Node *lpe_repr = xml_doc->createElement("inkscape:path-effect"); |
4852 | 2814 | gchar *href = g_strdup_printf("#%s", item->getRepr()->attribute("id")); | 2814 | { |
4853 | 2815 | lpe_repr->setAttribute("linkedpath", href); | 2815 | lpe_repr->setAttribute("effect", "fill_between_many"); |
4854 | 2816 | g_free(href); | 2816 | lpe_repr->setAttribute("linkedpaths", os.str().c_str()); |
4855 | 2817 | desktop->doc()->getDefs()->getRepr()->addChild(lpe_repr, NULL); // adds to <defs> and assigns the 'id' attribute | 2817 | desktop->doc()->getDefs()->getRepr()->addChild(lpe_repr, NULL); // adds to <defs> and assigns the 'id' attribute |
4856 | 2818 | } | 2818 | } |
4857 | 2819 | const gchar * lpe_id = lpe_repr->attribute("id"); | 2819 | const gchar * lpe_id = lpe_repr->attribute("id"); |
4858 | 2820 | Inkscape::GC::release(lpe_repr); | 2820 | Inkscape::GC::release(lpe_repr); |
4859 | 2821 | 2821 | ||
4860 | 2822 | // create the new path | 2822 | // create the new path |
4861 | 2823 | Inkscape::XML::Node *clone = xml_doc->createElement("svg:path"); | 2823 | Inkscape::XML::Node *clone = xml_doc->createElement("svg:path"); |
4862 | 2824 | { | 2824 | { |
4863 | 2825 | clone->setAttribute("d", "M 0 0", false); | 2825 | clone->setAttribute("d", "M 0 0", false); |
4864 | 2826 | // add the new clone to the top of the original's parent | 2826 | // add the new clone to the top of the original's parent |
4865 | 2827 | parent->appendChild(clone); | 2827 | parent->appendChildRepr(clone); |
4866 | 2828 | SPObject *clone_obj = desktop->doc()->getObjectById(clone->attribute("id")); | 2828 | SPObject *clone_obj = desktop->doc()->getObjectById(clone->attribute("id")); |
4867 | 2829 | if (SP_IS_LPE_ITEM(clone_obj)) { | 2829 | if (SP_IS_LPE_ITEM(clone_obj)) { |
4868 | 2830 | gchar *href = g_strdup_printf("#%s", lpe_id); | 2830 | gchar *href = g_strdup_printf("#%s", lpe_id); |
4869 | 2831 | SP_LPE_ITEM(clone_obj)->addPathEffect( href, false ); | 2831 | //sp_lpe_item_add_path_effect( SP_LPE_ITEM(clone_obj), href, false ); |
4870 | 2832 | g_free(href); | 2832 | SP_LPE_ITEM(clone_obj)->addPathEffect(href, false); |
4871 | 2833 | } | 2833 | g_free(href); |
4872 | 2834 | } | 2834 | } |
4873 | 2835 | 2835 | } | |
4874 | 2836 | DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_EDIT_CLONE_ORIGINAL_PATH_LPE, | 2836 | |
4875 | 2837 | _("Clone original path")); | 2837 | DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_EDIT_CLONE_ORIGINAL_PATH_LPE, |
4876 | 2838 | 2838 | _("Fill between strokes")); | |
4877 | 2839 | // select the new object: | 2839 | } else { |
4878 | 2840 | selection->set(clone); | 2840 | desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select path(s) to fill.")); |
4879 | 2841 | 2841 | } | |
4832 | 2842 | Inkscape::GC::release(clone); | ||
4880 | 2843 | } | 2842 | } |
4881 | 2844 | 2843 | ||
4882 | 2845 | void sp_selection_to_marker(SPDesktop *desktop, bool apply) | 2844 | void sp_selection_to_marker(SPDesktop *desktop, bool apply) |
4883 | @@ -3663,6 +3662,118 @@ | |||
4884 | 3663 | g_free(filepath); | 3662 | g_free(filepath); |
4885 | 3664 | } | 3663 | } |
4886 | 3665 | 3664 | ||
4887 | 3665 | /* Creates a mask or clipPath from selection. | ||
4888 | 3666 | * What is a clip group? | ||
4889 | 3667 | * A clip group is a tangled mess of XML that allows an object inside a group | ||
4890 | 3668 | * to clip the entire group using a few <use>s and generally irritating me. | ||
4891 | 3669 | */ | ||
4892 | 3670 | |||
4893 | 3671 | void sp_selection_set_clipgroup(SPDesktop *desktop) | ||
4894 | 3672 | { | ||
4895 | 3673 | if (desktop == NULL) { | ||
4896 | 3674 | return; | ||
4897 | 3675 | } | ||
4898 | 3676 | SPDocument* doc = sp_desktop_document(desktop); | ||
4899 | 3677 | Inkscape::XML::Document *xml_doc = doc->getReprDoc(); | ||
4900 | 3678 | |||
4901 | 3679 | Inkscape::Selection *selection = sp_desktop_selection(desktop); | ||
4902 | 3680 | if (selection->isEmpty()) { | ||
4903 | 3681 | desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to create clippath or mask from.")); | ||
4904 | 3682 | return; | ||
4905 | 3683 | } | ||
4906 | 3684 | |||
4907 | 3685 | GSList const *l = const_cast<GSList *>(selection->reprList()); | ||
4908 | 3686 | |||
4909 | 3687 | GSList *p = g_slist_copy(const_cast<GSList *>(l)); | ||
4910 | 3688 | |||
4911 | 3689 | p = g_slist_sort(p, (GCompareFunc) sp_repr_compare_position); | ||
4912 | 3690 | |||
4913 | 3691 | selection->clear(); | ||
4914 | 3692 | |||
4915 | 3693 | gint topmost = (static_cast<Inkscape::XML::Node *>(g_slist_last(p)->data))->position(); | ||
4916 | 3694 | Inkscape::XML::Node *topmost_parent = (static_cast<Inkscape::XML::Node *>(g_slist_last(p)->data))->parent(); | ||
4917 | 3695 | |||
4918 | 3696 | Inkscape::XML::Node *inner = xml_doc->createElement("svg:g"); | ||
4919 | 3697 | inner->setAttribute("inkscape:label", "Clip"); | ||
4920 | 3698 | |||
4921 | 3699 | while (p) { | ||
4922 | 3700 | Inkscape::XML::Node *current = static_cast<Inkscape::XML::Node *>(p->data); | ||
4923 | 3701 | |||
4924 | 3702 | if (current->parent() == topmost_parent) { | ||
4925 | 3703 | Inkscape::XML::Node *spnew = current->duplicate(xml_doc); | ||
4926 | 3704 | sp_repr_unparent(current); | ||
4927 | 3705 | inner->appendChild(spnew); | ||
4928 | 3706 | Inkscape::GC::release(spnew); | ||
4929 | 3707 | topmost --; // only reduce count for those items deleted from topmost_parent | ||
4930 | 3708 | } else { // move it to topmost_parent first | ||
4931 | 3709 | GSList *temp_clip = NULL; | ||
4932 | 3710 | |||
4933 | 3711 | // At this point, current may already have no item, due to its being a clone whose original is already moved away | ||
4934 | 3712 | // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform | ||
4935 | 3713 | gchar const *t_str = current->attribute("transform"); | ||
4936 | 3714 | Geom::Affine item_t(Geom::identity()); | ||
4937 | 3715 | if (t_str) | ||
4938 | 3716 | sp_svg_transform_read(t_str, &item_t); | ||
4939 | 3717 | item_t *= SP_ITEM(doc->getObjectByRepr(current->parent()))->i2doc_affine(); | ||
4940 | 3718 | // FIXME: when moving both clone and original from a transformed group (either by | ||
4941 | 3719 | // grouping into another parent, or by cut/paste) the transform from the original's | ||
4942 | 3720 | // parent becomes embedded into original itself, and this affects its clones. Fix | ||
4943 | 3721 | // this by remembering the transform diffs we write to each item into an array and | ||
4944 | 3722 | // then, if this is clone, looking up its original in that array and pre-multiplying | ||
4945 | 3723 | // it by the inverse of that original's transform diff. | ||
4946 | 3724 | |||
4947 | 3725 | sp_selection_copy_one(current, item_t, &temp_clip, xml_doc); | ||
4948 | 3726 | sp_repr_unparent(current); | ||
4949 | 3727 | |||
4950 | 3728 | // paste into topmost_parent (temporarily) | ||
4951 | 3729 | GSList *copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), &temp_clip); | ||
4952 | 3730 | if (temp_clip) g_slist_free(temp_clip); | ||
4953 | 3731 | if (copied) { // if success, | ||
4954 | 3732 | // take pasted object (now in topmost_parent) | ||
4955 | 3733 | Inkscape::XML::Node *in_topmost = static_cast<Inkscape::XML::Node *>(copied->data); | ||
4956 | 3734 | // make a copy | ||
4957 | 3735 | Inkscape::XML::Node *spnew = in_topmost->duplicate(xml_doc); | ||
4958 | 3736 | // remove pasted | ||
4959 | 3737 | sp_repr_unparent(in_topmost); | ||
4960 | 3738 | // put its copy into group | ||
4961 | 3739 | inner->appendChild(spnew); | ||
4962 | 3740 | Inkscape::GC::release(spnew); | ||
4963 | 3741 | g_slist_free(copied); | ||
4964 | 3742 | } | ||
4965 | 3743 | } | ||
4966 | 3744 | p = g_slist_remove(p, current); | ||
4967 | 3745 | } | ||
4968 | 3746 | |||
4969 | 3747 | Inkscape::XML::Node *outer = xml_doc->createElement("svg:g"); | ||
4970 | 3748 | outer->appendChild(inner); | ||
4971 | 3749 | topmost_parent->appendChild(outer); | ||
4972 | 3750 | outer->setPosition(topmost + 1); | ||
4973 | 3751 | |||
4974 | 3752 | Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); | ||
4975 | 3753 | clone->setAttribute("x", "0", false); | ||
4976 | 3754 | clone->setAttribute("y", "0", false); | ||
4977 | 3755 | clone->setAttribute("xlink:href", g_strdup_printf("#%s", inner->attribute("id")), false); | ||
4978 | 3756 | |||
4979 | 3757 | clone->setAttribute("inkscape:transform-center-x", inner->attribute("inkscape:transform-center-x"), false); | ||
4980 | 3758 | clone->setAttribute("inkscape:transform-center-y", inner->attribute("inkscape:transform-center-y"), false); | ||
4981 | 3759 | |||
4982 | 3760 | const Geom::Affine maskTransform(Geom::Affine::identity()); | ||
4983 | 3761 | GSList *templist = NULL; | ||
4984 | 3762 | |||
4985 | 3763 | templist = g_slist_append(templist, clone); | ||
4986 | 3764 | // add the new clone to the top of the original's parent | ||
4987 | 3765 | gchar const *mask_id = SPClipPath::create(templist, doc, &maskTransform); | ||
4988 | 3766 | |||
4989 | 3767 | g_slist_free(templist); | ||
4990 | 3768 | |||
4991 | 3769 | outer->setAttribute("clip-path", g_strdup_printf("url(#%s)", mask_id)); | ||
4992 | 3770 | |||
4993 | 3771 | Inkscape::GC::release(clone); | ||
4994 | 3772 | |||
4995 | 3773 | selection->set(outer); | ||
4996 | 3774 | DocumentUndo::done(doc, SP_VERB_OBJECT_SET_CLIPPATH, _("Create Clip Group")); | ||
4997 | 3775 | } | ||
4998 | 3776 | |||
4999 | 3666 | /** | 3777 | /** |
5000 | 3667 | * Creates a mask or clipPath from selection. | 3778 | * Creates a mask or clipPath from selection. |
The diff has been truncated for viewing.
I've passed along a few clean up points over irc and I can't spot anything really bad. So I'm going ahead with a merge.