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