Merge lp:~inkscape.dev/inkscape/copy-rotate-lpe-improvements into lp:~inkscape.dev/inkscape/trunk
- copy-rotate-lpe-improvements
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Jabiertxof |
Approved revision: | 13750 |
Merged at revision: | 14720 |
Proposed branch: | lp:~inkscape.dev/inkscape/copy-rotate-lpe-improvements |
Merge into: | lp:~inkscape.dev/inkscape/trunk |
Diff against target: |
500 lines (+313/-43) 3 files modified
src/live_effects/effect.cpp (+1/-1) src/live_effects/lpe-copy_rotate.cpp (+304/-30) src/live_effects/lpe-copy_rotate.h (+8/-12) |
To merge this branch: | bzr merge lp:~inkscape.dev/inkscape/copy-rotate-lpe-improvements |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Krzysztof Kosinski | Approve | ||
Martin Owens | Approve | ||
Jabiertxof | Pending | ||
Review via email: mp+247530@code.launchpad.net |
Commit message
Description of the change
Add Kaleidoscope Feature to Copy-Rotate LPE.
Here are videos working:
https:/
https:/
- 13726. By Jabiertxof <email address hidden>
-
update to trunk
- 13727. By Jabiertxof <email address hidden>
-
update to trunk
- 13728. By Jabiertxof <email address hidden>
-
adding rotation transform
- 13729. By Jabiertxof <email address hidden>
-
update to trunk
- 13730. By Jabiertxof <email address hidden>
-
Allow rotate copies whithout distorsion in kaleidoscope shapes
- 13731. By Jabiertxof <email address hidden>
-
update to trunk
- 13732. By Jabiertxof <email address hidden>
-
update to trunk
- 13733. By Jabiertxof <email address hidden>
-
astyle copy-rotate LPE
- 13734. By Jabiertxof <email address hidden>
-
Rename some variables to fit coding style
- 13735. By Jabiertxof <email address hidden>
-
update to trunk
- 13736. By Jabiertxof <email address hidden>
-
opening kaleidscope
- 13737. By Jabiertxof <email address hidden>
-
update to trunk
- 13738. By Jabiertxof <email address hidden>
-
opening kaleidscope
- 13739. By Jabiertxof <email address hidden>
-
update to trunk
- 13740. By Jabiertxof <email address hidden>
-
opening kaleidscope
- 13741. By Jabiertxof <email address hidden>
-
opening kaleidscope
- 13742. By Jabiertxof <email address hidden>
-
Change from kaleidoscope to multiangle fusion
- 13743. By Jabiertxof <email address hidden>
-
update to trunk
- 13744. By Jabiertxof <email address hidden>
-
fix minor bug
- 13745. By Jabiertxof <email address hidden>
-
update to trunk
- 13746. By Jabiertxof <email address hidden>
-
fixes for update to trunk
- 13747. By Jabiertxof <email address hidden>
-
update to trunk
- 13748. By Jabiertxof <email address hidden>
-
update to trunk
- 13749. By Jabiertxof <email address hidden>
-
Fix order LPE
- 13750. By Jabiertxof <email address hidden>
-
Fix compiling bugs
Krzysztof Kosinski (tweenk) wrote : | # |
Approve after these fixes.
Jabiertxof (jabiertxof) wrote : | # |
Thanks very much @Krzysztof for the review. I hope I can merge tonight.
Jabiertxof (jabiertxof) wrote : | # |
Thanks Martin!
- 13751. By Jabiertxof <email address hidden>
-
Fix Krzysztof comments on merge proposal
- 13752. By Jabiertxof <email address hidden>
-
Fix more Krzysztof comments on merge proposal, temporary disable LPE on clip and paths
- 13753. By Jabiertxof <email address hidden>
-
update to trunk
- 13754. By Jabiertxof <email address hidden>
-
update to trunk
Marcel Partap (empee584) wrote : | # |
Very nice stuff ๐
Now by the way, let's get inspired by https:/
Jabiertxof (jabiertxof) wrote : | # |
Thanks Marcel!
Preview Diff
1 | === modified file 'src/live_effects/effect.cpp' |
2 | --- src/live_effects/effect.cpp 2016-03-19 11:17:59 +0000 |
3 | +++ src/live_effects/effect.cpp 2016-03-19 11:19:31 +0000 |
4 | @@ -110,7 +110,6 @@ |
5 | {PATH_LENGTH, N_("Path length"), "path_length"}, |
6 | {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"}, |
7 | {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"}, |
8 | - {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, |
9 | {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, |
10 | {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, |
11 | {TEXT_LABEL, N_("Text label"), "text_label"}, |
12 | @@ -145,6 +144,7 @@ |
13 | {BSPLINE, N_("BSpline"), "bspline"}, |
14 | {JOIN_TYPE, N_("Join type"), "join_type"}, |
15 | {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, |
16 | + {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, |
17 | /* Ponyscape -> Inkscape 0.92*/ |
18 | {ATTACH_PATH, N_("Attach path"), "attach_path"}, |
19 | {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, |
20 | |
21 | === modified file 'src/live_effects/lpe-copy_rotate.cpp' |
22 | --- src/live_effects/lpe-copy_rotate.cpp 2016-03-02 19:34:31 +0000 |
23 | +++ src/live_effects/lpe-copy_rotate.cpp 2016-03-19 11:19:31 +0000 |
24 | @@ -5,7 +5,7 @@ |
25 | * Authors: |
26 | * Maximilian Albert <maximilian.albert@gmail.com> |
27 | * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl> |
28 | - * |
29 | + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> |
30 | * Copyright (C) Authors 2007-2012 |
31 | * |
32 | * Released under GNU GPL, read the file 'COPYING' for more information |
33 | @@ -13,7 +13,8 @@ |
34 | |
35 | #include <glibmm/i18n.h> |
36 | #include <gdk/gdk.h> |
37 | - |
38 | +#include <2geom/path-intersection.h> |
39 | +#include <2geom/sbasis-to-bezier.h> |
40 | #include "live_effects/lpe-copy_rotate.h" |
41 | #include <2geom/path.h> |
42 | #include <2geom/transforms.h> |
43 | @@ -41,22 +42,39 @@ |
44 | virtual Geom::Point knot_get() const; |
45 | }; |
46 | |
47 | -class KnotHolderEntityOrigin : public LPEKnotHolderEntity { |
48 | -public: |
49 | - KnotHolderEntityOrigin(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {}; |
50 | - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); |
51 | - virtual Geom::Point knot_get() const; |
52 | -}; |
53 | - |
54 | } // namespace CR |
55 | |
56 | +int |
57 | +pointSideOfLine(Geom::Point const &A, Geom::Point const &B, Geom::Point const &X) |
58 | +{ |
59 | + //http://stackoverflow.com/questions/1560492/how-to-tell-whether-a-point-is-to-the-right-or-left-side-of-a-line |
60 | + double pos = (B[Geom::X]-A[Geom::X])*(X[Geom::Y]-A[Geom::Y]) - (B[Geom::Y]-A[Geom::Y])*(X[Geom::X]-A[Geom::X]); |
61 | + return (pos < 0) ? -1 : (pos > 0); |
62 | +} |
63 | + |
64 | +bool |
65 | +pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) |
66 | +{ |
67 | + //http://totologic.blogspot.com.es/2014/01/accurate-point-in-triangle-test.html |
68 | + using Geom::X; |
69 | + using Geom::Y; |
70 | + double denominator = (p1[X]*(p2[Y] - p3[Y]) + p1[Y]*(p3[X] - p2[X]) + p2[X]*p3[Y] - p2[Y]*p3[X]); |
71 | + double t1 = (p[X]*(p3[Y] - p1[Y]) + p[Y]*(p1[X] - p3[X]) - p1[X]*p3[Y] + p1[Y]*p3[X]) / denominator; |
72 | + double t2 = (p[X]*(p2[Y] - p1[Y]) + p[Y]*(p1[X] - p2[X]) - p1[X]*p2[Y] + p1[Y]*p2[X]) / -denominator; |
73 | + double s = t1 + t2; |
74 | + |
75 | + return 0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1 && s <= 1; |
76 | +} |
77 | + |
78 | + |
79 | LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : |
80 | Effect(lpeobject), |
81 | origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"), |
82 | starting_angle(_("Starting:"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0), |
83 | rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 30.0), |
84 | num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 5), |
85 | - copiesTo360(_("360ยบ Copies"), _("No rotation angle, fixed to 360ยบ"), "copiesTo360", &wr, this, true), |
86 | + copies_to_360(_("360ยบ Copies"), _("No rotation angle, fixed to 360ยบ"), "copies_to_360", &wr, this, true), |
87 | + fuse_paths(_("Fuse paths"), _("Fuse paths by helper line"), "fuse_paths", &wr, this, false), |
88 | dist_angle_handle(100.0) |
89 | { |
90 | show_orig_path = true; |
91 | @@ -64,12 +82,13 @@ |
92 | apply_to_clippath_and_mask = true; |
93 | |
94 | // register all your parameters here, so Inkscape knows which parameters this effect has: |
95 | - registerParameter(&copiesTo360); |
96 | + registerParameter(&copies_to_360); |
97 | + registerParameter(&fuse_paths); |
98 | registerParameter(&starting_angle); |
99 | registerParameter(&rotation_angle); |
100 | registerParameter(&num_copies); |
101 | registerParameter(&origin); |
102 | - |
103 | + |
104 | num_copies.param_make_integer(true); |
105 | num_copies.param_set_range(0, 1000); |
106 | } |
107 | @@ -93,15 +112,45 @@ |
108 | dir = unit_vector(B - A); |
109 | } |
110 | |
111 | +void |
112 | +LPECopyRotate::transform_multiply(Geom::Affine const& postmul, bool set) |
113 | +{ |
114 | + if(fuse_paths) { |
115 | + Geom::Coord angle = Geom::deg_from_rad(atan(-postmul[1]/postmul[0])); |
116 | + angle += starting_angle; |
117 | + starting_angle.param_set_value(angle); |
118 | + } |
119 | + // cycle through all parameters. Most parameters will not need transformation, but path and point params do. |
120 | + |
121 | + for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) { |
122 | + Parameter * param = *it; |
123 | + param->param_transform_multiply(postmul, set); |
124 | + } |
125 | +} |
126 | |
127 | void |
128 | LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) |
129 | { |
130 | using namespace Geom; |
131 | original_bbox(lpeitem); |
132 | - if(copiesTo360 ){ |
133 | + if (copies_to_360) { |
134 | rotation_angle.param_set_value(360.0/(double)num_copies); |
135 | - } |
136 | + } |
137 | + if (fuse_paths && rotation_angle * num_copies > 360 && rotation_angle > 0) { |
138 | + num_copies.param_set_value(floor(360/rotation_angle)); |
139 | + } |
140 | + if (fuse_paths && copies_to_360) { |
141 | + num_copies.param_set_increments(2,2); |
142 | + if ((int)num_copies%2 !=0) { |
143 | + num_copies.param_set_value(num_copies+1); |
144 | + } |
145 | + } else { |
146 | + num_copies.param_set_increments(1,1); |
147 | + } |
148 | + |
149 | + if (dist_angle_handle < 1.0) { |
150 | + dist_angle_handle = 1.0; |
151 | + } |
152 | A = Point(boundingbox_X.min(), boundingbox_Y.middle()); |
153 | B = Point(boundingbox_X.middle(), boundingbox_Y.middle()); |
154 | dir = unit_vector(B - A); |
155 | @@ -109,27 +158,251 @@ |
156 | // likely due to SVG's choice of coordinate system orientation (max) |
157 | start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle; |
158 | rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle; |
159 | - if(copiesTo360 ){ |
160 | + if ( fuse_paths || copies_to_360 ) { |
161 | rot_pos = origin; |
162 | } |
163 | -} |
164 | - |
165 | + SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); |
166 | + item->apply_to_clippath(item); |
167 | + item->apply_to_mask(item); |
168 | +} |
169 | + |
170 | +void |
171 | +LPECopyRotate::split(Geom::PathVector &path_on, Geom::Path const ÷r) |
172 | +{ |
173 | + Geom::PathVector tmp_path; |
174 | + double time_start = 0.0; |
175 | + Geom::Path original = path_on[0]; |
176 | + int position = 0; |
177 | + Geom::Crossings cs = crossings(original,divider); |
178 | + std::vector<double> crossed; |
179 | + for(unsigned int i = 0; i < cs.size(); i++) { |
180 | + crossed.push_back(cs[i].ta); |
181 | + } |
182 | + std::sort(crossed.begin(), crossed.end()); |
183 | + for (unsigned int i = 0; i < crossed.size(); i++) { |
184 | + double time_end = crossed[i]; |
185 | + Geom::Path portion_original = original.portion(time_start,time_end); |
186 | + if (!portion_original.empty()) { |
187 | + Geom::Point side_checker = portion_original.pointAt(0.001); |
188 | + position = pointSideOfLine(divider[0].finalPoint(), divider[1].finalPoint(), side_checker); |
189 | + if (rotation_angle != 180) { |
190 | + position = pointInTriangle(side_checker, divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint()); |
191 | + } |
192 | + if (position == 1) { |
193 | + tmp_path.push_back(portion_original); |
194 | + } |
195 | + portion_original.clear(); |
196 | + time_start = time_end; |
197 | + } |
198 | + } |
199 | + position = pointSideOfLine(divider[0].finalPoint(), divider[1].finalPoint(), original.finalPoint()); |
200 | + if (rotation_angle != 180) { |
201 | + position = pointInTriangle(original.finalPoint(), divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint()); |
202 | + } |
203 | + if (cs.size() > 0 && position == 1) { |
204 | + Geom::Path portion_original = original.portion(time_start, original.size()); |
205 | + if(!portion_original.empty()){ |
206 | + if (!original.closed()) { |
207 | + tmp_path.push_back(portion_original); |
208 | + } else { |
209 | + if (tmp_path.size() > 0 && tmp_path[0].size() > 0 ) { |
210 | + portion_original.setFinal(tmp_path[0].initialPoint()); |
211 | + portion_original.append(tmp_path[0]); |
212 | + tmp_path[0] = portion_original; |
213 | + } else { |
214 | + tmp_path.push_back(portion_original); |
215 | + } |
216 | + } |
217 | + portion_original.clear(); |
218 | + } |
219 | + } |
220 | + if (cs.size()==0 && position == 1) { |
221 | + tmp_path.push_back(original); |
222 | + } |
223 | + path_on = tmp_path; |
224 | +} |
225 | + |
226 | +void |
227 | +LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double size_divider) |
228 | +{ |
229 | + split(path_on,divider); |
230 | + Geom::PathVector tmp_path; |
231 | + Geom::Affine pre = Geom::Translate(-origin); |
232 | + for (Geom::PathVector::const_iterator path_it = path_on.begin(); path_it != path_on.end(); ++path_it) { |
233 | + Geom::Path original = *path_it; |
234 | + if (path_it->empty()) { |
235 | + continue; |
236 | + } |
237 | + Geom::PathVector tmp_path_helper; |
238 | + Geom::Path append_path = original; |
239 | + |
240 | + for (int i = 0; i < num_copies; ++i) { |
241 | + Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * (i))); |
242 | + Geom::Affine m = pre * rot * Geom::Translate(origin); |
243 | + if (i%2 != 0) { |
244 | + Geom::Point A = (Geom::Point)origin; |
245 | + Geom::Point B = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider; |
246 | + Geom::Affine m1(1.0, 0.0, 0.0, 1.0, A[0], A[1]); |
247 | + double hyp = Geom::distance(A, B); |
248 | + double c = (B[0] - A[0]) / hyp; // cos(alpha) |
249 | + double s = (B[1] - A[1]) / hyp; // sin(alpha) |
250 | + |
251 | + Geom::Affine m2(c, -s, s, c, 0.0, 0.0); |
252 | + Geom::Affine sca(1.0, 0.0, 0.0, -1.0, 0.0, 0.0); |
253 | + |
254 | + Geom::Affine tmp_m = m1.inverse() * m2; |
255 | + m = tmp_m; |
256 | + m = m * sca; |
257 | + m = m * m2.inverse(); |
258 | + m = m * m1; |
259 | + } else { |
260 | + append_path = original; |
261 | + } |
262 | + append_path *= m; |
263 | + if (tmp_path_helper.size() > 0) { |
264 | + if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.finalPoint())) { |
265 | + Geom::Path tmp_append = append_path.reversed(); |
266 | + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); |
267 | + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); |
268 | + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(), append_path.initialPoint())) { |
269 | + Geom::Path tmp_append = append_path; |
270 | + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed(); |
271 | + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); |
272 | + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); |
273 | + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed(); |
274 | + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.initialPoint())) { |
275 | + Geom::Path tmp_append = append_path; |
276 | + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); |
277 | + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); |
278 | + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(), append_path.finalPoint())) { |
279 | + Geom::Path tmp_append = append_path.reversed(); |
280 | + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed(); |
281 | + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); |
282 | + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); |
283 | + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed(); |
284 | + } else if (Geom::are_near(tmp_path_helper[0].finalPoint(), append_path.finalPoint())) { |
285 | + Geom::Path tmp_append = append_path.reversed(); |
286 | + tmp_append.setInitial(tmp_path_helper[0].finalPoint()); |
287 | + tmp_path_helper[0].append(tmp_append); |
288 | + } else if (Geom::are_near(tmp_path_helper[0].initialPoint(), append_path.initialPoint())) { |
289 | + Geom::Path tmp_append = append_path; |
290 | + tmp_path_helper[0] = tmp_path_helper[0].reversed(); |
291 | + tmp_append.setInitial(tmp_path_helper[0].finalPoint()); |
292 | + tmp_path_helper[0].append(tmp_append); |
293 | + tmp_path_helper[0] = tmp_path_helper[0].reversed(); |
294 | + } else { |
295 | + tmp_path_helper.push_back(append_path); |
296 | + } |
297 | + if ( Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),tmp_path_helper[tmp_path_helper.size()-1].initialPoint())) { |
298 | + tmp_path_helper[tmp_path_helper.size()-1].close(); |
299 | + } |
300 | + } else { |
301 | + tmp_path_helper.push_back(append_path); |
302 | + } |
303 | + } |
304 | + if (tmp_path_helper.size() > 0) { |
305 | + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1]; |
306 | + tmp_path_helper[0] = tmp_path_helper[0]; |
307 | + if (rotation_angle * num_copies != 360) { |
308 | + Geom::Ray base_a(divider.pointAt(1),divider.pointAt(0)); |
309 | + double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); |
310 | + Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); |
311 | + double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); |
312 | + Geom::Point base_point = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle * num_copies) + starting_angle)) * size_divider; |
313 | + Geom::Ray base_b(divider.pointAt(1), base_point); |
314 | + if (Geom::are_near(tmp_path_helper[0].initialPoint(),base_a) && |
315 | + Geom::are_near(tmp_path_helper[0].finalPoint(),base_a)) |
316 | + { |
317 | + tmp_path_helper[0].close(); |
318 | + if (tmp_path_helper.size() > 1) { |
319 | + tmp_path_helper[tmp_path_helper.size()-1].close(); |
320 | + } |
321 | + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(),base_b) && |
322 | + Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_b)) |
323 | + { |
324 | + tmp_path_helper[0].close(); |
325 | + if (tmp_path_helper.size() > 1) { |
326 | + tmp_path_helper[tmp_path_helper.size()-1].close(); |
327 | + } |
328 | + } else if ((Geom::are_near(tmp_path_helper[0].initialPoint(),base_a) && |
329 | + Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_b)) || |
330 | + (Geom::are_near(tmp_path_helper[0].initialPoint(),base_b) && |
331 | + Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_a))) |
332 | + { |
333 | + Geom::Path close_path = Geom::Path(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); |
334 | + close_path.appendNew<Geom::LineSegment>((Geom::Point)origin); |
335 | + close_path.appendNew<Geom::LineSegment>(tmp_path_helper[0].initialPoint()); |
336 | + tmp_path_helper[0].append(close_path); |
337 | + } |
338 | + } |
339 | + |
340 | + if (Geom::are_near(tmp_path_helper[0].finalPoint(),tmp_path_helper[0].initialPoint())) { |
341 | + tmp_path_helper[0].close(); |
342 | + } |
343 | + } |
344 | + tmp_path.insert(tmp_path.end(), tmp_path_helper.begin(), tmp_path_helper.end()); |
345 | + tmp_path_helper.clear(); |
346 | + } |
347 | + path_on = tmp_path; |
348 | + tmp_path.clear(); |
349 | +} |
350 | |
351 | Geom::Piecewise<Geom::D2<Geom::SBasis> > |
352 | LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) |
353 | { |
354 | using namespace Geom; |
355 | |
356 | - if(num_copies == 1){ |
357 | + if (num_copies == 1 && !fuse_paths) { |
358 | return pwd2_in; |
359 | } |
360 | |
361 | + double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); |
362 | + Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); |
363 | + double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); |
364 | + Geom::Point line_start = origin + dir * Rotate(-rad_from_deg(starting_angle)) * size_divider; |
365 | + Geom::Point line_end = origin + dir * Rotate(-rad_from_deg(rotation_angle + starting_angle)) * size_divider; |
366 | + //Note:: beter way to do this |
367 | + //Whith AppendNew have problems whith the crossing order |
368 | + Geom::Path divider = Geom::Path(line_start); |
369 | + divider.appendNew<Geom::LineSegment>((Geom::Point)origin); |
370 | + divider.appendNew<Geom::LineSegment>(line_end); |
371 | Piecewise<D2<SBasis> > output; |
372 | Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle)); |
373 | - for (int i = 0; i < num_copies; ++i) { |
374 | - Rotate rot(-rad_from_deg(rotation_angle * i)); |
375 | - Affine t = pre * rot * Translate(origin); |
376 | - output.concat(pwd2_in * t); |
377 | + if (fuse_paths) { |
378 | + Geom::PathVector path_out; |
379 | + Geom::PathVector tmp_path; |
380 | + PathVector const original_pathv = path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001); |
381 | + for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { |
382 | + if (path_it->empty()) { |
383 | + continue; |
384 | + } |
385 | + bool end_open = false; |
386 | + if (path_it->closed()) { |
387 | + const Geom::Curve &closingline = path_it->back_closed(); |
388 | + if (!are_near(closingline.initialPoint(), closingline.finalPoint())) { |
389 | + end_open = true; |
390 | + } |
391 | + } |
392 | + Geom::Path original = (Geom::Path)(*path_it); |
393 | + if (end_open && path_it->closed()) { |
394 | + original.close(false); |
395 | + original.appendNew<Geom::LineSegment>( original.initialPoint() ); |
396 | + original.close(true); |
397 | + } |
398 | + tmp_path.push_back(original); |
399 | + setFusion(tmp_path, divider, size_divider); |
400 | + path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end()); |
401 | + tmp_path.clear(); |
402 | + } |
403 | + if (path_out.size()>0) { |
404 | + output = paths_to_pw(path_out); |
405 | + } |
406 | + } else { |
407 | + for (int i = 0; i < num_copies; ++i) { |
408 | + Rotate rot(-rad_from_deg(rotation_angle * i)); |
409 | + Affine t = pre * rot * Translate(origin); |
410 | + output.concat(pwd2_in * t); |
411 | + } |
412 | } |
413 | return output; |
414 | } |
415 | @@ -148,8 +421,16 @@ |
416 | hp_vec.push_back(pathv); |
417 | } |
418 | |
419 | +void |
420 | +LPECopyRotate::resetDefaults(SPItem const* item) |
421 | +{ |
422 | + Effect::resetDefaults(item); |
423 | + original_bbox(SP_LPE_ITEM(item)); |
424 | +} |
425 | |
426 | -void LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { |
427 | +void |
428 | +LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) |
429 | +{ |
430 | { |
431 | KnotHolderEntity *e = new CR::KnotHolderEntityStartingAngle(this); |
432 | e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, |
433 | @@ -162,13 +443,6 @@ |
434 | _("Adjust the rotation angle")); |
435 | knotholder->add(e); |
436 | } |
437 | -} |
438 | - |
439 | -void |
440 | -LPECopyRotate::resetDefaults(SPItem const* item) |
441 | -{ |
442 | - Effect::resetDefaults(item); |
443 | - original_bbox(SP_LPE_ITEM(item)); |
444 | }; |
445 | |
446 | namespace CR { |
447 | |
448 | === modified file 'src/live_effects/lpe-copy_rotate.h' |
449 | --- src/live_effects/lpe-copy_rotate.h 2015-01-20 23:05:32 +0000 |
450 | +++ src/live_effects/lpe-copy_rotate.h 2016-03-19 11:19:31 +0000 |
451 | @@ -22,24 +22,22 @@ |
452 | namespace LivePathEffect { |
453 | |
454 | namespace CR { |
455 | - // we need a separate namespace to avoid clashes with LPEPerpBisector |
456 | - class KnotHolderEntityStartingAngle; |
457 | - class KnotHolderEntityRotationAngle; |
458 | +// we need a separate namespace to avoid clashes with LPEPerpBisector |
459 | +class KnotHolderEntityStartingAngle; |
460 | +class KnotHolderEntityRotationAngle; |
461 | } |
462 | |
463 | class LPECopyRotate : public Effect, GroupBBoxEffect { |
464 | public: |
465 | LPECopyRotate(LivePathEffectObject *lpeobject); |
466 | virtual ~LPECopyRotate(); |
467 | - |
468 | virtual void doOnApply (SPLPEItem const* lpeitem); |
469 | - |
470 | virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); |
471 | - |
472 | virtual void doBeforeEffect (SPLPEItem const* lpeitem); |
473 | - |
474 | + virtual void setFusion(Geom::PathVector &path_in, Geom::Path divider, double sizeDivider); |
475 | + virtual void split(Geom::PathVector &path_in, Geom::Path const ÷r); |
476 | virtual void resetDefaults(SPItem const* item); |
477 | - |
478 | + virtual void transform_multiply(Geom::Affine const& postmul, bool set); |
479 | /* the knotholder entity classes must be declared friends */ |
480 | friend class CR::KnotHolderEntityStartingAngle; |
481 | friend class CR::KnotHolderEntityRotationAngle; |
482 | @@ -53,16 +51,14 @@ |
483 | ScalarParam starting_angle; |
484 | ScalarParam rotation_angle; |
485 | ScalarParam num_copies; |
486 | - BoolParam copiesTo360; |
487 | - |
488 | + BoolParam copies_to_360; |
489 | + BoolParam fuse_paths; |
490 | Geom::Point A; |
491 | Geom::Point B; |
492 | Geom::Point dir; |
493 | - |
494 | Geom::Point start_pos; |
495 | Geom::Point rot_pos; |
496 | double dist_angle_handle; |
497 | - |
498 | LPECopyRotate(const LPECopyRotate&); |
499 | LPECopyRotate& operator=(const LPECopyRotate&); |
500 | }; |
Everything looks good to me.