Merge lp:~inkscape.dev/inkscape/copy-rotate-lpe-improvements into lp:~inkscape.dev/inkscape/trunk

Proposed by Jabiertxof
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
Reviewer Review Type Date Requested Status
Krzysztof Kosinski Approve
Martin Owens Approve
Jabiertxof Pending
Review via email: mp+247530@code.launchpad.net

Description of the change

Add Kaleidoscope Feature to Copy-Rotate LPE.
Here are videos working:
https://www.youtube.com/watch?v=LfMixSKy3Eo
https://www.youtube.com/watch?v=fBQpvfgT4mE

To post a comment you must log in.
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

Revision history for this message
Martin Owens (doctormo) wrote :

Everything looks good to me.

review: Approve
Revision history for this message
Krzysztof Kosinski (tweenk) wrote :

Approve after these fixes.

review: Approve
Revision history for this message
Jabiertxof (jabiertxof) wrote :

Thanks very much @Krzysztof for the review. I hope I can merge tonight.

Revision history for this message
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

Revision history for this message
Marcel Partap (empee584) wrote :

Very nice stuff πŸ‘
Now by the way, let's get inspired by https://www.youtube.com/watch?v=rYk9YfJuQUs (Kudos to Greece!) for further workflow improvements πŸ™ƒ!

Revision history for this message
Jabiertxof (jabiertxof) wrote :

Thanks Marcel!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/live_effects/effect.cpp'
--- src/live_effects/effect.cpp 2016-03-19 11:17:59 +0000
+++ src/live_effects/effect.cpp 2016-03-19 11:19:31 +0000
@@ -110,7 +110,6 @@
110 {PATH_LENGTH, N_("Path length"), "path_length"},110 {PATH_LENGTH, N_("Path length"), "path_length"},
111 {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"},111 {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"},
112 {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"},112 {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"},
113 {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"},
114 {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"},113 {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"},
115 {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},114 {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},
116 {TEXT_LABEL, N_("Text label"), "text_label"},115 {TEXT_LABEL, N_("Text label"), "text_label"},
@@ -145,6 +144,7 @@
145 {BSPLINE, N_("BSpline"), "bspline"},144 {BSPLINE, N_("BSpline"), "bspline"},
146 {JOIN_TYPE, N_("Join type"), "join_type"},145 {JOIN_TYPE, N_("Join type"), "join_type"},
147 {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"},146 {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"},
147 {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"},
148/* Ponyscape -> Inkscape 0.92*/148/* Ponyscape -> Inkscape 0.92*/
149 {ATTACH_PATH, N_("Attach path"), "attach_path"},149 {ATTACH_PATH, N_("Attach path"), "attach_path"},
150 {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"},150 {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"},
151151
=== modified file 'src/live_effects/lpe-copy_rotate.cpp'
--- src/live_effects/lpe-copy_rotate.cpp 2016-03-02 19:34:31 +0000
+++ src/live_effects/lpe-copy_rotate.cpp 2016-03-19 11:19:31 +0000
@@ -5,7 +5,7 @@
5 * Authors:5 * Authors:
6 * Maximilian Albert <maximilian.albert@gmail.com>6 * Maximilian Albert <maximilian.albert@gmail.com>
7 * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>7 * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>
8 *8 * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
9 * Copyright (C) Authors 2007-20129 * Copyright (C) Authors 2007-2012
10 *10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information11 * Released under GNU GPL, read the file 'COPYING' for more information
@@ -13,7 +13,8 @@
1313
14#include <glibmm/i18n.h>14#include <glibmm/i18n.h>
15#include <gdk/gdk.h>15#include <gdk/gdk.h>
1616#include <2geom/path-intersection.h>
17#include <2geom/sbasis-to-bezier.h>
17#include "live_effects/lpe-copy_rotate.h"18#include "live_effects/lpe-copy_rotate.h"
18#include <2geom/path.h>19#include <2geom/path.h>
19#include <2geom/transforms.h>20#include <2geom/transforms.h>
@@ -41,22 +42,39 @@
41 virtual Geom::Point knot_get() const;42 virtual Geom::Point knot_get() const;
42};43};
4344
44class KnotHolderEntityOrigin : public LPEKnotHolderEntity {
45public:
46 KnotHolderEntityOrigin(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {};
47 virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
48 virtual Geom::Point knot_get() const;
49};
50
51} // namespace CR45} // namespace CR
5246
47int
48pointSideOfLine(Geom::Point const &A, Geom::Point const &B, Geom::Point const &X)
49{
50 //http://stackoverflow.com/questions/1560492/how-to-tell-whether-a-point-is-to-the-right-or-left-side-of-a-line
51 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]);
52 return (pos < 0) ? -1 : (pos > 0);
53}
54
55bool
56pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3)
57{
58 //http://totologic.blogspot.com.es/2014/01/accurate-point-in-triangle-test.html
59 using Geom::X;
60 using Geom::Y;
61 double denominator = (p1[X]*(p2[Y] - p3[Y]) + p1[Y]*(p3[X] - p2[X]) + p2[X]*p3[Y] - p2[Y]*p3[X]);
62 double t1 = (p[X]*(p3[Y] - p1[Y]) + p[Y]*(p1[X] - p3[X]) - p1[X]*p3[Y] + p1[Y]*p3[X]) / denominator;
63 double t2 = (p[X]*(p2[Y] - p1[Y]) + p[Y]*(p1[X] - p2[X]) - p1[X]*p2[Y] + p1[Y]*p2[X]) / -denominator;
64 double s = t1 + t2;
65
66 return 0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1 && s <= 1;
67}
68
69
53LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :70LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
54 Effect(lpeobject),71 Effect(lpeobject),
55 origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"),72 origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"),
56 starting_angle(_("Starting:"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0),73 starting_angle(_("Starting:"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0),
57 rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 30.0),74 rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 30.0),
58 num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 5),75 num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 5),
59 copiesTo360(_("360ΒΊ Copies"), _("No rotation angle, fixed to 360ΒΊ"), "copiesTo360", &wr, this, true),76 copies_to_360(_("360ΒΊ Copies"), _("No rotation angle, fixed to 360ΒΊ"), "copies_to_360", &wr, this, true),
77 fuse_paths(_("Fuse paths"), _("Fuse paths by helper line"), "fuse_paths", &wr, this, false),
60 dist_angle_handle(100.0)78 dist_angle_handle(100.0)
61{79{
62 show_orig_path = true;80 show_orig_path = true;
@@ -64,12 +82,13 @@
64 apply_to_clippath_and_mask = true;82 apply_to_clippath_and_mask = true;
6583
66 // register all your parameters here, so Inkscape knows which parameters this effect has:84 // register all your parameters here, so Inkscape knows which parameters this effect has:
67 registerParameter(&copiesTo360);85 registerParameter(&copies_to_360);
86 registerParameter(&fuse_paths);
68 registerParameter(&starting_angle);87 registerParameter(&starting_angle);
69 registerParameter(&rotation_angle);88 registerParameter(&rotation_angle);
70 registerParameter(&num_copies);89 registerParameter(&num_copies);
71 registerParameter(&origin);90 registerParameter(&origin);
72 91
73 num_copies.param_make_integer(true);92 num_copies.param_make_integer(true);
74 num_copies.param_set_range(0, 1000);93 num_copies.param_set_range(0, 1000);
75}94}
@@ -93,15 +112,45 @@
93 dir = unit_vector(B - A);112 dir = unit_vector(B - A);
94}113}
95114
115void
116LPECopyRotate::transform_multiply(Geom::Affine const& postmul, bool set)
117{
118 if(fuse_paths) {
119 Geom::Coord angle = Geom::deg_from_rad(atan(-postmul[1]/postmul[0]));
120 angle += starting_angle;
121 starting_angle.param_set_value(angle);
122 }
123 // cycle through all parameters. Most parameters will not need transformation, but path and point params do.
124
125 for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) {
126 Parameter * param = *it;
127 param->param_transform_multiply(postmul, set);
128 }
129}
96130
97void131void
98LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem)132LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem)
99{133{
100 using namespace Geom;134 using namespace Geom;
101 original_bbox(lpeitem);135 original_bbox(lpeitem);
102 if(copiesTo360 ){136 if (copies_to_360) {
103 rotation_angle.param_set_value(360.0/(double)num_copies);137 rotation_angle.param_set_value(360.0/(double)num_copies);
104 } 138 }
139 if (fuse_paths && rotation_angle * num_copies > 360 && rotation_angle > 0) {
140 num_copies.param_set_value(floor(360/rotation_angle));
141 }
142 if (fuse_paths && copies_to_360) {
143 num_copies.param_set_increments(2,2);
144 if ((int)num_copies%2 !=0) {
145 num_copies.param_set_value(num_copies+1);
146 }
147 } else {
148 num_copies.param_set_increments(1,1);
149 }
150
151 if (dist_angle_handle < 1.0) {
152 dist_angle_handle = 1.0;
153 }
105 A = Point(boundingbox_X.min(), boundingbox_Y.middle());154 A = Point(boundingbox_X.min(), boundingbox_Y.middle());
106 B = Point(boundingbox_X.middle(), boundingbox_Y.middle());155 B = Point(boundingbox_X.middle(), boundingbox_Y.middle());
107 dir = unit_vector(B - A);156 dir = unit_vector(B - A);
@@ -109,27 +158,251 @@
109 // likely due to SVG's choice of coordinate system orientation (max)158 // likely due to SVG's choice of coordinate system orientation (max)
110 start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle;159 start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle;
111 rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle;160 rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle;
112 if(copiesTo360 ){161 if ( fuse_paths || copies_to_360 ) {
113 rot_pos = origin;162 rot_pos = origin;
114 }163 }
115}164 SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
116165 item->apply_to_clippath(item);
166 item->apply_to_mask(item);
167}
168
169void
170LPECopyRotate::split(Geom::PathVector &path_on, Geom::Path const &divider)
171{
172 Geom::PathVector tmp_path;
173 double time_start = 0.0;
174 Geom::Path original = path_on[0];
175 int position = 0;
176 Geom::Crossings cs = crossings(original,divider);
177 std::vector<double> crossed;
178 for(unsigned int i = 0; i < cs.size(); i++) {
179 crossed.push_back(cs[i].ta);
180 }
181 std::sort(crossed.begin(), crossed.end());
182 for (unsigned int i = 0; i < crossed.size(); i++) {
183 double time_end = crossed[i];
184 Geom::Path portion_original = original.portion(time_start,time_end);
185 if (!portion_original.empty()) {
186 Geom::Point side_checker = portion_original.pointAt(0.001);
187 position = pointSideOfLine(divider[0].finalPoint(), divider[1].finalPoint(), side_checker);
188 if (rotation_angle != 180) {
189 position = pointInTriangle(side_checker, divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint());
190 }
191 if (position == 1) {
192 tmp_path.push_back(portion_original);
193 }
194 portion_original.clear();
195 time_start = time_end;
196 }
197 }
198 position = pointSideOfLine(divider[0].finalPoint(), divider[1].finalPoint(), original.finalPoint());
199 if (rotation_angle != 180) {
200 position = pointInTriangle(original.finalPoint(), divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint());
201 }
202 if (cs.size() > 0 && position == 1) {
203 Geom::Path portion_original = original.portion(time_start, original.size());
204 if(!portion_original.empty()){
205 if (!original.closed()) {
206 tmp_path.push_back(portion_original);
207 } else {
208 if (tmp_path.size() > 0 && tmp_path[0].size() > 0 ) {
209 portion_original.setFinal(tmp_path[0].initialPoint());
210 portion_original.append(tmp_path[0]);
211 tmp_path[0] = portion_original;
212 } else {
213 tmp_path.push_back(portion_original);
214 }
215 }
216 portion_original.clear();
217 }
218 }
219 if (cs.size()==0 && position == 1) {
220 tmp_path.push_back(original);
221 }
222 path_on = tmp_path;
223}
224
225void
226LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double size_divider)
227{
228 split(path_on,divider);
229 Geom::PathVector tmp_path;
230 Geom::Affine pre = Geom::Translate(-origin);
231 for (Geom::PathVector::const_iterator path_it = path_on.begin(); path_it != path_on.end(); ++path_it) {
232 Geom::Path original = *path_it;
233 if (path_it->empty()) {
234 continue;
235 }
236 Geom::PathVector tmp_path_helper;
237 Geom::Path append_path = original;
238
239 for (int i = 0; i < num_copies; ++i) {
240 Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * (i)));
241 Geom::Affine m = pre * rot * Geom::Translate(origin);
242 if (i%2 != 0) {
243 Geom::Point A = (Geom::Point)origin;
244 Geom::Point B = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider;
245 Geom::Affine m1(1.0, 0.0, 0.0, 1.0, A[0], A[1]);
246 double hyp = Geom::distance(A, B);
247 double c = (B[0] - A[0]) / hyp; // cos(alpha)
248 double s = (B[1] - A[1]) / hyp; // sin(alpha)
249
250 Geom::Affine m2(c, -s, s, c, 0.0, 0.0);
251 Geom::Affine sca(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
252
253 Geom::Affine tmp_m = m1.inverse() * m2;
254 m = tmp_m;
255 m = m * sca;
256 m = m * m2.inverse();
257 m = m * m1;
258 } else {
259 append_path = original;
260 }
261 append_path *= m;
262 if (tmp_path_helper.size() > 0) {
263 if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.finalPoint())) {
264 Geom::Path tmp_append = append_path.reversed();
265 tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint());
266 tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append);
267 } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(), append_path.initialPoint())) {
268 Geom::Path tmp_append = append_path;
269 tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed();
270 tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint());
271 tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append);
272 tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed();
273 } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.initialPoint())) {
274 Geom::Path tmp_append = append_path;
275 tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint());
276 tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append);
277 } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(), append_path.finalPoint())) {
278 Geom::Path tmp_append = append_path.reversed();
279 tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed();
280 tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint());
281 tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append);
282 tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed();
283 } else if (Geom::are_near(tmp_path_helper[0].finalPoint(), append_path.finalPoint())) {
284 Geom::Path tmp_append = append_path.reversed();
285 tmp_append.setInitial(tmp_path_helper[0].finalPoint());
286 tmp_path_helper[0].append(tmp_append);
287 } else if (Geom::are_near(tmp_path_helper[0].initialPoint(), append_path.initialPoint())) {
288 Geom::Path tmp_append = append_path;
289 tmp_path_helper[0] = tmp_path_helper[0].reversed();
290 tmp_append.setInitial(tmp_path_helper[0].finalPoint());
291 tmp_path_helper[0].append(tmp_append);
292 tmp_path_helper[0] = tmp_path_helper[0].reversed();
293 } else {
294 tmp_path_helper.push_back(append_path);
295 }
296 if ( Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),tmp_path_helper[tmp_path_helper.size()-1].initialPoint())) {
297 tmp_path_helper[tmp_path_helper.size()-1].close();
298 }
299 } else {
300 tmp_path_helper.push_back(append_path);
301 }
302 }
303 if (tmp_path_helper.size() > 0) {
304 tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1];
305 tmp_path_helper[0] = tmp_path_helper[0];
306 if (rotation_angle * num_copies != 360) {
307 Geom::Ray base_a(divider.pointAt(1),divider.pointAt(0));
308 double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max()));
309 Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max()));
310 double size_divider = Geom::distance(origin,bbox) + (diagonal * 2);
311 Geom::Point base_point = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle * num_copies) + starting_angle)) * size_divider;
312 Geom::Ray base_b(divider.pointAt(1), base_point);
313 if (Geom::are_near(tmp_path_helper[0].initialPoint(),base_a) &&
314 Geom::are_near(tmp_path_helper[0].finalPoint(),base_a))
315 {
316 tmp_path_helper[0].close();
317 if (tmp_path_helper.size() > 1) {
318 tmp_path_helper[tmp_path_helper.size()-1].close();
319 }
320 } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(),base_b) &&
321 Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_b))
322 {
323 tmp_path_helper[0].close();
324 if (tmp_path_helper.size() > 1) {
325 tmp_path_helper[tmp_path_helper.size()-1].close();
326 }
327 } else if ((Geom::are_near(tmp_path_helper[0].initialPoint(),base_a) &&
328 Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_b)) ||
329 (Geom::are_near(tmp_path_helper[0].initialPoint(),base_b) &&
330 Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_a)))
331 {
332 Geom::Path close_path = Geom::Path(tmp_path_helper[tmp_path_helper.size()-1].finalPoint());
333 close_path.appendNew<Geom::LineSegment>((Geom::Point)origin);
334 close_path.appendNew<Geom::LineSegment>(tmp_path_helper[0].initialPoint());
335 tmp_path_helper[0].append(close_path);
336 }
337 }
338
339 if (Geom::are_near(tmp_path_helper[0].finalPoint(),tmp_path_helper[0].initialPoint())) {
340 tmp_path_helper[0].close();
341 }
342 }
343 tmp_path.insert(tmp_path.end(), tmp_path_helper.begin(), tmp_path_helper.end());
344 tmp_path_helper.clear();
345 }
346 path_on = tmp_path;
347 tmp_path.clear();
348}
117349
118Geom::Piecewise<Geom::D2<Geom::SBasis> >350Geom::Piecewise<Geom::D2<Geom::SBasis> >
119LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)351LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
120{352{
121 using namespace Geom;353 using namespace Geom;
122354
123 if(num_copies == 1){355 if (num_copies == 1 && !fuse_paths) {
124 return pwd2_in;356 return pwd2_in;
125 }357 }
126358
359 double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max()));
360 Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max()));
361 double size_divider = Geom::distance(origin,bbox) + (diagonal * 2);
362 Geom::Point line_start = origin + dir * Rotate(-rad_from_deg(starting_angle)) * size_divider;
363 Geom::Point line_end = origin + dir * Rotate(-rad_from_deg(rotation_angle + starting_angle)) * size_divider;
364 //Note:: beter way to do this
365 //Whith AppendNew have problems whith the crossing order
366 Geom::Path divider = Geom::Path(line_start);
367 divider.appendNew<Geom::LineSegment>((Geom::Point)origin);
368 divider.appendNew<Geom::LineSegment>(line_end);
127 Piecewise<D2<SBasis> > output;369 Piecewise<D2<SBasis> > output;
128 Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle));370 Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle));
129 for (int i = 0; i < num_copies; ++i) {371 if (fuse_paths) {
130 Rotate rot(-rad_from_deg(rotation_angle * i));372 Geom::PathVector path_out;
131 Affine t = pre * rot * Translate(origin);373 Geom::PathVector tmp_path;
132 output.concat(pwd2_in * t);374 PathVector const original_pathv = path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001);
375 for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) {
376 if (path_it->empty()) {
377 continue;
378 }
379 bool end_open = false;
380 if (path_it->closed()) {
381 const Geom::Curve &closingline = path_it->back_closed();
382 if (!are_near(closingline.initialPoint(), closingline.finalPoint())) {
383 end_open = true;
384 }
385 }
386 Geom::Path original = (Geom::Path)(*path_it);
387 if (end_open && path_it->closed()) {
388 original.close(false);
389 original.appendNew<Geom::LineSegment>( original.initialPoint() );
390 original.close(true);
391 }
392 tmp_path.push_back(original);
393 setFusion(tmp_path, divider, size_divider);
394 path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end());
395 tmp_path.clear();
396 }
397 if (path_out.size()>0) {
398 output = paths_to_pw(path_out);
399 }
400 } else {
401 for (int i = 0; i < num_copies; ++i) {
402 Rotate rot(-rad_from_deg(rotation_angle * i));
403 Affine t = pre * rot * Translate(origin);
404 output.concat(pwd2_in * t);
405 }
133 }406 }
134 return output;407 return output;
135}408}
@@ -148,8 +421,16 @@
148 hp_vec.push_back(pathv);421 hp_vec.push_back(pathv);
149}422}
150423
424void
425LPECopyRotate::resetDefaults(SPItem const* item)
426{
427 Effect::resetDefaults(item);
428 original_bbox(SP_LPE_ITEM(item));
429}
151430
152void LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {431void
432LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
433{
153 {434 {
154 KnotHolderEntity *e = new CR::KnotHolderEntityStartingAngle(this);435 KnotHolderEntity *e = new CR::KnotHolderEntityStartingAngle(this);
155 e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,436 e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
@@ -162,13 +443,6 @@
162 _("Adjust the rotation angle"));443 _("Adjust the rotation angle"));
163 knotholder->add(e);444 knotholder->add(e);
164 }445 }
165}
166
167void
168LPECopyRotate::resetDefaults(SPItem const* item)
169{
170 Effect::resetDefaults(item);
171 original_bbox(SP_LPE_ITEM(item));
172};446};
173447
174namespace CR {448namespace CR {
175449
=== modified file 'src/live_effects/lpe-copy_rotate.h'
--- src/live_effects/lpe-copy_rotate.h 2015-01-20 23:05:32 +0000
+++ src/live_effects/lpe-copy_rotate.h 2016-03-19 11:19:31 +0000
@@ -22,24 +22,22 @@
22namespace LivePathEffect {22namespace LivePathEffect {
2323
24namespace CR {24namespace CR {
25 // we need a separate namespace to avoid clashes with LPEPerpBisector25// we need a separate namespace to avoid clashes with LPEPerpBisector
26 class KnotHolderEntityStartingAngle;26class KnotHolderEntityStartingAngle;
27 class KnotHolderEntityRotationAngle;27class KnotHolderEntityRotationAngle;
28}28}
2929
30class LPECopyRotate : public Effect, GroupBBoxEffect {30class LPECopyRotate : public Effect, GroupBBoxEffect {
31public:31public:
32 LPECopyRotate(LivePathEffectObject *lpeobject);32 LPECopyRotate(LivePathEffectObject *lpeobject);
33 virtual ~LPECopyRotate();33 virtual ~LPECopyRotate();
34
35 virtual void doOnApply (SPLPEItem const* lpeitem);34 virtual void doOnApply (SPLPEItem const* lpeitem);
36
37 virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);35 virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
38
39 virtual void doBeforeEffect (SPLPEItem const* lpeitem);36 virtual void doBeforeEffect (SPLPEItem const* lpeitem);
4037 virtual void setFusion(Geom::PathVector &path_in, Geom::Path divider, double sizeDivider);
38 virtual void split(Geom::PathVector &path_in, Geom::Path const &divider);
41 virtual void resetDefaults(SPItem const* item);39 virtual void resetDefaults(SPItem const* item);
4240 virtual void transform_multiply(Geom::Affine const& postmul, bool set);
43 /* the knotholder entity classes must be declared friends */41 /* the knotholder entity classes must be declared friends */
44 friend class CR::KnotHolderEntityStartingAngle;42 friend class CR::KnotHolderEntityStartingAngle;
45 friend class CR::KnotHolderEntityRotationAngle;43 friend class CR::KnotHolderEntityRotationAngle;
@@ -53,16 +51,14 @@
53 ScalarParam starting_angle;51 ScalarParam starting_angle;
54 ScalarParam rotation_angle;52 ScalarParam rotation_angle;
55 ScalarParam num_copies;53 ScalarParam num_copies;
56 BoolParam copiesTo360;54 BoolParam copies_to_360;
5755 BoolParam fuse_paths;
58 Geom::Point A;56 Geom::Point A;
59 Geom::Point B;57 Geom::Point B;
60 Geom::Point dir;58 Geom::Point dir;
61
62 Geom::Point start_pos;59 Geom::Point start_pos;
63 Geom::Point rot_pos;60 Geom::Point rot_pos;
64 double dist_angle_handle;61 double dist_angle_handle;
65
66 LPECopyRotate(const LPECopyRotate&);62 LPECopyRotate(const LPECopyRotate&);
67 LPECopyRotate& operator=(const LPECopyRotate&);63 LPECopyRotate& operator=(const LPECopyRotate&);
68};64};