Merge lp:~inkscape.dev/inkscape/pathVectorSatellites into lp:~inkscape.dev/inkscape/trunk

Proposed by Jabiertxof
Status: Merged
Merged at revision: 15666
Proposed branch: lp:~inkscape.dev/inkscape/pathVectorSatellites
Merge into: lp:~inkscape.dev/inkscape/trunk
Diff against target: 4168 lines (+2029/-1667)
20 files modified
po/POTFILES.in (+1/-1)
src/helper/CMakeLists.txt (+4/-0)
src/helper/geom-pathvectorsatellites.cpp (+244/-0)
src/helper/geom-pathvectorsatellites.h (+58/-0)
src/helper/geom-satellite.cpp (+245/-0)
src/helper/geom-satellite.h (+110/-0)
src/knotholder.h (+3/-2)
src/live_effects/CMakeLists.txt (+2/-2)
src/live_effects/effect.cpp (+1/-1)
src/live_effects/lpe-fillet-chamfer.cpp (+466/-543)
src/live_effects/lpe-fillet-chamfer.h (+29/-35)
src/live_effects/parameter/array.cpp (+40/-4)
src/live_effects/parameter/array.h (+38/-1)
src/live_effects/parameter/filletchamferpointarray.cpp (+0/-873)
src/live_effects/parameter/filletchamferpointarray.h (+0/-123)
src/live_effects/parameter/satellitesarray.cpp (+583/-0)
src/live_effects/parameter/satellitesarray.h (+114/-0)
src/ui/dialog/lpe-fillet-chamfer-properties.cpp (+63/-52)
src/ui/dialog/lpe-fillet-chamfer-properties.h (+28/-22)
src/ui/tool/path-manipulator.cpp (+0/-8)
To merge this branch: bzr merge lp:~inkscape.dev/inkscape/pathVectorSatellites
Reviewer Review Type Date Requested Status
Jabiertxof Needs Resubmitting
Krzysztof Kosinski Needs Fixing
Review via email: mp+254724@code.launchpad.net

Description of the change

Add pointwise class to manage "satellite" data in nodes and a add a refactor of fillet-chamfer LPE using it.

To post a comment you must log in.
13704. By Jabiertxof <email address hidden>

change pointwise comment

13705. By Jabiertxof <email address hidden>

Remove active desktop calls from LPE

13706. By Jabiertxof <email address hidden>

fixed hide knots and removed unused headers

13707. By Jabiertxof <email address hidden>

removed code comments

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

- 2Geom is a separate library, not part of Inkscape. It should only contain code which is useful outside of Inkscape, and the changes should be submitted to 2Geom.
- 2geom/pointwise.h has a dependency on helper/geom.h, which is unacceptable.
- The Pointwise and Satellite classes are poorly undocumented - I don't understand what they are supposed to do. Are they supposed to some store per-node data? Their interface is rather unintelligible.
- The computational complexity comments are misleading. This code is obviously O(N) in the number of satellites and should either use a map or a simple vector, not a vector of pairs of size_t and Satellite. What is the intended purpose?
- The coding style does not match Inkscape's and is in fact inconsistent even within this patchset (some methods are in snake_case, some local variables are in lowerCamelCase, invalid indent in class definitions, etc.)
- The getters and setters on Satellite are pointless, they could simply be replaced by public fields.
- The way the satellite parameters are stored is very un-XML. I possible, each of the boolean parameters should be a separate attribute.

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

Hi Krzysztof thanks for the fast review.
I try to improve all.
Regards.

13708. By Jabiertxof <email address hidden>

Move 2Geom work to a intermediate positon -helper-
Removed dependency to helper/geom.h
Now use a simple vector, not a vector of pairs of size_t and Satellite
Getters and setters on Satellite removed
Update store parameter to a more friendly string, like powerstroke
Todo:
Documentation and Fix coding style.

13709. By Jabiertxof <email address hidden>

More cleanup of code structure.
TODO: Documentation
TODO: Fit code guidelines of Inkscape

13710. By Jabiertxof <email address hidden>

add documentation

13711. By Jabiertxof <email address hidden>

Added documentation and fix to coding style.

13712. By Jabiertxof <email address hidden>

update to trunk

13713. By Jabiertxof <email address hidden>

Now open -without conversion- old fillet chamfer objects

13714. By Jabiertxof <email address hidden>

add move knots when move nodes pointed by su_v

13715. By Jabiertxof <email address hidden>

Adding suport for duplicate nodes
Allow degenrate curves
Show helper path whith original path

13716. By Jabiertxof <email address hidden>

update to trunk

13717. By Jabiertxof <email address hidden>

Update pathinfo class to allow piecewise and pathvector as input.
Add a method on pointwise to allow update if degenerated curves in new path, not noticed by piecewises

13718. By Jabiertxof <email address hidden>

Updated Pathinfo to discrimine degenerate curves optionaly.
Fixed redundant data in are_near from pointwise
Fixed Fillet-Chamfer lpe to allow duplicate nodes

13719. By Jabiertxof <email address hidden>

Fix a bug in pathinfo

13720. By Jabiertxof <email address hidden>

update to trunk

13721. By Jabiertxof <email address hidden>

fixing bug on closed paths

13722. By Jabiertxof <email address hidden>

Fixed bug on closed paths, Clenup of pathinfo

Revision history for this message
Jabiertxof (jabiertxof) wrote :

Hi Krzysztof, could you review again the branch?
Thanks very much, Jabier.

review: Needs Resubmitting
13723. By Jabiertxof <email address hidden>

rename pathinfo function

13724. By Jabiertxof <email address hidden>

Adding and renaming methofs to pathinfo

13725. By Jabiertxof <email address hidden>

added comment

13726. By Jabiertxof <email address hidden>

update to trunk

13727. By Jabiertxof <email address hidden>

adding suport to full path reverse

13728. By Jabiertxof <email address hidden>

update to trunk

13729. By Jabiertxof <email address hidden>

prevent overflow index on a pathinfo function

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

There are still a lot of issues that need to be fixed.

I am not sure about the class Pathinfo. I think these functions could be added directly to PathVector, but I'm not sure yet what Pathinfo does.

You should spend some time on writing comments what your code wants to do, it will be easier to review.

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

Thanks for the review Krzysztof. I take it soon.

13730. By Jabiertxof <email address hidden>

update to trunk

13731. By Jabiertxof <email address hidden>

fixing review

13732. By Jabiertxof <email address hidden>

fixing review

13733. By Jabiertxof <email address hidden>

update to trunk

13734. By Jabiertxof <email address hidden>

Working on Krzysztof review. Seems to be all fixed.
TODO: double check review and comment

13735. By Jabiertxof <email address hidden>

Added some comments

13736. By Jabiertxof <email address hidden>

some comments and pointwise related refactor

Revision history for this message
Jabiertxof (jabiertxof) wrote :

Hi Krzysztof, could you review again the branch?
Thanks very much, Jabier.

review: Needs Resubmitting
13737. By Jabiertxof <email address hidden>

fix a minor bug calculating max time

13738. By Jabiertxof <email address hidden>

update to trunk

13739. By Jabiertxof <email address hidden>

update to trunk

13740. By Jabiertxof <email address hidden>

attemp to handle reverse path

13741. By Jabiertxof <email address hidden>

update to trunk

13742. By Jabiertxof <email address hidden>

removed reverse path, commented why

13743. By Jabiertxof <email address hidden>

update to trunk

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

This looks better, but I think I understand what Pathinfo does now, and the whole class is unnecessary. The number of nodes in a Geom::Path is equal to size_closed(), you don't need to reimplement it and you don't need the active attribute in satellites.

I only reviewed a portion of the code - I will try to continue the review during this weekend.

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

Thanks Krzysztof for the review. A great new i can use your last work on 2Geom inside Inkscape trunk! Go to fix!

Revision history for this message
Jabiertxof (jabiertxof) wrote :

One question Krzysztof, whats the best way to know the first and last subpath curve index on a pathvector?

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

The first subpath is always at index 0. The last one is at size_default() - 1. The number of nodes is always equal to std::max(size_closed(), 1ul): a path that has no segments contains only a naked moveto, and thus has one node. Hope this helps.

Revision history for this message
Jabiertxof (jabiertxof) wrote :

> The first subpath is always at index 0. The last one is at size_default() - 1.
> The number of nodes is always equal to std::max(size_closed(), 1ul): a path
> that has no segments contains only a naked moveto, and thus has one node. Hope
> this helps.
Thanks Krzysztof for the quick reply!
Seems I ask bad the question, i want to know the index of start and end index in a intermediate "subpath" not at full pathvector.

Maybe PathVectorTime can also return this value when retrive the value of pathvector index from PathVector->nearestPoint. This solve my problem with start/end of intermediate paths.

Sorry for my bad english.

Revision history for this message
Jabiertxof (jabiertxof) wrote :

More, Krzysztof:
I have a new commit with pathinfo class removed. Is working except a small function that need the index of first and last subpath.
Think is better commit it or wait to you to full review current branch?

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

You can commit your new code to this branch and I will try to review both the new code and the parts I didn't review yet.

13744. By Jabiertxof <email address hidden>

update to trunk

13745. By Jabiertxof <email address hidden>

fix to compile on Krzysztof merge previous to fix the improvements in the merge request

13746. By Jabiertxof <email address hidden>

Fix a bug displaying arcs

13747. By Jabiertxof <email address hidden>

Fixes from branch review

13748. By Jabiertxof <email address hidden>

update to trunk

13749. By Jabiertxof <email address hidden>

pointwise tweak

13750. By Jabiertxof <email address hidden>

astyle

Revision history for this message
Jabiertxof (jabiertxof) wrote :

> You can commit your new code to this branch and I will try to review both the
> new code and the parts I didn't review yet.

Commited. Thanks for your time!

review: Needs Resubmitting
13751. By Jabiertxof <email address hidden>

update to trunk

13752. By Jabiertxof <email address hidden>

Not sure about this changes :(

13753. By Jabiertxof <email address hidden>

update to trunk

13754. By Jabiertxof <email address hidden>

remove couts

13755. By Jabiertxof <email address hidden>

satellites in curves

13756. By Jabiertxof <email address hidden>

Cached some functions

13757. By Jabiertxof <email address hidden>

addes cache and log to a function, result of the test, no diference so remove cache on next commit

13758. By Jabiertxof <email address hidden>

Removed cache work :(

13759. By Jabiertxof <email address hidden>

add 'little' comment

13760. By Jabiertxof <email address hidden>

update to trunk

13761. By Jabiertxof <email address hidden>

astyle code

13762. By Jabiertxof <email address hidden>

update to trunk

13763. By Jabiertxof <email address hidden>

Update to limit options to radius = 0, radious > 0 or both

13764. By Jabiertxof <email address hidden>

Update to trunk

13765. By Jabiertxof <email address hidden>

Fixed bugs post merge

13766. By Jabiertxof <email address hidden>

update to trunk

13767. By Jabiertxof <email address hidden>

update to trunk

13768. By Jabiertxof <email address hidden>

Remove advertaising buttons of old version

13769. By Jabiertxof <email address hidden>

update to trunk

13770. By Jabiertxof

update to trunk

13771. By Jabiertxof

remove a waring on compile

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

This is a little better, but it needs two major changes.

1. Opening a dialog by shift-clicking on a node is completely crazy. There must another way.
2. The doEffect function must be broken down into smaller functions so I can have any hope of understanding what it does.

Moreover, please consider using a vector of vectors for storing satellites. You would not need flat indexing of curves in pathvectors, which is error prone, and your code would be a lot simpler.

review: Needs Fixing
13772. By Jabiertxof

update to trunk

13773. By Jabiertxof

First attempt to make fixed tweenk review

13774. By Jabiertxof

update to trunk

13775. By Jabiertxof

Working with path updates

13776. By Jabiertxof

update to trunk

13777. By Jabiertxof

pre-remove of subpath update satellites

13778. By Jabiertxof

Fiximg pointwise

13779. By Jabiertxof

update to trunk

13780. By Jabiertxof

Fixing pointwise

13781. By Jabiertxof

update to trunk

13782. By Jabiertxof

Fixing pointwise

13783. By Jabiertxof

update to trunk

13784. By Jabiertxof

Update to refresh knots

13785. By Jabiertxof

update to trunk

13786. By Jabiertxof

Fixing pointwise

13787. By Jabiertxof

update to trunk

13788. By Jabiertxof

Fixing pointwise

13789. By Jabiertxof

update to trunk

13790. By Jabiertxof

Rename branch

13791. By Jabiertxof

Fixing satellites bug on erase

13792. By Jabiertxof

update to trunk

13793. By Jabiertxof

Fix the bug deleting satellites

13794. By Jabiertxof

update to trunk

13795. By Jabiertxof

Handle path add and remove nodes

13796. By Jabiertxof

update to trunk

13797. By Jabiertxof

Fix bug consecutive nodes at same position

13798. By Jabiertxof

update to trunk

13799. By Jabiertxof

Handle both directions on knot reposition

13800. By Jabiertxof

Fix 90% of tweenk review

13801. By Jabiertxof

update to trunk

13802. By Jabiertxof

Add snap to origin in double direction knots

13803. By Jabiertxof

update to trunk

13804. By Jabiertxof

attemp to simplify doeffect code on fillet chamfer

13805. By Jabiertxof

update to trunk

13806. By Jabiertxof

Pre fixing selected points

13807. By Jabiertxof

fixing bug moving nodes

13808. By Jabiertxof

Fixes when moves a path

13809. By Jabiertxof

Organize doeffect function

Revision history for this message
Jabiertxof (jabiertxof) wrote :

Fix Krzysztof Kosinski review.
Target 0.93

review: Needs Resubmitting
13810. By Jabiertxof <jtx@jtx>

Update to trunk

13811. By Jabiertxof <jtx@jtx>

Update to new code in trunk

13812. By Jabiertxof <jtx@jtx>

Update to trunk

13813. By Jabiertxof

update to trunk

13814. By Jabiertxof

update to trunk

13815. By Jabiertxof <jtx@jtx>

Update to trunk

13816. By Jabiertxof <jtx@jtx>

Remove some warnings

13817. By Jabiertxof <jtx@jtx>

Remove some warnings

13818. By Jabiertxof <jtx@jtx>

Update to trunk

Revision history for this message
Jabiertxof (jabiertxof) wrote :

Just updated to trunk. Code on trunk about fillet/chamfer need to be replaced by this branch. This is the cause this LPE is not on 0.92.

review: Needs Resubmitting
13819. By Jabiertxof

Update to trunk

13820. By Jabiertxof <jtx@jtx>

Update to trunk

13821. By Jabiertxof <jtx@jtx>

Updating code to trunk

13822. By Jabiertxof <jtx@jtx>

Pre merge fixing

Revision history for this message
Jabiertxof (jabiertxof) wrote :

Merged on r.15666

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 2016-12-27 15:49:22 +0000
3+++ po/POTFILES.in 2017-05-06 17:46:29 +0000
4@@ -153,7 +153,7 @@
5 src/live_effects/lpe-vonkoch.cpp
6 src/live_effects/parameter/bool.cpp
7 src/live_effects/parameter/enum.h
8-src/live_effects/parameter/filletchamferpointarray.cpp
9+src/live_effects/parameter/satellitearray.cpp
10 src/live_effects/parameter/fontbutton.cpp
11 src/live_effects/parameter/originalpath.cpp
12 src/live_effects/parameter/originalpatharray.cpp
13
14=== modified file 'src/helper/CMakeLists.txt'
15--- src/helper/CMakeLists.txt 2015-03-19 01:41:26 +0000
16+++ src/helper/CMakeLists.txt 2017-05-06 17:46:29 +0000
17@@ -14,6 +14,8 @@
18 geom.cpp
19 geom-nodetype.cpp
20 geom-pathstroke.cpp
21+ geom-pathvectorsatellites.cpp
22+ geom-satellite.cpp
23 gnome-utils.cpp
24 pixbuf-ops.cpp
25 png-write.cpp
26@@ -32,6 +34,8 @@
27 geom-curves.h
28 geom-nodetype.h
29 geom-pathstroke.h
30+ geom-pathvectorsatellites.h
31+ geom-satellite.h
32 geom.h
33 gnome-utils.h
34 mathfns.h
35
36=== added file 'src/helper/geom-pathvectorsatellites.cpp'
37--- src/helper/geom-pathvectorsatellites.cpp 1970-01-01 00:00:00 +0000
38+++ src/helper/geom-pathvectorsatellites.cpp 2017-05-06 17:46:29 +0000
39@@ -0,0 +1,244 @@
40+/**
41+ * \file
42+ * \brief PathVectorSatellites a class to manage satellites -per node extra data- in a pathvector
43+ */ /*
44+ * Authors:
45+ * Jabiertxof
46+ * Nathan Hurst
47+ * Johan Engelen
48+ * Josh Andler
49+ * suv
50+ * Mc-
51+ * Liam P. White
52+ * Krzysztof Kosiński
53+ * This code is in public domain
54+ */
55+
56+#include <helper/geom-pathvectorsatellites.h>
57+#include "util/units.h"
58+
59+Geom::PathVector PathVectorSatellites::getPathVector() const
60+{
61+ return _pathvector;
62+}
63+
64+void PathVectorSatellites::setPathVector(Geom::PathVector pathv)
65+{
66+ _pathvector = pathv;
67+}
68+
69+Satellites PathVectorSatellites::getSatellites()
70+{
71+ return _satellites;
72+}
73+
74+void PathVectorSatellites::setSatellites(Satellites satellites)
75+{
76+ _satellites = satellites;
77+}
78+
79+size_t PathVectorSatellites::getTotalSatellites()
80+{
81+ size_t counter = 0;
82+ for (size_t i = 0; i < _satellites.size(); ++i) {
83+ for (size_t j = 0; j < _satellites[i].size(); ++j) {
84+ counter++;
85+ }
86+ }
87+ return counter;
88+}
89+
90+std::pair<size_t, size_t> PathVectorSatellites::getIndexData(size_t index)
91+{
92+ size_t counter = 0;
93+ for (size_t i = 0; i < _satellites.size(); ++i) {
94+ for (size_t j = 0; j < _satellites[i].size(); ++j) {
95+ if (index == counter) {
96+ return std::make_pair(i,j);
97+ }
98+ counter++;
99+ }
100+ }
101+ return std::make_pair(0,0);
102+}
103+
104+void PathVectorSatellites::setSelected(std::vector<size_t> selected)
105+{
106+ size_t counter = 0;
107+ for (size_t i = 0; i < _satellites.size(); ++i) {
108+ for (size_t j = 0; j < _satellites[i].size(); ++j) {
109+ if (find (selected.begin(), selected.end(), counter) != selected.end()) {
110+ _satellites[i][j].setSelected(true);
111+ } else {
112+ _satellites[i][j].setSelected(false);
113+ }
114+ counter++;
115+ }
116+ }
117+}
118+
119+void PathVectorSatellites::updateSteps(size_t steps, bool apply_no_radius, bool apply_with_radius, bool only_selected)
120+{
121+ for (size_t i = 0; i < _satellites.size(); ++i) {
122+ for (size_t j = 0; j < _satellites[i].size(); ++j) {
123+ if ((!apply_no_radius && _satellites[i][j].amount == 0) ||
124+ (!apply_with_radius && _satellites[i][j].amount != 0))
125+ {
126+ continue;
127+ }
128+ if (only_selected) {
129+ if (_satellites[i][j].selected) {
130+ _satellites[i][j].steps = steps;
131+ }
132+ } else {
133+ _satellites[i][j].steps = steps;
134+ }
135+ }
136+ }
137+}
138+
139+void PathVectorSatellites::updateAmount(double radius, bool apply_no_radius, bool apply_with_radius, bool only_selected,
140+ bool use_knot_distance, bool flexible)
141+{
142+ double power = 0;
143+ if (!flexible) {
144+ power = radius;
145+ } else {
146+ power = radius / 100;
147+ }
148+ for (size_t i = 0; i < _satellites.size(); ++i) {
149+ for (size_t j = 0; j < _satellites[i].size(); ++j) {
150+ boost::optional<size_t> previous_index = boost::none;
151+ if (j == 0 && _pathvector[i].closed()) {
152+ previous_index = _pathvector[i].size() - 1;
153+ } else if (!_pathvector[i].closed() || j != 0) {
154+ previous_index = j - 1;
155+ }
156+ if (!_pathvector[i].closed() && j == 0) {
157+ _satellites[i][j].amount = 0;
158+ continue;
159+ }
160+ if (_pathvector[i].size() == j) {
161+ continue;
162+ }
163+ if ((!apply_no_radius && _satellites[i][j].amount == 0) ||
164+ (!apply_with_radius && _satellites[i][j].amount != 0))
165+ {
166+ continue;
167+ }
168+
169+ Geom::Point satellite_point = _pathvector[i].pointAt(j);
170+ if (_satellites[i][j].selected || !only_selected) {
171+ if (!use_knot_distance && !flexible) {
172+ if (previous_index) {
173+ _satellites[i][j].amount = _satellites[i][j].radToLen(power, _pathvector[i][*previous_index], _pathvector[i][j]);
174+ if (power && !_satellites[i][j].amount) {
175+ g_warning("Seems a too high radius value");
176+ }
177+ } else {
178+ _satellites[i][j].amount = 0.0;
179+ }
180+ } else {
181+ _satellites[i][j].amount = power;
182+ }
183+ }
184+ }
185+ }
186+}
187+
188+void PathVectorSatellites::convertUnit(Glib::ustring in, Glib::ustring to, bool apply_no_radius, bool apply_with_radius)
189+{
190+ for (size_t i = 0; i < _satellites.size(); ++i) {
191+ for (size_t j = 0; j < _satellites[i].size(); ++j) {
192+ if (!_pathvector[i].closed() && j == 0) {
193+ _satellites[i][j].amount = 0;
194+ continue;
195+ }
196+ if (_pathvector[i].size() == j) {
197+ continue;
198+ }
199+ if ((!apply_no_radius && _satellites[i][j].amount == 0) ||
200+ (!apply_with_radius && _satellites[i][j].amount != 0))
201+ {
202+ continue;
203+ }
204+ _satellites[i][j].amount = Inkscape::Util::Quantity::convert(_satellites[i][j].amount, in.c_str(), to.c_str());
205+ }
206+ }
207+}
208+
209+void PathVectorSatellites::updateSatelliteType(SatelliteType satellitetype, bool apply_no_radius, bool apply_with_radius,
210+ bool only_selected)
211+{
212+ for (size_t i = 0; i < _satellites.size(); ++i) {
213+ for (size_t j = 0; j < _satellites[i].size(); ++j) {
214+ if ((!apply_no_radius && _satellites[i][j].amount == 0) ||
215+ (!apply_with_radius && _satellites[i][j].amount != 0))
216+ {
217+ continue;
218+ }
219+ if (_pathvector[i].size() == j) {
220+ if (!only_selected) {
221+ _satellites[i][j].satellite_type = satellitetype;
222+ }
223+ continue;
224+ }
225+ if (only_selected) {
226+ Geom::Point satellite_point = _pathvector[i].pointAt(j);
227+ if (_satellites[i][j].selected) {
228+ _satellites[i][j].satellite_type = satellitetype;
229+ }
230+ } else {
231+ _satellites[i][j].satellite_type = satellitetype;
232+ }
233+ }
234+ }
235+}
236+
237+void PathVectorSatellites::recalculateForNewPathVector(Geom::PathVector const pathv, Satellite const S)
238+{
239+ Satellites satellites;
240+ bool found = false;
241+ //TODO evaluate fix on nodes at same position
242+ size_t number_nodes = pathv.nodes().size();
243+ size_t previous_number_nodes = _pathvector.nodes().size();
244+ for (size_t i = 0; i < pathv.size(); i++) {
245+ std::vector<Satellite> path_satellites;
246+ for (size_t j = 0; j < pathv[i].size_closed(); j++) {
247+ found = false;
248+ for (size_t k = 0; k < _pathvector.size(); k++) {
249+ for (size_t l = 0; l < _pathvector[k].size_closed(); l++) {
250+ if (Geom::are_near(_pathvector[k][l].initialPoint(), pathv[i][j].initialPoint()))
251+ {
252+ path_satellites.push_back(_satellites[k][l]);
253+ found = true;
254+ break;
255+ }
256+ }
257+ if (found) {
258+ break;
259+ }
260+ }
261+
262+ if (!found && previous_number_nodes < number_nodes) {
263+ path_satellites.push_back(S);
264+ }
265+ }
266+ satellites.push_back(path_satellites);
267+ }
268+ setPathVector(pathv);
269+ setSatellites(satellites);
270+}
271+
272+/*
273+ Local Variables:
274+ mode:c++
275+ c-file-style:"stroustrup"
276+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
277+ indent-tabs-mode:nil
278+ fill-column:99
279+ End:
280+*/
281+// vim:
282+// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
283+// :
284
285=== added file 'src/helper/geom-pathvectorsatellites.h'
286--- src/helper/geom-pathvectorsatellites.h 1970-01-01 00:00:00 +0000
287+++ src/helper/geom-pathvectorsatellites.h 2017-05-06 17:46:29 +0000
288@@ -0,0 +1,58 @@
289+/**
290+ * \file
291+ * \brief PathVectorSatellites a class to manage satellites -per node extra data- in a pathvector
292+ */ /*
293+ * Authors:
294+ * Jabiertxof
295+ * Nathan Hurst
296+ * Johan Engelen
297+ * Josh Andler
298+ * suv
299+ * Mc-
300+ * Liam P. White
301+ * Krzysztof Kosiński
302+ * This code is in public domain
303+ */
304+
305+#ifndef SEEN_PATHVECTORSATELLITES_H
306+#define SEEN_PATHVECTORSATELLITES_H
307+
308+#include <helper/geom-satellite.h>
309+#include <2geom/path.h>
310+#include <2geom/pathvector.h>
311+
312+typedef std::vector<std::vector<Satellite> > Satellites;
313+///@brief PathVectorSatellites a class to manage satellites in a pathvector
314+class PathVectorSatellites {
315+public:
316+ Geom::PathVector getPathVector() const;
317+ void setPathVector(Geom::PathVector pathv);
318+ Satellites getSatellites();
319+ void setSatellites(Satellites satellites);
320+ size_t getTotalSatellites();
321+ void setSelected(std::vector<size_t> selected);
322+ void updateSteps(size_t steps, bool apply_no_radius, bool apply_with_radius, bool only_selected);
323+ void updateAmount(double radius, bool apply_no_radius, bool apply_with_radius, bool only_selected,
324+ bool use_knot_distance, bool flexible);
325+ void convertUnit(Glib::ustring in, Glib::ustring to, bool apply_no_radius, bool apply_with_radius);
326+ void updateSatelliteType(SatelliteType satellitetype, bool apply_no_radius, bool apply_with_radius, bool only_selected);
327+ std::pair<size_t, size_t> getIndexData(size_t index);
328+ void recalculateForNewPathVector(Geom::PathVector const pathv, Satellite const S);
329+private:
330+ Geom::PathVector _pathvector;
331+ Satellites _satellites;
332+};
333+
334+#endif //SEEN_PATHVECTORSATELLITES_H
335+/*
336+ Local Variables:
337+ mode:c++
338+ c-file-style:"stroustrup"
339+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
340+ indent-tabs-mode:nil
341+ fill-column:99
342+ End:
343+*/
344+// vim:
345+// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
346+// :
347
348=== added file 'src/helper/geom-satellite.cpp'
349--- src/helper/geom-satellite.cpp 1970-01-01 00:00:00 +0000
350+++ src/helper/geom-satellite.cpp 2017-05-06 17:46:29 +0000
351@@ -0,0 +1,245 @@
352+/**
353+ * \file
354+ * \brief Satellite a per node holder of data.
355+ */ /*
356+ * Authors:
357+ * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es>
358+ *
359+ * This code is in public domain
360+ */
361+
362+#include <helper/geom-satellite.h>
363+#include <2geom/curve.h>
364+#include <2geom/nearest-time.h>
365+#include <2geom/path-intersection.h>
366+#include <2geom/sbasis-to-bezier.h>
367+#include <2geom/ray.h>
368+#include <boost/optional.hpp>
369+//log cache
370+#ifdef _WIN32
371+#include <Windows.h>
372+#else
373+#include <sys/time.h>
374+#include <ctime>
375+#endif
376+
377+///@brief Satellite a per node holder of data.
378+Satellite::Satellite() {}
379+
380+
381+Satellite::Satellite(SatelliteType satellite_type)
382+ : satellite_type(satellite_type),
383+ is_time(false),
384+ selected(false),
385+ has_mirror(false),
386+ hidden(true),
387+ amount(0.0),
388+ angle(0.0),
389+ steps(0)
390+{}
391+
392+Satellite::~Satellite() {}
393+
394+///Calculate the time in curve_in with a size of A
395+//TODO: find a better place to it
396+double timeAtArcLength(double const A, Geom::Curve const &curve_in)
397+{
398+ if ( A == 0 || curve_in.isDegenerate()) {
399+ return 0;
400+ }
401+
402+ Geom::D2<Geom::SBasis> d2_in = curve_in.toSBasis();
403+ double t = 0;
404+ double length_part = curve_in.length();
405+ if (A >= length_part || curve_in.isLineSegment()) {
406+ if (length_part != 0) {
407+ t = A / length_part;
408+ }
409+ } else if (!curve_in.isLineSegment()) {
410+ std::vector<double> t_roots = roots(Geom::arcLengthSb(d2_in) - A);
411+ if (!t_roots.empty()) {
412+ t = t_roots[0];
413+ }
414+ }
415+ return t;
416+}
417+
418+///Calculate the size in curve_in with a point at A
419+//TODO: find a better place to it
420+double arcLengthAt(double const A, Geom::Curve const &curve_in)
421+{
422+ if ( A == 0 || curve_in.isDegenerate()) {
423+ return 0;
424+ }
425+
426+ double s = 0;
427+ double length_part = curve_in.length();
428+ if (A > length_part || curve_in.isLineSegment()) {
429+ s = (A * length_part);
430+ } else if (!curve_in.isLineSegment()) {
431+ Geom::Curve *curve = curve_in.portion(0.0, A);
432+ s = curve->length();
433+ delete curve;
434+ }
435+ return s;
436+}
437+
438+///Convert a arc radius of a fillet/chamfer to his satellite length -point position where fillet/chamfer knot be on original curve
439+double Satellite::radToLen(
440+ double const A, Geom::Curve const &curve_in,
441+ Geom::Curve const &curve_out) const
442+{
443+ double len = 0;
444+ Geom::D2<Geom::SBasis> d2_in = curve_in.toSBasis();
445+ Geom::D2<Geom::SBasis> d2_out = curve_out.toSBasis();
446+ Geom::Piecewise<Geom::D2<Geom::SBasis> > offset_curve0 =
447+ Geom::Piecewise<Geom::D2<Geom::SBasis> >(d2_in) +
448+ rot90(unitVector(derivative(d2_in))) * (A);
449+ Geom::Piecewise<Geom::D2<Geom::SBasis> > offset_curve1 =
450+ Geom::Piecewise<Geom::D2<Geom::SBasis> >(d2_out) +
451+ rot90(unitVector(derivative(d2_out))) * (A);
452+ Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0];
453+ Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0];
454+ Geom::Crossings cs = Geom::crossings(p0, p1);
455+ if (cs.size() > 0) {
456+ Geom::Point cp = p0(cs[0].ta);
457+ double p0pt = nearest_time(cp, curve_out);
458+ len = arcLengthAt(p0pt, curve_out);
459+ } else {
460+ if (A > 0) {
461+ len = radToLen(A * -1, curve_in, curve_out);
462+ }
463+ }
464+ return len;
465+}
466+
467+///Convert a satelite length -point position where fillet/chamfer knot be on original curve- to a arc radius of fillet/chamfer
468+double Satellite::lenToRad(
469+ double const A, Geom::Curve const &curve_in,
470+ Geom::Curve const &curve_out,
471+ Satellite const previousSatellite) const
472+{
473+ double time_in = (previousSatellite).time(A, true, curve_in);
474+ double time_out = timeAtArcLength(A, curve_out);
475+ Geom::Point start_arc_point = curve_in.pointAt(time_in);
476+ Geom::Point end_arc_point = curve_out.pointAt(time_out);
477+ Geom::Curve *knot_curve1 = curve_in.portion(0, time_in);
478+ Geom::Curve *knot_curve2 = curve_out.portion(time_out, 1);
479+ Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve1);
480+ Geom::Ray ray1(start_arc_point, curve_in.pointAt(1));
481+ if (cubic1) {
482+ ray1.setPoints((*cubic1)[2], start_arc_point);
483+ }
484+ Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve2);
485+ Geom::Ray ray2(curve_out.pointAt(0), end_arc_point);
486+ if (cubic2) {
487+ ray2.setPoints(end_arc_point, (*cubic2)[1]);
488+ }
489+ bool ccw_toggle = cross(curve_in.pointAt(1) - start_arc_point,
490+ end_arc_point - start_arc_point) < 0;
491+ double distance_arc =
492+ Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point));
493+ double angle = angle_between(ray1, ray2, ccw_toggle);
494+ double divisor = std::sin(angle / 2.0);
495+ if (divisor > 0) {
496+ return distance_arc / divisor;
497+ }
498+ return 0;
499+}
500+
501+///Get the time position of the satellite in curve_in
502+double Satellite::time(Geom::Curve const &curve_in, bool inverse) const
503+{
504+ double t = amount;
505+ if (!is_time) {
506+ t = time(t, inverse, curve_in);
507+ } else if (inverse) {
508+ t = 1-t;
509+ }
510+ if (t > 1) {
511+ t = 1;
512+ }
513+ return t;
514+}
515+
516+///Get the time from a length A in other curve, a bolean inverse gived to reverse time
517+double Satellite::time(double A, bool inverse,
518+ Geom::Curve const &curve_in) const
519+{
520+ if (A == 0 && inverse) {
521+ return 1;
522+ }
523+ if (A == 0 && !inverse) {
524+ return 0;
525+ }
526+ if (!inverse) {
527+ return timeAtArcLength(A, curve_in);
528+ }
529+ double length_part = curve_in.length();
530+ A = length_part - A;
531+ return timeAtArcLength(A, curve_in);
532+}
533+
534+///Get the length of the satellite in curve_in
535+double Satellite::arcDistance(Geom::Curve const &curve_in) const
536+{
537+ double s = amount;
538+ if (is_time) {
539+ s = arcLengthAt(s, curve_in);
540+ }
541+ return s;
542+}
543+
544+///Get the point position of the satellite
545+Geom::Point Satellite::getPosition(Geom::Curve const &curve_in, bool inverse) const
546+{
547+ double t = time(curve_in, inverse);
548+ return curve_in.pointAt(t);
549+}
550+
551+///Set the position of the satellite from a gived point P
552+void Satellite::setPosition(Geom::Point const p, Geom::Curve const &curve_in, bool inverse)
553+{
554+ Geom::Curve * curve = const_cast<Geom::Curve *>(&curve_in);
555+ if (inverse) {
556+ curve = curve->reverse();
557+ }
558+ double A = Geom::nearest_time(p, *curve);
559+ if (!is_time) {
560+ A = arcLengthAt(A, *curve);
561+ }
562+ amount = A;
563+}
564+
565+
566+///Map a satellite type with gchar
567+void Satellite::setSatelliteType(gchar const *A)
568+{
569+ std::map<std::string, SatelliteType> gchar_map_to_satellite_type =
570+ boost::assign::map_list_of("F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE);
571+ std::map<std::string, SatelliteType>::iterator it = gchar_map_to_satellite_type.find(std::string(A));
572+ if (it != gchar_map_to_satellite_type.end()) {
573+ satellite_type = it->second;
574+ }
575+}
576+
577+///Map a gchar with satelliteType
578+gchar const *Satellite::getSatelliteTypeGchar() const
579+{
580+ std::map<SatelliteType, gchar const *> satellite_type_to_gchar_map =
581+ boost::assign::map_list_of(FILLET, "F")(INVERSE_FILLET, "IF")(CHAMFER, "C")(INVERSE_CHAMFER, "IC")(INVALID_SATELLITE, "KO");
582+ return satellite_type_to_gchar_map.at(satellite_type);
583+}
584+
585+/*
586+ Local Variables:
587+ mode:c++
588+ c-file-style:"stroustrup"
589+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
590+ indent-tabs-mode:nil
591+ fill-column:99
592+ End:
593+*/
594+// vim:
595+// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
596+// :
597
598=== added file 'src/helper/geom-satellite.h'
599--- src/helper/geom-satellite.h 1970-01-01 00:00:00 +0000
600+++ src/helper/geom-satellite.h 2017-05-06 17:46:29 +0000
601@@ -0,0 +1,110 @@
602+/**
603+ * \file
604+ * \brief Satellite a per node holder of data.
605+ */ /*
606+ * Authors:
607+ * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es>
608+ *
609+ * This code is in public domain
610+ */
611+
612+#ifndef SEEN_SATELLITE_H
613+#define SEEN_SATELLITE_H
614+
615+#include <map>
616+#include <boost/assign.hpp>
617+#include <2geom/sbasis-geometric.h>
618+#include "util/enums.h"
619+
620+
621+enum SatelliteType {
622+ FILLET = 0, //Fillet
623+ INVERSE_FILLET, //Inverse Fillet
624+ CHAMFER, //Chamfer
625+ INVERSE_CHAMFER, //Inverse Chamfer
626+ INVALID_SATELLITE // Invalid Satellite
627+};
628+/**
629+ * @brief Satellite a per node holder of data.
630+ */
631+
632+class Satellite {
633+public:
634+
635+ Satellite();
636+ Satellite(SatelliteType satellite_type);
637+
638+ virtual ~Satellite();
639+ void setIsTime(bool set_is_time)
640+ {
641+ is_time = set_is_time;
642+ }
643+ void setSelected(bool set_selected)
644+ {
645+ selected = set_selected;
646+ }
647+ void setHasMirror(bool set_has_mirror)
648+ {
649+ has_mirror = set_has_mirror;
650+ }
651+ void setHidden(bool set_hidden)
652+ {
653+ hidden = set_hidden;
654+ }
655+ void setAmount(bool set_amount)
656+ {
657+ amount = set_amount;
658+ }
659+ void setAngle(bool set_angle)
660+ {
661+ angle = set_angle;
662+ }
663+ void setSteps(bool set_steps)
664+ {
665+ steps = set_steps;
666+ }
667+ double lenToRad(double const A, Geom::Curve const &curve_in,
668+ Geom::Curve const &curve_out,
669+ Satellite const previousSatellite) const;
670+ double radToLen(double const A, Geom::Curve const &curve_in,
671+ Geom::Curve const &curve_out) const;
672+
673+ double time(Geom::Curve const &curve_in, bool inverse = false) const;
674+ double time(double A, bool inverse, Geom::Curve const &curve_in) const;
675+ double arcDistance(Geom::Curve const &curve_in) const;
676+
677+ void setPosition(Geom::Point const p, Geom::Curve const &curve_in, bool inverse = false);
678+ Geom::Point getPosition(Geom::Curve const &curve_in, bool inverse = false) const;
679+
680+ void setSatelliteType(gchar const *A);
681+ gchar const *getSatelliteTypeGchar() const;
682+ SatelliteType satellite_type;
683+ //The value stored could be a time value of the satellite in the curve or a lenght of distance to the node from the satellite
684+ //"is_time" tell is if is a time or lenght value
685+ bool is_time;
686+ bool selected;
687+ bool has_mirror;
688+ bool hidden;
689+ //in "amount" we store the time or distance used in the satellite
690+ double amount;
691+ double angle;
692+ size_t steps;
693+};
694+
695+double timeAtArcLength(double const A, Geom::Curve const &curve_in);
696+double arcLengthAt(double const A, Geom::Curve const &curve_in);
697+
698+#endif // SEEN_SATELLITE_H
699+
700+/*
701+ Local Variables:
702+ mode:c++
703+ c-file-style:"stroustrup"
704+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
705+ indent-tabs-mode:nil
706+ fill-column:99
707+ End:
708+*/
709+// vim:
710+// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
711+// :
712
713=== modified file 'src/knotholder.h'
714--- src/knotholder.h 2016-07-30 17:04:34 +0000
715+++ src/knotholder.h 2017-05-06 17:46:29 +0000
716@@ -30,7 +30,8 @@
717 }
718 namespace LivePathEffect {
719 class PowerStrokePointArrayParamKnotHolderEntity;
720-class FilletPointArrayParamKnotHolderEntity;
721+class SatellitesArrayParam;
722+class FilletChamferKnotHolderEntity;
723 }
724 }
725
726@@ -63,7 +64,7 @@
727
728 friend class Inkscape::UI::ShapeEditor; // FIXME why?
729 friend class Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity; // why?
730- friend class Inkscape::LivePathEffect::FilletPointArrayParamKnotHolderEntity; // why?
731+ friend class Inkscape::LivePathEffect::FilletChamferKnotHolderEntity; // why?
732
733 protected:
734
735
736=== modified file 'src/live_effects/CMakeLists.txt'
737--- src/live_effects/CMakeLists.txt 2017-01-24 09:44:10 +0000
738+++ src/live_effects/CMakeLists.txt 2017-05-06 17:46:29 +0000
739@@ -59,7 +59,6 @@
740
741 parameter/array.cpp
742 parameter/bool.cpp
743- parameter/filletchamferpointarray.cpp
744 parameter/item-reference.cpp
745 parameter/item.cpp
746 parameter/originalitem.cpp
747@@ -70,6 +69,7 @@
748 parameter/path.cpp
749 parameter/point.cpp
750 parameter/powerstrokepointarray.cpp
751+ parameter/satellitesarray.cpp
752 parameter/random.cpp
753 parameter/text.cpp
754 parameter/fontbutton.cpp
755@@ -144,7 +144,6 @@
756 parameter/array.h
757 parameter/bool.h
758 parameter/enum.h
759- parameter/filletchamferpointarray.h
760 parameter/item.h
761 parameter/item-reference.h
762 parameter/originalitem.h
763@@ -155,6 +154,7 @@
764 parameter/path.h
765 parameter/point.h
766 parameter/powerstrokepointarray.h
767+ parameter/satellitesarray.h
768 parameter/random.h
769 parameter/text.h
770 parameter/fontbutton.h
771
772=== modified file 'src/live_effects/effect.cpp'
773--- src/live_effects/effect.cpp 2017-05-05 14:45:16 +0000
774+++ src/live_effects/effect.cpp 2017-05-06 17:46:29 +0000
775@@ -101,7 +101,6 @@
776 {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"},
777 {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},
778 {TEXT_LABEL, N_("Text label"), "text_label"},
779- {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"},
780 #endif
781 /* 0.46 */
782 {BEND_PATH, N_("Bend"), "bend_path"},
783@@ -142,6 +141,7 @@
784 {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"},
785 /* 9.93 */
786 {MEASURE_LINE, N_("Measure Line"), "measure_line"},
787+ {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"},
788 };
789 const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
790
791
792=== modified file 'src/live_effects/lpe-fillet-chamfer.cpp'
793--- src/live_effects/lpe-fillet-chamfer.cpp 2017-04-28 19:42:36 +0000
794+++ src/live_effects/lpe-fillet-chamfer.cpp 2017-05-06 17:46:29 +0000
795@@ -4,86 +4,131 @@
796 *
797 * Copyright (C) 2014 Author(s)
798 *
799- * Special thanks to Johan Engelen for the base of the effect -powerstroke-
800- * Also to ScislaC for point me to the idea
801- * Also su_v for his construvtive feedback and time
802- * Also to Mc- (IRC nick) for his important contribution to find real time
803- * values based on
804- * and finaly to Liam P. White for his big help on coding, that save me a lot of hours
805 *
806 * Released under GNU GPL, read the file 'COPYING' for more information
807 */
808+
809 #include "live_effects/lpe-fillet-chamfer.h"
810-
811-#include <2geom/sbasis-to-bezier.h>
812-#include <2geom/elliptical-arc.h>
813-
814+#include "helper/geom.h"
815 #include "display/curve.h"
816-#include "helper/geom-nodetype.h"
817 #include "helper/geom-curves.h"
818-#include "helper/geom.h"
819+#include "helper/geom-satellite.h"
820+#include <2geom/elliptical-arc.h>
821+#include "knotholder.h"
822+#include <boost/optional.hpp>
823
824-// for programmatically updating knots
825-#include "ui/tools-switch.h"
826 // TODO due to internal breakage in glibmm headers, this must be last:
827 #include <glibmm/i18n.h>
828
829-using namespace Geom;
830 namespace Inkscape {
831 namespace LivePathEffect {
832
833-static const Util::EnumData<FilletMethod> FilletMethodData[FM_END] = {
834- { FM_AUTO, N_("Auto"), "auto" },
835+static const Util::EnumData<Filletmethod> FilletmethodData[] = {
836+ { FM_AUTO, N_("Auto"), "auto" },
837 { FM_ARC, N_("Force arc"), "arc" },
838 { FM_BEZIER, N_("Force bezier"), "bezier" }
839 };
840-static const Util::EnumDataConverter<FilletMethod>
841-FMConverter(FilletMethodData, FM_END);
842-
843-const double tolerance = 0.001;
844-const double gapHelper = 0.00001;
845-
846-LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) :
847- Effect(lpeobject),
848- fillet_chamfer_values(_("Fillet point"), _("Fillet point"), "fillet_chamfer_values", &wr, this),
849- hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, false),
850- ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), "ignore_radius_0", &wr, this, false),
851- only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false),
852- flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false),
853- use_knot_distance(_("Use knots distance instead radius"), _("Use knots distance instead radius"), "use_knot_distance", &wr, this, false),
854- method(_("Method:"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO),
855- radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr, this, 0.),
856- chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps", &wr, this, 0),
857-
858- helper_size(_("Helper size with direction:"), _("Helper size with direction"), "helper_size", &wr, this, 0)
859+static const Util::EnumDataConverter<Filletmethod> FMConverter(FilletmethodData, FM_END);
860+
861+LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject)
862+ : Effect(lpeobject),
863+ unit(_("Unit"), _("Unit"), "unit", &wr, this, "px"),
864+ satellites_param("Satellites_param", "Satellites_param",
865+ "satellites_param", &wr, this),
866+ method(_("Method:"), _("Methods to calculate the fillet or chamfer"),
867+ "method", FMConverter, &wr, this, FM_AUTO),
868+ radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr,
869+ this, 0.0),
870+ chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps",
871+ &wr, this, 1),
872+ flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"),
873+ "flexible", &wr, this, false),
874+ mirror_knots(_("Mirror Knots"), _("Mirror Knots"), "mirror_knots", &wr,
875+ this, true),
876+ only_selected(_("Change only selected nodes"),
877+ _("Change only selected nodes"), "only_selected", &wr, this,
878+ false),
879+ use_knot_distance(_("Use knots distance instead radius"),
880+ _("Use knots distance instead radius"),
881+ "use_knot_distance", &wr, this, false),
882+ hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this,
883+ false),
884+ apply_no_radius(_("Apply changes if radius = 0"), _("Apply changes if radius = 0"), "apply_no_radius", &wr, this, true),
885+ apply_with_radius(_("Apply changes if radius > 0"), _("Apply changes if radius > 0"), "apply_with_radius", &wr, this, true),
886+ helper_size(_("Helper path size with direction to node:"),
887+ _("Helper path size with direction to node"), "helper_size", &wr, this, 0),
888+ _pathvector_satellites(NULL),
889+ _degenerate_hide(false)
890 {
891- registerParameter(&fillet_chamfer_values);
892+ registerParameter(&satellites_param);
893+ registerParameter(&unit);
894 registerParameter(&method);
895 registerParameter(&radius);
896 registerParameter(&chamfer_steps);
897 registerParameter(&helper_size);
898 registerParameter(&flexible);
899 registerParameter(&use_knot_distance);
900- registerParameter(&ignore_radius_0);
901+ registerParameter(&mirror_knots);
902+ registerParameter(&apply_no_radius);
903+ registerParameter(&apply_with_radius);
904 registerParameter(&only_selected);
905 registerParameter(&hide_knots);
906
907- radius.param_set_range(0., infinity());
908+ radius.param_set_range(0.0, Geom::infinity());
909 radius.param_set_increments(1, 1);
910 radius.param_set_digits(4);
911 radius.param_overwrite_widget(true);
912 chamfer_steps.param_set_range(1, 999);
913 chamfer_steps.param_set_increments(1, 1);
914 chamfer_steps.param_set_digits(0);
915- chamfer_steps.param_overwrite_widget(true);
916- helper_size.param_set_range(0, infinity());
917+ helper_size.param_set_range(0, 999);
918 helper_size.param_set_increments(5, 5);
919 helper_size.param_set_digits(0);
920- helper_size.param_overwrite_widget(true);
921- fillet_chamfer_values.set_chamfer_steps(3);
922+ _provides_knotholder_entities = true;
923 }
924
925-LPEFilletChamfer::~LPEFilletChamfer() {}
926+void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem)
927+{
928+ SPLPEItem *splpeitem = const_cast<SPLPEItem *>(lpeItem);
929+ SPShape *shape = dynamic_cast<SPShape *>(splpeitem);
930+ if (shape) {
931+ Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(shape->getCurve()->get_pathvector());
932+ Satellites satellites;
933+ for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
934+ if (path_it->empty()) {
935+ continue;
936+ }
937+ std::vector<Satellite> subpath_satellites;
938+ for (Geom::Path::const_iterator curve_it = path_it->begin(); curve_it != path_it->end(); ++curve_it) {
939+ //Maybe we want this satellites...
940+ //if (curve_it->isDegenerate()) {
941+ // continue
942+ //}
943+ Satellite satellite(FILLET);
944+ satellite.setSteps(chamfer_steps);
945+ subpath_satellites.push_back(satellite);
946+ }
947+ //we add the last satellite on open path because _pathvector_satellites is related to nodes, not curves
948+ //so maybe in the future we can need this last satellite in other effects
949+ //dont remove for this effect because _pathvector_satellites class has methods when the path is modiffied
950+ //and we want one method for all uses
951+ if (!path_it->closed()) {
952+ Satellite satellite(FILLET);
953+ satellite.setSteps(chamfer_steps);
954+ subpath_satellites.push_back(satellite);
955+ }
956+ satellites.push_back(subpath_satellites);
957+ }
958+ _pathvector_satellites = new PathVectorSatellites();
959+ _pathvector_satellites->setPathVector(pathv);
960+ _pathvector_satellites->setSatellites(satellites);
961+ satellites_param.setPathVectorSatellites(_pathvector_satellites);
962+ } else {
963+ g_warning("LPE Fillet/Chamfer can only be applied to shapes (not groups).");
964+ SPLPEItem *item = const_cast<SPLPEItem *>(lpeItem);
965+ item->removeCurrentPathEffect(false);
966+ }
967+}
968
969 Gtk::Widget *LPEFilletChamfer::newWidget()
970 {
971@@ -94,54 +139,50 @@
972 vbox->set_border_width(5);
973 vbox->set_homogeneous(false);
974 vbox->set_spacing(2);
975- Gtk::HBox *advertaising = Gtk::manage(new Gtk::HBox(true, 0));
976- Gtk::Button *advert = Gtk::manage(new Gtk::Button(Glib::ustring(_("IMPORTANT! New version soon..."))));
977- advertaising->pack_start(*advert, true, true, 2);
978- vbox->pack_start(*advertaising, true, true, 2);
979- Gtk::HBox *advertaising2 = Gtk::manage(new Gtk::HBox(true, 0));
980- Gtk::Button *advert2 = Gtk::manage(new Gtk::Button(Glib::ustring(_("Not compatible. Convert to path after."))));
981- advertaising2->pack_start(*advert2, true, true, 2);
982- vbox->pack_start(*advertaising2, true, true, 2);
983 std::vector<Parameter *>::iterator it = param_vector.begin();
984 while (it != param_vector.end()) {
985 if ((*it)->widget_is_visible) {
986 Parameter *param = *it;
987 Gtk::Widget *widg = param->param_newWidget();
988 if (param->param_key == "radius") {
989- Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
990- widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::updateFillet));
991- widg = widgRegistered;
992+ Inkscape::UI::Widget::Scalar *widg_registered =
993+ Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
994+ widg_registered->signal_value_changed().connect(
995+ sigc::mem_fun(*this, &LPEFilletChamfer::updateAmount));
996+ widg = widg_registered;
997 if (widg) {
998- Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg);
999- std::vector<Gtk::Widget *> childList = scalarParameter->get_children();
1000- Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);
1001- entryWidg->set_width_chars(6);
1002+ Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg);
1003+ std::vector<Gtk::Widget *> childList = scalar_parameter->get_children();
1004+ Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]);
1005+ entry_widget->set_width_chars(6);
1006 }
1007+// } else if (param->param_key == "unit") {
1008+// Inkscape::UI::Widget::RegisteredUnitMenu* widg_registered =
1009+// Gtk::manage(dynamic_cast< Inkscape::UI::Widget::RegisteredUnitMenu *>(widg));
1010+// widg_registered->setUnit(unit.get_abbreviation());
1011+// widg_registered->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change unit parameter"));
1012+// widg_registered->getUnitMenu()->signal_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::convertUnit));
1013+// widg = widg_registered;
1014 } else if (param->param_key == "chamfer_steps") {
1015- Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
1016- widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamferSubdivisions));
1017- widg = widgRegistered;
1018+ Inkscape::UI::Widget::Scalar *widg_registered =
1019+ Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
1020+ widg_registered->signal_value_changed().connect(
1021+ sigc::mem_fun(*this, &LPEFilletChamfer::updateChamferSteps));
1022+ widg = widg_registered;
1023 if (widg) {
1024- Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg);
1025- std::vector<Gtk::Widget *> childList = scalarParameter->get_children();
1026- Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);
1027- entryWidg->set_width_chars(3);
1028+ Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg);
1029+ std::vector<Gtk::Widget *> childList = scalar_parameter->get_children();
1030+ Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]);
1031+ entry_widget->set_width_chars(3);
1032 }
1033- } else if (param->param_key == "flexible") {
1034- Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
1035- widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleFlexFixed));
1036 } else if (param->param_key == "helper_size") {
1037- Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
1038- widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots));
1039- } else if (param->param_key == "hide_knots") {
1040- Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
1041- widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleHide));
1042+ Inkscape::UI::Widget::Scalar *widg_registered =
1043+ Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
1044+ widg_registered->signal_value_changed().connect(
1045+ sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots));
1046 } else if (param->param_key == "only_selected") {
1047 Gtk::manage(widg);
1048- } else if (param->param_key == "ignore_radius_0") {
1049- Gtk::manage(widg);
1050 }
1051-
1052 Glib::ustring *tip = param->param_getTooltip();
1053 if (widg) {
1054 vbox->pack_start(*widg, true, true, 2);
1055@@ -153,504 +194,386 @@
1056 }
1057 }
1058 }
1059-
1060 ++it;
1061 }
1062- Gtk::HBox *filletContainer = Gtk::manage(new Gtk::HBox(true, 0));
1063- Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet"))));
1064- fillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet));
1065-
1066- filletContainer->pack_start(*fillet, true, true, 2);
1067- Gtk::Button *inverseFillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet"))));
1068- inverseFillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseFillet));
1069- filletContainer->pack_start(*inverseFillet, true, true, 2);
1070-
1071- Gtk::HBox *chamferContainer = Gtk::manage(new Gtk::HBox(true, 0));
1072+
1073+ Gtk::HBox *fillet_container = Gtk::manage(new Gtk::HBox(true, 0));
1074+ Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet"))));
1075+ fillet->signal_clicked()
1076+ .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),FILLET));
1077+
1078+ fillet_container->pack_start(*fillet, true, true, 2);
1079+ Gtk::Button *inverse_fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet"))));
1080+ inverse_fillet->signal_clicked()
1081+ .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_FILLET));
1082+ fillet_container->pack_start(*inverse_fillet, true, true, 2);
1083+
1084+ Gtk::HBox *chamfer_container = Gtk::manage(new Gtk::HBox(true, 0));
1085 Gtk::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer"))));
1086- chamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer));
1087-
1088- chamferContainer->pack_start(*chamfer, true, true, 2);
1089- Gtk::Button *inverseChamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer"))));
1090- inverseChamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseChamfer));
1091- chamferContainer->pack_start(*inverseChamfer, true, true, 2);
1092-
1093- vbox->pack_start(*filletContainer, true, true, 2);
1094- vbox->pack_start(*chamferContainer, true, true, 2);
1095+ chamfer->signal_clicked()
1096+ .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),CHAMFER));
1097+
1098+ chamfer_container->pack_start(*chamfer, true, true, 2);
1099+ Gtk::Button *inverse_chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer"))));
1100+ inverse_chamfer->signal_clicked()
1101+ .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_CHAMFER));
1102+ chamfer_container->pack_start(*inverse_chamfer, true, true, 2);
1103+
1104+ vbox->pack_start(*fillet_container, true, true, 2);
1105+ vbox->pack_start(*chamfer_container, true, true, 2);
1106
1107 return vbox;
1108 }
1109
1110-void LPEFilletChamfer::toggleHide()
1111-{
1112- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
1113- std::vector<Geom::Point> result;
1114- for (std::vector<Point>::const_iterator point_it = filletChamferData.begin();
1115- point_it != filletChamferData.end(); ++point_it) {
1116- if (hide_knots) {
1117- result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y]) * -1));
1118- } else {
1119- result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y])));
1120- }
1121- }
1122- fillet_chamfer_values.param_set_and_write_new_value(result);
1123- refreshKnots();
1124-}
1125-
1126-void LPEFilletChamfer::toggleFlexFixed()
1127-{
1128- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
1129- std::vector<Geom::Point> result;
1130- unsigned int i = 0;
1131- for (std::vector<Point>::const_iterator point_it = filletChamferData.begin();
1132- point_it != filletChamferData.end(); ++point_it) {
1133- if (flexible) {
1134- result.push_back(Point(fillet_chamfer_values.to_time(i, (*point_it)[X]),
1135- (*point_it)[Y]));
1136- } else {
1137- result.push_back(Point(fillet_chamfer_values.to_len(i, (*point_it)[X]),
1138- (*point_it)[Y]));
1139- }
1140- i++;
1141- }
1142- if (flexible) {
1143- radius.param_set_range(0., 100);
1144- radius.param_set_value(0);
1145- } else {
1146- radius.param_set_range(0., infinity());
1147- radius.param_set_value(0);
1148- }
1149- fillet_chamfer_values.param_set_and_write_new_value(result);
1150-}
1151-
1152-void LPEFilletChamfer::updateFillet()
1153-{
1154- double power = 0;
1155+void LPEFilletChamfer::refreshKnots()
1156+{
1157+ if (satellites_param._knoth) {
1158+ satellites_param._knoth->update_knots();
1159+ }
1160+}
1161+
1162+void LPEFilletChamfer::updateAmount()
1163+{
1164+ setSelected(_pathvector_satellites);
1165+ double power = radius;
1166 if (!flexible) {
1167- power = radius * -1;
1168- } else {
1169- power = radius;
1170- }
1171- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
1172- doUpdateFillet(path_from_piecewise(pwd2, tolerance), power);
1173- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
1174-}
1175-
1176-void LPEFilletChamfer::fillet()
1177-{
1178- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
1179- doChangeType(path_from_piecewise(pwd2, tolerance), 1);
1180- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to fillet"));
1181-}
1182-
1183-void LPEFilletChamfer::inverseFillet()
1184-{
1185- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
1186- doChangeType(path_from_piecewise(pwd2, tolerance), 2);
1187- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet"));
1188-}
1189-
1190-void LPEFilletChamfer::chamferSubdivisions()
1191-{
1192- fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
1193- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
1194- doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 5000);
1195- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
1196-}
1197-
1198-void LPEFilletChamfer::chamfer()
1199-{
1200- fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
1201- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
1202- doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3000);
1203- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to chamfer"));
1204-}
1205-
1206-void LPEFilletChamfer::inverseChamfer()
1207-{
1208- fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
1209- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
1210- doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 4000);
1211- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet"));
1212-}
1213-
1214-void LPEFilletChamfer::refreshKnots()
1215-{
1216- Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
1217- fillet_chamfer_values.recalculate_knots(pwd2);
1218- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1219- if (tools_isactive(desktop, TOOLS_NODES)) {
1220- tools_switch(desktop, TOOLS_SELECT);
1221- tools_switch(desktop, TOOLS_NODES);
1222- }
1223- DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Knots and helper paths refreshed"));
1224-}
1225-
1226-void LPEFilletChamfer::doUpdateFillet(Geom::PathVector const &original_pathv, double power)
1227-{
1228- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
1229- std::vector<Geom::Point> result;
1230- Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv);
1231- int counter = 0;
1232- for (PathVector::const_iterator path_it = original_pathv_processed.begin();
1233- path_it != original_pathv_processed.end(); ++path_it) {
1234- if (path_it->empty())
1235- continue;
1236-
1237- Geom::Path::const_iterator curve_it1 = path_it->begin();
1238- Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
1239- Geom::Path::const_iterator curve_endit = path_it->end_default();
1240- if (path_it->closed() && path_it->back_closed().isDegenerate()) {
1241- const Curve &closingline = path_it->back_closed();
1242- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
1243- curve_endit = path_it->end_open();
1244- }
1245- }
1246- double powerend = 0;
1247- while (curve_it1 != curve_endit) {
1248- powerend = power;
1249- if (power < 0 && !use_knot_distance) {
1250- powerend = fillet_chamfer_values.rad_to_len(counter,powerend);
1251- }
1252- if (power > 0) {
1253- powerend = counter + (power / 100);
1254- }
1255- if (ignore_radius_0 && (filletChamferData[counter][X] == 0 ||
1256- filletChamferData[counter][X] == counter)) {
1257- powerend = filletChamferData[counter][X];
1258- }
1259- if (filletChamferData[counter][Y] == 0) {
1260- powerend = filletChamferData[counter][X];
1261- }
1262- if (only_selected && !isNodePointSelected(curve_it1->initialPoint())) {
1263- powerend = filletChamferData[counter][X];
1264- }
1265- result.push_back(Point(powerend, filletChamferData[counter][Y]));
1266- ++curve_it1;
1267- ++curve_it2;
1268- counter++;
1269- }
1270- }
1271- fillet_chamfer_values.param_set_and_write_new_value(result);
1272-}
1273-
1274-void LPEFilletChamfer::doChangeType(Geom::PathVector const &original_pathv, int type)
1275-{
1276- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
1277- std::vector<Geom::Point> result;
1278- Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv);
1279- int counter = 0;
1280- for (PathVector::const_iterator path_it = original_pathv_processed.begin(); path_it != original_pathv_processed.end(); ++path_it) {
1281- int pathCounter = 0;
1282- if (path_it->empty())
1283- continue;
1284-
1285- Geom::Path::const_iterator curve_it1 = path_it->begin();
1286- Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
1287- Geom::Path::const_iterator curve_endit = path_it->end_default();
1288- if (path_it->closed() && path_it->back_closed().isDegenerate()) {
1289- const Curve &closingline = path_it->back_closed();
1290- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
1291- curve_endit = path_it->end_open();
1292- }
1293- }
1294- while (curve_it1 != curve_endit) {
1295- bool toggle = true;
1296- if (filletChamferData[counter][Y] == 0 ||
1297- (ignore_radius_0 && (filletChamferData[counter][X] == 0 ||
1298- filletChamferData[counter][X] == counter)) ||
1299- (only_selected && !isNodePointSelected(curve_it1->initialPoint()))) {
1300- toggle = false;
1301- }
1302- if (toggle) {
1303- if(type >= 5000){
1304- if(filletChamferData[counter][Y] >= 3000 && filletChamferData[counter][Y] < 4000){
1305- type = type - 2000;
1306- } else if (filletChamferData[counter][Y] >= 4000 && filletChamferData[counter][Y] < 5000){
1307- type = type - 1000;
1308- }
1309- }
1310- result.push_back(Point(filletChamferData[counter][X], type));
1311+ SPDocument * document = SP_ACTIVE_DOCUMENT;
1312+ SPNamedView *nv = sp_document_namedview(document, NULL);
1313+ Glib::ustring display_unit = nv->display_units->abbr;
1314+ power = Inkscape::Util::Quantity::convert(power, unit.get_abbreviation(), display_unit.c_str());
1315+ }
1316+ _pathvector_satellites->updateAmount(power, apply_no_radius, apply_with_radius, only_selected,
1317+ use_knot_distance, flexible);
1318+ satellites_param.setPathVectorSatellites(_pathvector_satellites);
1319+}
1320+
1321+//void LPEFilletChamfer::convertUnit()
1322+//{
1323+// SPDocument * document = SP_ACTIVE_DOCUMENT;
1324+// SPNamedView *nv = sp_document_namedview(document, NULL);
1325+// Glib::ustring display_unit = nv->display_units->abbr;
1326+// _pathvector_satellites->convertUnit(unit.get_abbreviation(), display_unit, apply_no_radius, apply_with_radius);
1327+// satellites_param.setPathVectorSatellites(_pathvector_satellites);
1328+//}
1329+
1330+void LPEFilletChamfer::updateChamferSteps()
1331+{
1332+ setSelected(_pathvector_satellites);
1333+ _pathvector_satellites->updateSteps(chamfer_steps, apply_no_radius, apply_with_radius, only_selected);
1334+ satellites_param.setPathVectorSatellites(_pathvector_satellites);
1335+}
1336+
1337+void LPEFilletChamfer::updateSatelliteType(SatelliteType satellitetype)
1338+{
1339+ setSelected(_pathvector_satellites);
1340+ _pathvector_satellites->updateSatelliteType(satellitetype, apply_no_radius, apply_with_radius, only_selected);
1341+ satellites_param.setPathVectorSatellites(_pathvector_satellites);
1342+}
1343+
1344+void LPEFilletChamfer::setSelected(PathVectorSatellites *_pathvector_satellites){
1345+ Geom::PathVector const pathv = _pathvector_satellites->getPathVector();
1346+ Satellites satellites = _pathvector_satellites->getSatellites();
1347+ for (size_t i = 0; i < satellites.size(); ++i) {
1348+ for (size_t j = 0; j < satellites[i].size(); ++j) {
1349+ Geom::Curve const &curve_in = pathv[i][j];
1350+ if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){
1351+ satellites[i][j].setSelected(true);
1352 } else {
1353- result.push_back(filletChamferData[counter]);
1354- }
1355- ++curve_it1;
1356- if (curve_it2 != curve_endit) {
1357- ++curve_it2;
1358- }
1359- counter++;
1360- pathCounter++;
1361- }
1362- }
1363- fillet_chamfer_values.param_set_and_write_new_value(result);
1364-}
1365-
1366-void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem)
1367-{
1368- if (SP_IS_SHAPE(lpeItem)) {
1369- std::vector<Point> point;
1370- PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeItem)->_curve->get_pathvector());
1371- Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv);
1372- for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) {
1373- if (path_it->empty())
1374- continue;
1375-
1376- Geom::Path::const_iterator curve_it1 = path_it->begin();
1377- Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
1378- Geom::Path::const_iterator curve_endit = path_it->end_default();
1379- if (path_it->closed()) {
1380- const Geom::Curve &closingline = path_it->back_closed();
1381- // the closing line segment is always of type
1382- // Geom::LineSegment.
1383- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
1384- // closingline.isDegenerate() did not work, because it only checks for
1385- // *exact* zero length, which goes wrong for relative coordinates and
1386- // rounding errors...
1387- // the closing line segment has zero-length. So stop before that one!
1388- curve_endit = path_it->end_open();
1389- }
1390- }
1391- int counter = 0;
1392- while (curve_it1 != curve_endit) {
1393- std::pair<std::size_t, std::size_t> positions = fillet_chamfer_values.get_positions(counter, original_pathv);
1394- Geom::NodeType nodetype;
1395- if (positions.second == 0) {
1396- if (path_it->closed()) {
1397- Piecewise<D2<SBasis> > u;
1398- u.push_cut(0);
1399- u.push(pwd2_in[fillet_chamfer_values.last_index(counter, original_pathv)], 1);
1400- Geom::Curve const * A = path_from_piecewise(u, 0.1)[0][0].duplicate();
1401- nodetype = get_nodetype(*A, *curve_it1);
1402- } else {
1403- nodetype = NODE_NONE;
1404- }
1405- } else {
1406- nodetype = get_nodetype((*path_it)[counter - 1], *curve_it1);
1407- }
1408- if (nodetype == NODE_CUSP) {
1409- point.push_back(Point(0, 1));
1410- } else {
1411- point.push_back(Point(0, 0));
1412- }
1413- ++curve_it1;
1414- if (curve_it2 != curve_endit) {
1415- ++curve_it2;
1416- }
1417- counter++;
1418- }
1419- }
1420- fillet_chamfer_values.param_set_and_write_new_value(point);
1421- } else {
1422- g_warning("LPE Fillet can only be applied to shapes (not groups).");
1423- SPLPEItem * item = const_cast<SPLPEItem*>(lpeItem);
1424- item->removeCurrentPathEffect(false);
1425- }
1426+ satellites[i][j].setSelected(false);
1427+ }
1428+ }
1429+ }
1430+ _pathvector_satellites->setSatellites(satellites);
1431 }
1432
1433 void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem)
1434 {
1435- if (SP_IS_SHAPE(lpeItem)) {
1436- if(hide_knots){
1437- fillet_chamfer_values.set_helper_size(0);
1438- } else {
1439- fillet_chamfer_values.set_helper_size(helper_size);
1440- }
1441- fillet_chamfer_values.set_use_distance(use_knot_distance);
1442- SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast<SPPath const *>(lpeItem)
1443- ->get_original_curve()
1444- : SP_SHAPE(lpeItem)->getCurve();
1445- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
1446- if (!filletChamferData.empty() && getKnotsNumber(c) != (int)
1447- filletChamferData.size()) {
1448- PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(c->get_pathvector());
1449- Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv);
1450- fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in);
1451- }
1452+ if (sp_curve) {
1453+ //fillet chamfer specific calls
1454+ satellites_param.setUseDistance(use_knot_distance);
1455+ satellites_param.setCurrentZoom(current_zoom);
1456+ //mandatory call
1457+ satellites_param.setEffectType(effectType());
1458+ Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(sp_curve->get_pathvector());
1459+ //if are diferent sizes call to recalculate
1460+ //TODO: Update the satellite data in paths modified,
1461+ Satellites satellites = satellites_param.data();
1462+ if (satellites.empty()) {
1463+ doOnApply(lpeItem);
1464+ satellites = satellites_param.data();
1465+ }
1466+ if (_pathvector_satellites) {
1467+ size_t number_nodes = pathv.nodes().size();
1468+ size_t previous_number_nodes = _pathvector_satellites->getTotalSatellites();
1469+ if (number_nodes != previous_number_nodes) {
1470+ Satellite satellite(FILLET);
1471+ satellite.setIsTime(flexible);
1472+ satellite.setHasMirror(mirror_knots);
1473+ satellite.setHidden(hide_knots);
1474+ _pathvector_satellites->recalculateForNewPathVector(pathv, satellite);
1475+ satellites = _pathvector_satellites->getSatellites();
1476+ }
1477+ }
1478+ if (_degenerate_hide) {
1479+ satellites_param.setGlobalKnotHide(true);
1480+ } else {
1481+ satellites_param.setGlobalKnotHide(false);
1482+ }
1483+ if (hide_knots) {
1484+ satellites_param.setHelperSize(0);
1485+ } else {
1486+ satellites_param.setHelperSize(helper_size);
1487+ }
1488+ for (size_t i = 0; i < satellites.size(); ++i) {
1489+ for (size_t j = 0; j < satellites[i].size(); ++j) {
1490+ Geom::Curve const &curve_in = pathv[i][j];
1491+ if (satellites[i][j].is_time != flexible) {
1492+ satellites[i][j].is_time = flexible;
1493+ double amount = satellites[i][j].amount;
1494+ if (pathv[i].size() == j) {
1495+ continue;
1496+ }
1497+ if (satellites[i][j].is_time) {
1498+ double time = timeAtArcLength(amount, curve_in);
1499+ satellites[i][j].amount = time;
1500+ } else {
1501+ double size = arcLengthAt(amount, curve_in);
1502+ satellites[i][j].amount = size;
1503+ }
1504+ }
1505+ if (satellites[i][j].has_mirror != mirror_knots) {
1506+ satellites[i][j].has_mirror = mirror_knots;
1507+ }
1508+ satellites[i][j].hidden = hide_knots;
1509+ if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){
1510+ satellites[i][j].setSelected(true);
1511+ }
1512+ }
1513+ }
1514+ if (!_pathvector_satellites) {
1515+ _pathvector_satellites = new PathVectorSatellites();
1516+ }
1517+ _pathvector_satellites->setPathVector(pathv);
1518+ _pathvector_satellites->setSatellites(satellites);
1519+ satellites_param.setPathVectorSatellites(_pathvector_satellites, false);
1520+ refreshKnots();
1521 } else {
1522 g_warning("LPE Fillet can only be applied to shapes (not groups).");
1523 }
1524 }
1525
1526-int LPEFilletChamfer::getKnotsNumber(SPCurve const *c)
1527+void
1528+LPEFilletChamfer::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
1529 {
1530- int nKnots = c->nodes_in_path();
1531- PathVector const pv = pathv_to_linear_and_cubic_beziers(c->get_pathvector());
1532- for (Geom::PathVector::const_iterator path_it = pv.begin();
1533- path_it != pv.end(); ++path_it) {
1534- if (!(*path_it).closed()) {
1535- nKnots--;
1536- }
1537- }
1538- return nKnots;
1539+ hp_vec.push_back(_hp);
1540 }
1541
1542 void
1543-LPEFilletChamfer::adjustForNewPath(Geom::PathVector const &path_in)
1544+LPEFilletChamfer::addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps)
1545 {
1546- if (!path_in.empty()) {
1547- fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb());
1548+ setSelected(_pathvector_satellites);
1549+ double path_subdivision = 1.0 / steps;
1550+ for (size_t i = 1; i < steps; i++) {
1551+ Geom::Point chamfer_step = path_chamfer.pointAt(path_subdivision * i);
1552+ tmp_path.appendNew<Geom::LineSegment>(chamfer_step);
1553 }
1554+ tmp_path.appendNew<Geom::LineSegment>(end_arc_point);
1555 }
1556
1557 Geom::PathVector
1558 LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in)
1559 {
1560- Geom::PathVector pathvector_out;
1561- Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(pathv_to_linear_and_cubic_beziers(path_in));
1562- pwd2_in = remove_short_cuts(pwd2_in, .01);
1563- Piecewise<D2<SBasis> > der = derivative(pwd2_in);
1564- Piecewise<D2<SBasis> > n = rot90(unitVector(der));
1565- fillet_chamfer_values.set_pwd2(pwd2_in, n);
1566- std::vector<Point> filletChamferData = fillet_chamfer_values.data();
1567- unsigned int counter = 0;
1568+ const double GAP_HELPER = 0.00001;
1569+ Geom::PathVector path_out;
1570+ size_t path = 0;
1571 const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0);
1572- Geom::PathVector path_in_processed = pathv_to_linear_and_cubic_beziers(path_in);
1573- for (PathVector::const_iterator path_it = path_in_processed.begin();
1574- path_it != path_in_processed.end(); ++path_it) {
1575- if (path_it->empty())
1576- continue;
1577- Geom::Path path_out;
1578- Geom::Path::const_iterator curve_it1 = path_it->begin();
1579- Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
1580- Geom::Path::const_iterator curve_endit = path_it->end_default();
1581+ _degenerate_hide = false;
1582+ Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(path_in);
1583+ Satellites satellites = _pathvector_satellites->getSatellites();
1584+ for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
1585+ if (path_it->empty()) {
1586+ continue;
1587+ }
1588+ Geom::Path tmp_path;
1589+ if (path_it->size() == 1) {
1590+ path++;
1591+ tmp_path.start(path_it[0].pointAt(0));
1592+ tmp_path.append(path_it[0]);
1593+ path_out.push_back(tmp_path);
1594+ continue;
1595+ }
1596+ double time0 = 0;
1597+ size_t curve = 0;
1598+ for (Geom::Path::const_iterator curve_it1 = path_it->begin(); curve_it1 != path_it->end(); ++curve_it1) {
1599+ size_t next_index = curve + 1;
1600+ if (curve == pathv[path].size() - 1 && pathv[path].closed()) {
1601+ next_index = 0;
1602+ }
1603+ //append last extreme of paths on open paths
1604+ if (curve == pathv[path].size() -1 && !pathv[path].closed()) { //the path is open and we are at end of path
1605+ if (time0 != 1) { //Previous satellite not at 100% amount
1606+ Geom::Curve *last_curve = curve_it1->portion(time0, 1);
1607+ last_curve->setInitial(tmp_path.finalPoint());
1608+ tmp_path.append(*last_curve);
1609+ }
1610+ continue;
1611+ }
1612+ Geom::Curve const &curve_it2 = pathv[path][next_index];
1613+ Satellite satellite = satellites[path][next_index];
1614+ if (Geom::are_near((*curve_it1).initialPoint(), (*curve_it1).finalPoint())) {
1615+ _degenerate_hide = true;
1616+ g_warning("Knots hidded if consecutive nodes has the same position.");
1617+ return path_in;
1618+ }
1619+ if (!curve) { //curve == 0
1620+ if (!path_it->closed()) {
1621+ time0 = 0;
1622+ } else {
1623+ time0 = satellites[path][0].time(*curve_it1);
1624+ }
1625+ }
1626+ double s = satellite.arcDistance(curve_it2);
1627+ double time1 = satellite.time(s, true, (*curve_it1));
1628+ double time2 = satellite.time(curve_it2);
1629+ if (time1 <= time0) {
1630+ time1 = time0;
1631+ }
1632+ if (time2 > 1) {
1633+ time2 = 1;
1634+ }
1635+ Geom::Curve *knot_curve_1 = curve_it1->portion(time0, time1);
1636+ Geom::Curve *knot_curve_2 = curve_it2.portion(time2, 1);
1637+ if (curve > 0) {
1638+ knot_curve_1->setInitial(tmp_path.finalPoint());
1639+ } else {
1640+ tmp_path.start((*curve_it1).pointAt(time0));
1641+ }
1642+
1643+ Geom::Point start_arc_point = knot_curve_1->finalPoint();
1644+ Geom::Point end_arc_point = curve_it2.pointAt(time2);
1645+ //add a gap helper
1646+ if (time2 == 1) {
1647+ end_arc_point = curve_it2.pointAt(time2 - GAP_HELPER);
1648+ }
1649+ if (time1 == time0) {
1650+ start_arc_point = curve_it1->pointAt(time1 + GAP_HELPER);
1651+ }
1652+
1653+ double k1 = distance(start_arc_point, curve_it1->finalPoint()) * K;
1654+ double k2 = distance(curve_it2.initialPoint(), end_arc_point) * K;
1655+ Geom::CubicBezier const *cubic_1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_1);
1656+ Geom::CubicBezier const *cubic_2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_2);
1657+ Geom::Ray ray_1(start_arc_point, curve_it1->finalPoint());
1658+ Geom::Ray ray_2(curve_it2.initialPoint(), end_arc_point);
1659+ if (cubic_1) {
1660+ ray_1.setPoints((*cubic_1)[2], start_arc_point);
1661+ }
1662+ if (cubic_2) {
1663+ ray_2.setPoints(end_arc_point, (*cubic_2)[1]);
1664+ }
1665+ bool ccw_toggle = cross(curve_it1->finalPoint() - start_arc_point, end_arc_point - start_arc_point) < 0;
1666+ double angle = angle_between(ray_1, ray_2, ccw_toggle);
1667+ double handle_angle_1 = ray_1.angle() - angle;
1668+ double handle_angle_2 = ray_2.angle() + angle;
1669+ if (ccw_toggle) {
1670+ handle_angle_1 = ray_1.angle() + angle;
1671+ handle_angle_2 = ray_2.angle() - angle;
1672+ }
1673+ Geom::Point handle_1 = Geom::Point::polar(ray_1.angle(), k1) + start_arc_point;
1674+ Geom::Point handle_2 = end_arc_point - Geom::Point::polar(ray_2.angle(), k2);
1675+ Geom::Point inverse_handle_1 = Geom::Point::polar(handle_angle_1, k1) + start_arc_point;
1676+ Geom::Point inverse_handle_2 = end_arc_point - Geom::Point::polar(handle_angle_2, k2);
1677+ if (time0 == 1) {
1678+ handle_1 = start_arc_point;
1679+ inverse_handle_1 = start_arc_point;
1680+ }
1681+ //remove gap helper
1682+ if (time2 == 1) {
1683+ end_arc_point = curve_it2.pointAt(time2);
1684+ }
1685+ if (time1 == time0) {
1686+ start_arc_point = curve_it1->pointAt(time0);
1687+ }
1688+ if (time1 != 1) {
1689+ if (time1 != time0 || (time1 == 1 && time0 == 1)) {
1690+ if (!knot_curve_1->isDegenerate()) {
1691+ tmp_path.append(*knot_curve_1);
1692+ }
1693+ }
1694+ SatelliteType type = satellite.satellite_type;
1695+ size_t steps = satellite.steps;
1696+ if (!steps) steps = 1;
1697+ Geom::Line const x_line(Geom::Point(0, 0), Geom::Point(1, 0));
1698+ Geom::Line const angled_line(start_arc_point, end_arc_point);
1699+ double arc_angle = Geom::angle_between(x_line, angled_line);
1700+ double radius = Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point)) /
1701+ sin(angle / 2.0);
1702+ Geom::Coord rx = radius;
1703+ Geom::Coord ry = rx;
1704+ bool eliptical = (is_straight_curve(*curve_it1) &&
1705+ is_straight_curve(curve_it2) && method != FM_BEZIER) ||
1706+ method == FM_ARC;
1707+ switch (type) {
1708+ case CHAMFER:
1709+ {
1710+ Geom::Path path_chamfer;
1711+ path_chamfer.start(tmp_path.finalPoint());
1712+ if (eliptical) {
1713+ ccw_toggle = ccw_toggle ? 0 : 1;
1714+ path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
1715+ } else {
1716+ path_chamfer.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point);
1717+ }
1718+ addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps);
1719+ }
1720+ break;
1721+ case INVERSE_CHAMFER:
1722+ {
1723+ Geom::Path path_chamfer;
1724+ path_chamfer.start(tmp_path.finalPoint());
1725+ if (eliptical) {
1726+ path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
1727+ } else {
1728+ path_chamfer.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point);
1729+ }
1730+ addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps);
1731+ }
1732+ break;
1733+ case INVERSE_FILLET:
1734+ {
1735+ if (eliptical) {
1736+ tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
1737+ } else {
1738+ tmp_path.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point);
1739+ }
1740+ }
1741+ break;
1742+ default: //fillet
1743+ {
1744+ if (eliptical) {
1745+ ccw_toggle = ccw_toggle ? 0 : 1;
1746+ tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
1747+ } else {
1748+ tmp_path.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point);
1749+ }
1750+ }
1751+ break;
1752+ }
1753+ } else {
1754+ if (!knot_curve_1->isDegenerate()) {
1755+ tmp_path.append(*knot_curve_1);
1756+ }
1757+ }
1758+ curve++;
1759+ time0 = time2;
1760+ }
1761 if (path_it->closed()) {
1762- const Geom::Curve &closingline = path_it->back_closed();
1763- // the closing line segment is always of type
1764- // Geom::LineSegment.
1765- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
1766- // closingline.isDegenerate() did not work, because it only checks for
1767- // *exact* zero length, which goes wrong for relative coordinates and
1768- // rounding errors...
1769- // the closing line segment has zero-length. So stop before that one!
1770- curve_endit = path_it->end_open();
1771- }
1772- }
1773- unsigned int counterCurves = 0;
1774- while (curve_it1 != curve_endit) {
1775- Curve *curve_it2Fixed = (*path_it->begin()).duplicate();
1776- if(!path_it->closed() || curve_it2 != curve_endit){
1777- curve_it2Fixed = (*curve_it2).duplicate();
1778- }
1779- bool last = curve_it2 == curve_endit;
1780- std::vector<double> times = fillet_chamfer_values.get_times(counter, path_in, last);
1781- Curve *knotCurve1 = curve_it1->portion(times[0], times[1]);
1782- if (counterCurves > 0) {
1783- knotCurve1->setInitial(path_out.finalPoint());
1784- } else {
1785- path_out.start((*curve_it1).pointAt(times[0]));
1786- }
1787- Curve *knotCurve2 = curve_it2Fixed->portion(times[2], 1);
1788- Point startArcPoint = knotCurve1->finalPoint();
1789- Point endArcPoint = curve_it2Fixed->pointAt(times[2]);
1790- double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K;
1791- double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K;
1792- Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1);
1793- Ray ray1(startArcPoint, curve_it1->finalPoint());
1794- if (cubic1) {
1795- ray1.setPoints((*cubic1)[2], startArcPoint);
1796- }
1797- Point handle1 = Point::polar(ray1.angle(),k1) + startArcPoint;
1798- Geom::CubicBezier const *cubic2 =
1799- dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2);
1800- Ray ray2(curve_it1->finalPoint(), endArcPoint);
1801- if (cubic2) {
1802- ray2.setPoints(endArcPoint, (*cubic2)[1]);
1803- }
1804- Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2);
1805- bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0;
1806- double angle = angle_between(ray1, ray2, ccwToggle);
1807- double handleAngle = ray1.angle() - angle;
1808- if (ccwToggle) {
1809- handleAngle = ray1.angle() + angle;
1810- }
1811- Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint;
1812- handleAngle = ray2.angle() + angle;
1813- if (ccwToggle) {
1814- handleAngle = ray2.angle() - angle;
1815- }
1816- Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2);
1817- //straigth lines arc based
1818- Line const x_line(Geom::Point(0,0),Geom::Point(1,0));
1819- Line const angled_line(startArcPoint,endArcPoint);
1820- double angleArc = Geom::angle_between( x_line,angled_line);
1821- double radius = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint))/sin(angle/2.0);
1822- Coord rx = radius;
1823- Coord ry = rx;
1824-
1825- if (times[1] != 1) {
1826- if (times[1] != gapHelper && times[1] != times[0] + gapHelper) {
1827- path_out.append(*knotCurve1);
1828- }
1829- int type = 0;
1830- if(path_it->closed() && last){
1831- type = std::abs(filletChamferData[counter - counterCurves][Y]);
1832- } else if (!path_it->closed() && last){
1833- //0
1834- } else {
1835- type = std::abs(filletChamferData[counter + 1][Y]);
1836- }
1837- if(are_near(middle_point(startArcPoint,endArcPoint),curve_it1->finalPoint(), 0.0001)){
1838- path_out.appendNew<Geom::LineSegment>(endArcPoint);
1839- } else if (type >= 3000 && type < 4000) {
1840- unsigned int chamferSubs = type-3000;
1841- Geom::Path path_chamfer;
1842- path_chamfer.start(path_out.finalPoint());
1843- if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
1844- path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
1845- } else {
1846- path_chamfer.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint);
1847- }
1848- double chamfer_stepsTime = 1.0/chamferSubs;
1849- for(unsigned int i = 1; i < chamferSubs; i++){
1850- Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i);
1851- path_out.appendNew<Geom::LineSegment>(chamferStep);
1852- }
1853- path_out.appendNew<Geom::LineSegment>(endArcPoint);
1854- } else if (type >= 4000 && type < 5000) {
1855- unsigned int chamferSubs = type-4000;
1856- Geom::Path path_chamfer;
1857- path_chamfer.start(path_out.finalPoint());
1858- if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
1859- ccwToggle = ccwToggle?0:1;
1860- path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
1861- }else{
1862- path_chamfer.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint);
1863- }
1864- double chamfer_stepsTime = 1.0/chamferSubs;
1865- for(unsigned int i = 1; i < chamferSubs; i++){
1866- Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i);
1867- path_out.appendNew<Geom::LineSegment>(chamferStep);
1868- }
1869- path_out.appendNew<Geom::LineSegment>(endArcPoint);
1870- } else if (type == 2) {
1871- if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
1872- ccwToggle = ccwToggle?0:1;
1873- path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
1874- }else{
1875- path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint);
1876- }
1877- } else if (type == 1){
1878- if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
1879- path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
1880- } else {
1881- path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint);
1882- }
1883- }
1884- } else {
1885- path_out.append(*knotCurve1);
1886- }
1887- if (path_it->closed() && last) {
1888- path_out.close();
1889- }
1890- ++curve_it1;
1891- if (curve_it2 != curve_endit) {
1892- ++curve_it2;
1893- }
1894- counter++;
1895- counterCurves++;
1896- }
1897- pathvector_out.push_back(path_out);
1898+ tmp_path.close();
1899+ }
1900+ path++;
1901+ path_out.push_back(tmp_path);
1902 }
1903- return pathvector_out;
1904+ return path_out;
1905 }
1906
1907 }; //namespace LivePathEffect
1908
1909=== modified file 'src/live_effects/lpe-fillet-chamfer.h'
1910--- src/live_effects/lpe-fillet-chamfer.h 2015-07-24 18:50:50 +0000
1911+++ src/live_effects/lpe-fillet-chamfer.h 2017-05-06 17:46:29 +0000
1912@@ -7,25 +7,22 @@
1913 *
1914 * Copyright (C) 2014 Author(s)
1915 *
1916- * Special thanks to Johan Engelen for the base of the effect -powerstroke-
1917- * Also to ScislaC for point me to the idea
1918- * Also su_v for his construvtive feedback and time
1919- * and finaly to Liam P. White for his big help on coding, that save me a lot of hours
1920+ * Jabiertxof:Thanks to all people help me
1921 *
1922 * Released under GNU GPL, read the file 'COPYING' for more information
1923 */
1924
1925 #include "live_effects/parameter/enum.h"
1926-#include "live_effects/parameter/bool.h"
1927+#include "live_effects/parameter/satellitesarray.h"
1928+#include "live_effects/effect.h"
1929 #include "live_effects/parameter/unit.h"
1930-
1931-#include "live_effects/parameter/filletchamferpointarray.h"
1932-#include "live_effects/effect.h"
1933+#include "helper/geom-pathvectorsatellites.h"
1934+#include "helper/geom-satellite.h"
1935
1936 namespace Inkscape {
1937 namespace LivePathEffect {
1938
1939-enum FilletMethod {
1940+enum Filletmethod {
1941 FM_AUTO,
1942 FM_ARC,
1943 FM_BEZIER,
1944@@ -35,41 +32,38 @@
1945 class LPEFilletChamfer : public Effect {
1946 public:
1947 LPEFilletChamfer(LivePathEffectObject *lpeobject);
1948- virtual ~LPEFilletChamfer();
1949-
1950+ virtual void doBeforeEffect(SPLPEItem const *lpeItem);
1951 virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in);
1952-
1953 virtual void doOnApply(SPLPEItem const *lpeItem);
1954- virtual void doBeforeEffect(SPLPEItem const *lpeItem);
1955- virtual void adjustForNewPath(Geom::PathVector const &path_in);
1956- virtual Gtk::Widget* newWidget();
1957-
1958- int getKnotsNumber(SPCurve const *c);
1959- void toggleHide();
1960- void toggleFlexFixed();
1961- void chamfer();
1962- void chamferSubdivisions();
1963- void inverseChamfer();
1964- void fillet();
1965- void inverseFillet();
1966- void updateFillet();
1967- void doUpdateFillet(Geom::PathVector const& original_pathv, double power);
1968- void doChangeType(Geom::PathVector const& original_pathv, int type);
1969+ virtual Gtk::Widget *newWidget();
1970+ Geom::Ray getRay(Geom::Point start, Geom::Point end, Geom::Curve *curve, bool reverse);
1971+ void addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps);
1972+ void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
1973+ void updateSatelliteType(SatelliteType satellitetype);
1974+ void setSelected(PathVectorSatellites *_pathvector_satellites);
1975+ //void convertUnit();
1976+ void updateChamferSteps();
1977+ void updateAmount();
1978 void refreshKnots();
1979
1980- FilletChamferPointArrayParam fillet_chamfer_values;
1981+ SatellitesArrayParam satellites_param;
1982
1983 private:
1984-
1985- BoolParam hide_knots;
1986- BoolParam ignore_radius_0;
1987+ UnitParam unit;
1988+ EnumParam<Filletmethod> method;
1989+ ScalarParam radius;
1990+ ScalarParam chamfer_steps;
1991+ BoolParam flexible;
1992+ BoolParam mirror_knots;
1993 BoolParam only_selected;
1994- BoolParam flexible;
1995 BoolParam use_knot_distance;
1996- EnumParam<FilletMethod> method;
1997- ScalarParam radius;
1998- ScalarParam chamfer_steps;
1999+ BoolParam hide_knots;
2000+ BoolParam apply_no_radius;
2001+ BoolParam apply_with_radius;
2002 ScalarParam helper_size;
2003+ bool _degenerate_hide;
2004+ PathVectorSatellites *_pathvector_satellites;
2005+ Geom::PathVector _hp;
2006
2007 LPEFilletChamfer(const LPEFilletChamfer &);
2008 LPEFilletChamfer &operator=(const LPEFilletChamfer &);
2009
2010=== modified file 'src/live_effects/parameter/array.cpp'
2011--- src/live_effects/parameter/array.cpp 2014-03-27 01:33:44 +0000
2012+++ src/live_effects/parameter/array.cpp 2017-05-06 17:46:29 +0000
2013@@ -5,10 +5,7 @@
2014 */
2015
2016 #include "live_effects/parameter/array.h"
2017-
2018-#include "svg/svg.h"
2019-#include "svg/stringstream.h"
2020-
2021+#include "helper-fns.h"
2022 #include <2geom/coord.h>
2023 #include <2geom/point.h>
2024
2025@@ -49,6 +46,45 @@
2026 return Geom::Point(Geom::infinity(),Geom::infinity());
2027 }
2028
2029+
2030+template <>
2031+std::vector<Satellite>
2032+ArrayParam<std::vector<Satellite > >::readsvg(const gchar * str)
2033+{
2034+ std::vector<Satellite> subpath_satellites;
2035+ if (!str) {
2036+ return subpath_satellites;
2037+ }
2038+ gchar ** strarray = g_strsplit(str, "@", 0);
2039+ gchar ** iter = strarray;
2040+ while (*iter != NULL) {
2041+ gchar ** strsubarray = g_strsplit(*iter, ",", 8);
2042+ if (*strsubarray[7]) {//steps always > 0
2043+ Satellite *satellite = new Satellite();
2044+ satellite->setSatelliteType(g_strstrip(strsubarray[0]));
2045+ satellite->is_time = strncmp(strsubarray[1],"1",1) == 0;
2046+ satellite->selected = strncmp(strsubarray[2],"1",1) == 0;
2047+ satellite->has_mirror = strncmp(strsubarray[3],"1",1) == 0;
2048+ satellite->hidden = strncmp(strsubarray[4],"1",1) == 0;
2049+ double amount,angle;
2050+ float stepsTmp;
2051+ sp_svg_number_read_d(strsubarray[5], &amount);
2052+ sp_svg_number_read_d(strsubarray[6], &angle);
2053+ sp_svg_number_read_f(g_strstrip(strsubarray[7]), &stepsTmp);
2054+ unsigned int steps = (unsigned int)stepsTmp;
2055+ satellite->amount = amount;
2056+ satellite->angle = angle;
2057+ satellite->steps = steps;
2058+ subpath_satellites.push_back(*satellite);
2059+ }
2060+ g_strfreev (strsubarray);
2061+ iter++;
2062+ }
2063+ g_strfreev (strarray);
2064+ return subpath_satellites;
2065+}
2066+
2067+
2068 } /* namespace LivePathEffect */
2069
2070 } /* namespace Inkscape */
2071
2072=== modified file 'src/live_effects/parameter/array.h'
2073--- src/live_effects/parameter/array.h 2017-04-29 00:01:22 +0000
2074+++ src/live_effects/parameter/array.h 2017-05-06 17:46:29 +0000
2075@@ -15,6 +15,7 @@
2076
2077 #include "live_effects/parameter/parameter.h"
2078
2079+#include "helper/geom-satellite.h"
2080 #include "svg/svg.h"
2081 #include "svg/stringstream.h"
2082
2083@@ -93,7 +94,43 @@
2084 // separate items with pipe symbol
2085 str << " | ";
2086 }
2087- str << vector[i];
2088+ writesvgData(str,vector[i]);
2089+ }
2090+ }
2091+
2092+ void writesvgData(SVGOStringStream &str, float const &vector_data) const {
2093+ str << vector_data;
2094+ }
2095+
2096+ void writesvgData(SVGOStringStream &str, double const &vector_data) const {
2097+ str << vector_data;
2098+ }
2099+
2100+ void writesvgData(SVGOStringStream &str, Geom::Point const &vector_data) const {
2101+ str << vector_data;
2102+ }
2103+
2104+ void writesvgData(SVGOStringStream &str, std::vector<Satellite> const &vector_data) const {
2105+ for (size_t i = 0; i < vector_data.size(); ++i) {
2106+ if (i != 0) {
2107+ // separate items with @ symbol ¿Any other?
2108+ str << " @ ";
2109+ }
2110+ str << vector_data[i].getSatelliteTypeGchar();
2111+ str << ",";
2112+ str << vector_data[i].is_time;
2113+ str << ",";
2114+ str << vector_data[i].selected;
2115+ str << ",";
2116+ str << vector_data[i].has_mirror;
2117+ str << ",";
2118+ str << vector_data[i].hidden;
2119+ str << ",";
2120+ str << vector_data[i].amount;
2121+ str << ",";
2122+ str << vector_data[i].angle;
2123+ str << ",";
2124+ str << vector_data[i].steps;
2125 }
2126 }
2127
2128
2129=== removed file 'src/live_effects/parameter/filletchamferpointarray.cpp'
2130--- src/live_effects/parameter/filletchamferpointarray.cpp 2016-12-19 20:54:42 +0000
2131+++ src/live_effects/parameter/filletchamferpointarray.cpp 1970-01-01 00:00:00 +0000
2132@@ -1,873 +0,0 @@
2133-/*
2134- * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
2135- * Special thanks to Johan Engelen for the base of the effect -powerstroke-
2136- * Also to ScislaC for point me to the idea
2137- * Also su_v for his construvtive feedback and time
2138- * and finaly to Liam P. White for his big help on coding, that save me a lot of
2139- * hours
2140- * Released under GNU GPL, read the file 'COPYING' for more information
2141- */
2142-
2143-#include <2geom/piecewise.h>
2144-#include <2geom/sbasis-to-bezier.h>
2145-#include <2geom/sbasis-geometric.h>
2146-#include <2geom/line.h>
2147-#include <2geom/path-intersection.h>
2148-
2149-#include "ui/dialog/lpe-fillet-chamfer-properties.h"
2150-#include "live_effects/parameter/filletchamferpointarray.h"
2151-#include "live_effects/effect.h"
2152-#include "svg/svg.h"
2153-#include "svg/stringstream.h"
2154-#include "knotholder.h"
2155-#include "sp-lpe-item.h"
2156-#include "selection.h"
2157-
2158-// needed for on-canvas editting:
2159-#include "live_effects/lpeobject.h"
2160-#include "helper/geom-nodetype.h"
2161-#include "helper/geom-curves.h"
2162-#include "ui/tools/node-tool.h"
2163-
2164-// TODO due to internal breakage in glibmm headers,
2165-// this has to be included last.
2166-#include <glibmm/i18n.h>
2167-
2168-
2169-using namespace Geom;
2170-
2171-namespace Inkscape {
2172-
2173-namespace LivePathEffect {
2174-
2175-FilletChamferPointArrayParam::FilletChamferPointArrayParam(
2176- const Glib::ustring &label, const Glib::ustring &tip,
2177- const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr,
2178- Effect *effect)
2179- : ArrayParam<Point>(label, tip, key, wr, effect, 0)
2180-{
2181- knot_shape = SP_KNOT_SHAPE_DIAMOND;
2182- knot_mode = SP_KNOT_MODE_XOR;
2183- knot_color = 0x00ff0000;
2184-}
2185-
2186-FilletChamferPointArrayParam::~FilletChamferPointArrayParam() {}
2187-
2188-Gtk::Widget *FilletChamferPointArrayParam::param_newWidget()
2189-{
2190- return NULL;
2191- /*
2192- Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg =
2193- Gtk::manage(
2194- new Inkscape::UI::Widget::RegisteredTransformedPoint(
2195- param_label,
2196- param_tooltip,
2197- param_key,
2198- *param_wr,
2199- param_effect->getRepr(),
2200- param_effect->getSPDoc()
2201- ) );
2202- // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP)
2203- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
2204- Affine transf = desktop->doc2dt();
2205- pointwdg->setTransform(transf);
2206- pointwdg->setValue( *this );
2207- pointwdg->clearProgrammatically();
2208- pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT,
2209- _("Change point parameter"));
2210-
2211- Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() );
2212- static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true);
2213- static_cast<Gtk::HBox*>(hbox)->show_all_children();
2214-
2215- return dynamic_cast<Gtk::Widget *> (hbox);
2216- */
2217-}
2218-
2219-void
2220-FilletChamferPointArrayParam::param_transform_multiply(Affine const &postmul,
2221- bool /*set*/)
2222-{
2223- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2224-
2225- if (prefs->getBool("/options/transform/rectcorners", true) &&
2226- _vector[1][X] <= 0) {
2227- std::vector<Geom::Point> result;
2228- for (std::vector<Point>::const_iterator point_it = _vector.begin();
2229- point_it != _vector.end(); ++point_it) {
2230- Coord A =
2231- (*point_it)[X] * ((postmul.expansionX() + postmul.expansionY()) / 2);
2232- result.push_back(Point(A, (*point_it)[Y]));
2233- }
2234- param_set_and_write_new_value(result);
2235- }
2236-
2237- // param_set_and_write_new_value( (*this) * postmul );
2238-}
2239-
2240-/** call this method to recalculate the controlpoints such that they stay at the
2241- * same location relative to the new path. Useful after adding/deleting nodes to
2242- * the path.*/
2243-void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2(
2244- Piecewise<D2<SBasis> > const &pwd2_in)
2245-{
2246- if (!last_pwd2.empty()) {
2247- PathVector const pathv =
2248- path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001);
2249- PathVector last_pathv =
2250- path_from_piecewise(remove_short_cuts(last_pwd2, 0.1), 0.001);
2251- std::vector<Point> result;
2252- unsigned long counter = 0;
2253- unsigned long counterPaths = 0;
2254- unsigned long counterCurves = 0;
2255- long offset = 0;
2256- long offsetPaths = 0;
2257- Geom::NodeType nodetype;
2258- for (PathVector::const_iterator path_it = pathv.begin();
2259- path_it != pathv.end(); ++path_it) {
2260- if (path_it->empty()) {
2261- counterPaths++;
2262- counter++;
2263- continue;
2264- }
2265- Geom::Path::const_iterator curve_it1 = path_it->begin();
2266- Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
2267- Geom::Path::const_iterator curve_endit = path_it->end_default();
2268- if (path_it->closed() && path_it->back_closed().isDegenerate()) {
2269- const Curve &closingline = path_it->back_closed();
2270- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
2271- curve_endit = path_it->end_open();
2272- }
2273- }
2274- counterCurves = 0;
2275- while (curve_it1 != curve_endit) {
2276- //if start a path get node type
2277- if (counterCurves == 0) {
2278- if (path_it->closed()) {
2279- if (path_it->back_closed().isDegenerate()) {
2280- nodetype = get_nodetype(path_it->back_open(), *curve_it1);
2281- } else {
2282- nodetype = get_nodetype(path_it->back_closed(), *curve_it1);
2283- }
2284- } else {
2285- nodetype = NODE_NONE;
2286- }
2287- } else {
2288- //check node type also whith straight lines because get_nodetype
2289- //return non cusp node in a node inserted inside a straight line
2290- //todo: if the path remove some nodes whith the result of a straight
2291- //line but with handles, the node inserted into dont fire the knot
2292- // because is not handle as cusp node by get_nodetype function
2293- bool next_is_line = is_straight_curve(*curve_it1);
2294- bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
2295- nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
2296- if (this_is_line || next_is_line) {
2297- nodetype = NODE_CUSP;
2298- }
2299- }
2300- if (last_pathv.size() > pathv.size() ||
2301- (last_pathv.size() > counterPaths &&
2302- last_pathv[counterPaths].size() > counter - offset &&
2303- !are_near(curve_it1->initialPoint(),
2304- last_pathv[counterPaths][counter - offset].initialPoint(),
2305- 0.1))) {
2306- if ( curve_it2 == curve_endit) {
2307- if (last_pathv[counterPaths].size() != pathv[counterPaths].size()) {
2308- offset = (last_pathv[counterPaths].size() - pathv[counterPaths].size()) * -1;
2309- } else {
2310- offset = 0;
2311- }
2312- offsetPaths += offset;
2313- offset = offsetPaths;
2314- } else if (counterCurves == 0 && last_pathv.size() <= pathv.size() &&
2315- counter - offset <= last_pathv[counterPaths].size() &&
2316- are_near(curve_it1->initialPoint(),
2317- last_pathv[counterPaths].finalPoint(), 0.1) &&
2318- !last_pathv[counterPaths].closed()) {
2319- long e = counter - offset + 1;
2320- std::vector<Point> tmp = _vector;
2321- for (unsigned long i =
2322- last_pathv[counterPaths].size() + counter - offset;
2323- i > counterCurves - offset + 1; i--) {
2324-
2325- if (tmp[i - 1][X] > 0) {
2326- double fractpart, intpart;
2327- fractpart = modf(tmp[i - 1][X], &intpart);
2328- _vector[e] = Point(e + fractpart, tmp[i - 1][Y]);
2329- } else {
2330- _vector[e] = Point(tmp[i - 1][X], tmp[i - 1][Y]);
2331- }
2332- e++;
2333- }
2334- //delete temp vector
2335- std::vector<Point>().swap(tmp);
2336- if (last_pathv.size() > counterPaths) {
2337- last_pathv[counterPaths] = last_pathv[counterPaths].reversed();
2338- }
2339- } else {
2340- if (last_pathv.size() > counterPaths) {
2341- if (last_pathv[counterPaths].size() <
2342- pathv[counterPaths].size()) {
2343- offset++;
2344- } else if (last_pathv[counterPaths].size() >
2345- pathv[counterPaths].size()) {
2346- offset--;
2347- continue;
2348- }
2349- } else {
2350- offset++;
2351- }
2352- }
2353- double xPos = 0;
2354- if (_vector[1][X] > 0) {
2355- xPos = nearest_time(curve_it1->initialPoint(), pwd2_in);
2356- }
2357- if (nodetype == NODE_CUSP) {
2358- result.push_back(Point(xPos, 1));
2359- } else {
2360- result.push_back(Point(xPos, 0));
2361- }
2362- } else {
2363- double xPos = _vector[counter - offset][X];
2364- if (_vector.size() <= (unsigned)(counter - offset)) {
2365- if (_vector[1][X] > 0) {
2366- xPos = nearest_time(curve_it1->initialPoint(), pwd2_in);
2367- } else {
2368- xPos = 0;
2369- }
2370- }
2371- if (nodetype == NODE_CUSP) {
2372- double vectorY = _vector[counter - offset][Y];
2373- if (_vector.size() <= (unsigned)(counter - offset) || vectorY == 0) {
2374- vectorY = 1;
2375- }
2376- result.push_back(Point(xPos, vectorY));
2377- } else {
2378- if (_vector[1][X] < 0) {
2379- xPos = 0;
2380- }
2381- result.push_back(Point(floor(xPos), 0));
2382- }
2383- }
2384- ++curve_it1;
2385- if (curve_it2 != curve_endit) {
2386- ++curve_it2;
2387- }
2388- counter++;
2389- counterCurves++;
2390- }
2391- counterPaths++;
2392- }
2393- _vector = result;
2394- write_to_SVG();
2395- }
2396-}
2397-
2398-void FilletChamferPointArrayParam::recalculate_knots(
2399- Piecewise<D2<SBasis> > const &pwd2_in)
2400-{
2401- bool change = false;
2402- if(_vector.size() == 0){
2403- return;
2404- }
2405- PathVector pathv = path_from_piecewise(pwd2_in, 0.001);
2406- if (!pathv.empty()) {
2407- std::vector<Point> result;
2408- int counter = 0;
2409- int counterCurves = 0;
2410- Geom::NodeType nodetype;
2411- for (PathVector::const_iterator path_it = pathv.begin();
2412- path_it != pathv.end(); ++path_it) {
2413- if (path_it->empty()) {
2414- counter++;
2415- continue;
2416- }
2417- Geom::Path::const_iterator curve_it1 = path_it->begin();
2418- Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
2419- Geom::Path::const_iterator curve_endit = path_it->end_default();
2420- if (path_it->closed() && path_it->back_closed().isDegenerate()) {
2421- const Curve &closingline = path_it->back_closed();
2422- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
2423- curve_endit = path_it->end_open();
2424- }
2425- }
2426- counterCurves = 0;
2427- while (curve_it1 != curve_endit) {
2428- //if start a path get node type
2429- if (counterCurves == 0) {
2430- if (path_it->closed()) {
2431- if (path_it->back_closed().isDegenerate()) {
2432- nodetype = get_nodetype(path_it->back_open(), *curve_it1);
2433- } else {
2434- nodetype = get_nodetype(path_it->back_closed(), *curve_it1);
2435- }
2436- } else {
2437- nodetype = NODE_NONE;
2438- }
2439- } else {
2440- bool next_is_line = is_straight_curve(*curve_it1);
2441- bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
2442- nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
2443- if (this_is_line || next_is_line) {
2444- nodetype = NODE_CUSP;
2445- }
2446- }
2447- if (nodetype == NODE_CUSP) {
2448- double vectorY = _vector[counter][Y];
2449- if (vectorY == 0) {
2450- vectorY = 1;
2451- change = true;
2452- }
2453- result.push_back(Point(_vector[counter][X], vectorY));
2454- } else {
2455- double xPos = floor(_vector[counter][X]);
2456- if (_vector[1][X] < 0) {
2457- xPos = 0;
2458- }
2459- double vectorY = _vector[counter][Y];
2460- if (vectorY != 0) {
2461- change = true;
2462- }
2463- result.push_back(Point(xPos, 0));
2464- }
2465- ++curve_it1;
2466- counter++;
2467- if (curve_it2 != curve_endit) {
2468- ++curve_it2;
2469- }
2470- counterCurves++;
2471- }
2472- }
2473- if (change) {
2474- _vector = result;
2475- write_to_SVG();
2476- }
2477- }
2478-}
2479-
2480-void FilletChamferPointArrayParam::set_pwd2(
2481- Piecewise<D2<SBasis> > const &pwd2_in,
2482- Piecewise<D2<SBasis> > const &pwd2_normal_in)
2483-{
2484- last_pwd2 = pwd2_in;
2485- last_pwd2_normal = pwd2_normal_in;
2486-}
2487-
2488-void FilletChamferPointArrayParam::set_helper_size(int hs)
2489-{
2490- helper_size = hs;
2491-}
2492-
2493-void FilletChamferPointArrayParam::set_chamfer_steps(int value_chamfer_steps)
2494-{
2495- chamfer_steps = value_chamfer_steps;
2496-}
2497-
2498-void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance )
2499-{
2500- use_distance = use_knot_distance;
2501-}
2502-
2503-void FilletChamferPointArrayParam::updateCanvasIndicators()
2504-{
2505- std::vector<Point> ts = data();
2506- hp.clear();
2507- unsigned int i = 0;
2508- for (std::vector<Point>::const_iterator point_it = ts.begin();
2509- point_it != ts.end(); ++point_it) {
2510- double Xvalue = to_time(i, (*point_it)[X]) -i;
2511- if (Xvalue == 0) {
2512- i++;
2513- continue;
2514- }
2515- Geom::Point ptA = last_pwd2[i].valueAt(Xvalue);
2516- Geom::Point derivA = unit_vector(derivative(last_pwd2[i]).valueAt(Xvalue));
2517- Geom::Rotate rot(Geom::Rotate::from_degrees(-90));
2518- derivA = derivA * rot;
2519- Geom::Point C = ptA - derivA * helper_size;
2520- Geom::Point D = ptA + derivA * helper_size;
2521- Geom::Ray ray1(C, D);
2522- char const * svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5";
2523- Geom::PathVector pathv = sp_svg_read_pathv(svgd);
2524- Geom::Affine aff = Geom::Affine();
2525- aff *= Geom::Scale(helper_size);
2526- aff *= Geom::Rotate(ray1.angle() - rad_from_deg(270));
2527- aff *= Geom::Translate(last_pwd2[i].valueAt(Xvalue));
2528- pathv *= aff;
2529- hp.push_back(pathv[0]);
2530- hp.push_back(pathv[1]);
2531- i++;
2532- }
2533-}
2534-
2535-void FilletChamferPointArrayParam::addCanvasIndicators(
2536- SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
2537-{
2538- hp_vec.push_back(hp);
2539-}
2540-
2541-double FilletChamferPointArrayParam::rad_to_len(int index, double rad)
2542-{
2543- double len = 0;
2544- Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1);
2545- std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
2546- D2<SBasis> A = last_pwd2[last_index(index, subpaths)];
2547- if(positions.second != 0){
2548- A = last_pwd2[index-1];
2549- }else{
2550- if(!subpaths[positions.first].closed()){
2551- return len;
2552- }
2553- }
2554- D2<SBasis> B = last_pwd2[index];
2555- Piecewise<D2<SBasis> > offset_curve0 = Piecewise<D2<SBasis> >(A)+rot90(unitVector(derivative(A)))*(rad);
2556- Piecewise<D2<SBasis> > offset_curve1 = Piecewise<D2<SBasis> >(B)+rot90(unitVector(derivative(B)))*(rad);
2557- Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0];
2558- Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0];
2559- Geom::Crossings cs = Geom::crossings(p0, p1);
2560- if(cs.size() > 0){
2561- Point cp =p0(cs[0].ta);
2562- double p0pt = nearest_time(cp, B);
2563- len = time_to_len(index,p0pt);
2564- } else {
2565- if(rad < 0){
2566- len = rad_to_len(index, rad * -1);
2567- }
2568- }
2569- return len;
2570-}
2571-
2572-double FilletChamferPointArrayParam::len_to_rad(int index, double len)
2573-{
2574- double rad = 0;
2575- double tmp_len = _vector[index][X];
2576- _vector[index] = Geom::Point(len,_vector[index][Y]);
2577- Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1);
2578- std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
2579- Piecewise<D2<SBasis> > u;
2580- u.push_cut(0);
2581- u.push(last_pwd2[last_index(index, subpaths)], 1);
2582- Geom::Curve * A = path_from_piecewise(u, 0.1)[0][0].duplicate();
2583- Geom::Curve * B = subpaths[positions.first][positions.second].duplicate();
2584- std::vector<double> times;
2585- if(positions.second != 0){
2586- A = subpaths[positions.first][positions.second-1].duplicate();
2587- times = get_times(index-1, subpaths, false);
2588- }else{
2589- if(!subpaths[positions.first].closed()){
2590- return rad;
2591- }
2592- times = get_times(last_index(index, subpaths), subpaths, true);
2593- }
2594- _vector[index] = Geom::Point(tmp_len,_vector[index][Y]);
2595- Geom::Point startArcPoint = A->toSBasis().valueAt(times[1]);
2596- Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]);
2597- Curve *knotCurve1 = A->portion(times[0], times[1]);
2598- Curve *knotCurve2 = B->portion(times[2], 1);
2599- Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(knotCurve1);
2600- Ray ray1(startArcPoint, A->finalPoint());
2601- if (cubic1) {
2602- ray1.setPoints((*cubic1)[2], startArcPoint);
2603- }
2604- Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(knotCurve2);
2605- Ray ray2(B->initialPoint(), endArcPoint);
2606- if (cubic2) {
2607- ray2.setPoints(endArcPoint, (*cubic2)[1]);
2608- }
2609- bool ccwToggle = cross(A->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0;
2610- double distanceArc = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint));
2611- double angleBetween = angle_between(ray1, ray2, ccwToggle);
2612- rad = distanceArc/sin(angleBetween/2.0);
2613- return rad * -1;
2614-}
2615-
2616-std::vector<double> FilletChamferPointArrayParam::get_times(int index, Geom::PathVector subpaths, bool last)
2617-{
2618- const double tolerance = 0.001;
2619- const double gapHelper = 0.00001;
2620- std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
2621- Curve *curve_it1;
2622- curve_it1 = subpaths[positions.first][positions.second].duplicate();
2623- Coord it1_length = (*curve_it1).length(tolerance);
2624- double time_it1, time_it2, time_it1_B, intpart;
2625- if (static_cast<int>(_vector.size()) <= index){
2626- std::vector<double> out;
2627- out.push_back(0);
2628- out.push_back(1);
2629- out.push_back(0);
2630- return out;
2631- }
2632- time_it1 = modf(to_time(index, _vector[index][X]), &intpart);
2633- if (_vector[index][Y] == 0) {
2634- time_it1 = 0;
2635- }
2636- double resultLenght = 0;
2637- if (subpaths[positions.first].closed() && last) {
2638- time_it2 = modf(to_time(index - positions.second , _vector[index - positions.second ][X]), &intpart);
2639- resultLenght = it1_length + to_len(index - positions.second, _vector[index - positions.second ][X]);
2640- } else if (!subpaths[positions.first].closed() && last){
2641- time_it2 = 0;
2642- resultLenght = 0;
2643- } else {
2644- time_it2 = modf(to_time(index + 1, _vector[index + 1][X]), &intpart);
2645- resultLenght = it1_length + to_len( index + 1, _vector[index + 1][X]);
2646- }
2647- if (resultLenght > 0 && time_it2 != 0) {
2648- time_it1_B = modf(to_time(index, -resultLenght), &intpart);
2649- } else {
2650- if (time_it2 == 0) {
2651- time_it1_B = 1;
2652- } else {
2653- time_it1_B = gapHelper;
2654- }
2655- }
2656-
2657- if ((subpaths[positions.first].closed() && last && _vector[index - positions.second][Y] == 0) || (subpaths[positions.first].size() > positions.second + 1 && _vector[index + 1][Y] == 0)) {
2658- time_it1_B = 1;
2659- time_it2 = 0;
2660- }
2661- if (time_it1_B < time_it1) {
2662- time_it1_B = time_it1 + gapHelper;
2663- }
2664- std::vector<double> out;
2665- out.push_back(time_it1);
2666- out.push_back(time_it1_B);
2667- out.push_back(time_it2);
2668- return out;
2669-}
2670-
2671-std::pair<std::size_t, std::size_t> FilletChamferPointArrayParam::get_positions(int index, Geom::PathVector subpaths)
2672-{
2673- int counter = -1;
2674- std::size_t first = 0;
2675- std::size_t second = 0;
2676- for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) {
2677- if (path_it->empty())
2678- continue;
2679- Geom::Path::const_iterator curve_it1 = path_it->begin();
2680- Geom::Path::const_iterator curve_endit = path_it->end_default();
2681- if (path_it->closed()) {
2682- const Geom::Curve &closingline = path_it->back_closed();
2683- // the closing line segment is always of type
2684- // Geom::LineSegment.
2685- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
2686- // closingline.isDegenerate() did not work, because it only checks for
2687- // *exact* zero length, which goes wrong for relative coordinates and
2688- // rounding errors...
2689- // the closing line segment has zero-length. So stop before that one!
2690- curve_endit = path_it->end_open();
2691- }
2692- }
2693- first++;
2694- second = 0;
2695- while (curve_it1 != curve_endit) {
2696- counter++;
2697- second++;
2698- if(counter == index){
2699- break;
2700- }
2701- ++curve_it1;
2702- }
2703- if(counter == index){
2704- break;
2705- }
2706- }
2707- first--;
2708- second--;
2709- std::pair<std::size_t, std::size_t> out(first, second);
2710- return out;
2711-}
2712-
2713-int FilletChamferPointArrayParam::last_index(int index, Geom::PathVector subpaths)
2714-{
2715- int counter = -1;
2716- bool inSubpath = false;
2717- for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) {
2718- if (path_it->empty())
2719- continue;
2720- Geom::Path::const_iterator curve_it1 = path_it->begin();
2721- Geom::Path::const_iterator curve_endit = path_it->end_default();
2722- if (path_it->closed()) {
2723- const Geom::Curve &closingline = path_it->back_closed();
2724- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
2725- curve_endit = path_it->end_open();
2726- }
2727- }
2728- while (curve_it1 != curve_endit) {
2729- counter++;
2730- if(counter == index){
2731- inSubpath = true;
2732- }
2733- ++curve_it1;
2734- }
2735- if(inSubpath){
2736- break;
2737- }
2738- }
2739- if(!inSubpath){
2740- counter = -1;
2741- }
2742- return counter;
2743-}
2744-
2745-
2746-double FilletChamferPointArrayParam::len_to_time(int index, double len)
2747-{
2748- double t = 0;
2749- if (last_pwd2.size() > (unsigned) index) {
2750- if (len != 0) {
2751- if (last_pwd2[index][0].degreesOfFreedom() != 2) {
2752- Piecewise<D2<SBasis> > u;
2753- u.push_cut(0);
2754- u.push(last_pwd2[index], 1);
2755- std::vector<double> t_roots = roots(arcLengthSb(u) - std::abs(len));
2756- if (t_roots.size() > 0) {
2757- t = t_roots[0];
2758- }
2759- } else {
2760- double lenghtPart = 0;
2761- if (last_pwd2.size() > (unsigned) index) {
2762- lenghtPart = length(last_pwd2[index], EPSILON);
2763- }
2764- if (std::abs(len) < lenghtPart && lenghtPart != 0) {
2765- t = std::abs(len) / lenghtPart;
2766- }
2767- }
2768- }
2769- t = double(index) + t;
2770- } else {
2771- t = double(last_pwd2.size() - 1);
2772- }
2773-
2774- return t;
2775-}
2776-
2777-double FilletChamferPointArrayParam::time_to_len(int index, double time)
2778-{
2779- double intpart;
2780- double len = 0;
2781- time = modf(time, &intpart);
2782- double lenghtPart = 0;
2783- if (last_pwd2.size() <= (unsigned) index || time == 0) {
2784- return len;
2785- }
2786- if (last_pwd2[index][0].degreesOfFreedom() != 2) {
2787- Piecewise<D2<SBasis> > u;
2788- u.push_cut(0);
2789- u.push(last_pwd2[index], 1);
2790- u = portion(u, 0, time);
2791- return length(u, 0.001) * -1;
2792- }
2793- lenghtPart = length(last_pwd2[index], EPSILON);
2794- return (time * lenghtPart) * -1;
2795-}
2796-
2797-double FilletChamferPointArrayParam::to_time(int index, double A)
2798-{
2799- if (A > 0) {
2800- return A;
2801- } else {
2802- return len_to_time(index, A);
2803- }
2804-}
2805-
2806-double FilletChamferPointArrayParam::to_len(int index, double A)
2807-{
2808- if (A > 0) {
2809- return time_to_len(index, A);
2810- } else {
2811- return A;
2812- }
2813-}
2814-
2815-void FilletChamferPointArrayParam::set_oncanvas_looks(SPKnotShapeType shape,
2816- SPKnotModeType mode,
2817- guint32 color)
2818-{
2819- knot_shape = shape;
2820- knot_mode = mode;
2821- knot_color = color;
2822-}
2823-
2824-FilletChamferPointArrayParamKnotHolderEntity::
2825-FilletChamferPointArrayParamKnotHolderEntity(
2826- FilletChamferPointArrayParam *p, unsigned int index)
2827- : _pparam(p), _index(index) {}
2828-
2829-void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p,
2830- Point const &/*origin*/,
2831- guint state)
2832-{
2833- using namespace Geom;
2834-
2835- if (!valid_index(_index)) {
2836- return;
2837- }
2838- Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2();
2839- double t = nearest_time(p, pwd2[_index]);
2840- Geom::Point const s = snap_knot_position(pwd2[_index].valueAt(t), state);
2841- t = nearest_time(s, pwd2[_index]);
2842- if (t == 1) {
2843- t = 0.9999;
2844- }
2845- t += _index;
2846-
2847- if (_pparam->_vector.at(_index)[X] <= 0) {
2848- _pparam->_vector.at(_index) =
2849- Point(_pparam->time_to_len(_index, t), _pparam->_vector.at(_index)[Y]);
2850- } else {
2851- _pparam->_vector.at(_index) = Point(t, _pparam->_vector.at(_index)[Y]);
2852- }
2853- sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
2854-}
2855-
2856-Point FilletChamferPointArrayParamKnotHolderEntity::knot_get() const
2857-{
2858- using namespace Geom;
2859-
2860- if (!valid_index(_index)) {
2861- return Point(infinity(), infinity());
2862- }
2863-
2864- Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2();
2865-
2866- double time_it = _pparam->to_time(_index, _pparam->_vector.at(_index)[X]);
2867- Point canvas_point = pwd2.valueAt(time_it);
2868-
2869- _pparam->updateCanvasIndicators();
2870- return canvas_point;
2871-
2872-}
2873-
2874-void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state)
2875-{
2876- if (state & GDK_CONTROL_MASK) {
2877- if (state & GDK_MOD1_MASK) {
2878- _pparam->_vector.at(_index) = Point(_index, _pparam->_vector.at(_index)[Y]);
2879- _pparam->param_set_and_write_new_value(_pparam->_vector);
2880- sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
2881- }else{
2882- using namespace Geom;
2883- int type = (int)_pparam->_vector.at(_index)[Y];
2884- if (type >=3000 && type < 4000){
2885- type = 3;
2886- }
2887- if (type >=4000 && type < 5000){
2888- type = 4;
2889- }
2890- switch(type){
2891- case 1:
2892- type = 2;
2893- break;
2894- case 2:
2895- type = _pparam->chamfer_steps + 3000;
2896- break;
2897- case 3:
2898- type = _pparam->chamfer_steps + 4000;
2899- break;
2900- default:
2901- type = 1;
2902- break;
2903- }
2904- _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], (double)type);
2905- _pparam->param_set_and_write_new_value(_pparam->_vector);
2906- sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
2907- const gchar *tip;
2908- if (type >=3000 && type < 4000){
2909- tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
2910- "<b>Shift+Click</b> open dialog, "
2911- "<b>Ctrl+Alt+Click</b> reset");
2912- } else if (type >=4000 && type < 5000) {
2913- tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
2914- "<b>Shift+Click</b> open dialog, "
2915- "<b>Ctrl+Alt+Click</b> reset");
2916- } else if (type == 2) {
2917- tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, "
2918- "<b>Shift+Click</b> open dialog, "
2919- "<b>Ctrl+Alt+Click</b> reset");
2920- } else {
2921- tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, "
2922- "<b>Shift+Click</b> open dialog, "
2923- "<b>Ctrl+Alt+Click</b> reset");
2924- }
2925- this->knot->tip = g_strdup(tip);
2926- this->knot->show();
2927- }
2928- } else if (state & GDK_SHIFT_MASK) {
2929- double xModified = _pparam->_vector.at(_index).x();
2930- if(xModified < 0 && !_pparam->use_distance){
2931- xModified = _pparam->len_to_rad(_index, _pparam->_vector.at(_index).x());
2932- }
2933- Geom::PathVector subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1);
2934- std::pair<std::size_t, std::size_t> positions = _pparam->get_positions(_index, subpaths);
2935- D2<SBasis> A = _pparam->last_pwd2[_pparam->last_index(_index, subpaths)];
2936- if(positions.second != 0){
2937- A = _pparam->last_pwd2[_index-1];
2938- }
2939- D2<SBasis> B = _pparam->last_pwd2[_index];
2940- bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false;
2941- Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y());
2942- Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog(
2943- this->desktop, offset, this, _pparam->use_distance, aprox);
2944- }
2945-
2946-}
2947-
2948-void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset(
2949- Geom::Point offset)
2950-{
2951- double xModified = offset.x();
2952- if(xModified < 0 && !_pparam->use_distance){
2953- xModified = _pparam->rad_to_len(_index, offset.x());
2954- }
2955- _pparam->_vector.at(_index) = Geom::Point(xModified, offset.y());
2956- this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
2957-}
2958-
2959-void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) {
2960- recalculate_knots(get_pwd2());
2961- for (unsigned int i = 0; i < _vector.size(); ++i) {
2962- if (_vector[i][Y] <= 0) {
2963- continue;
2964- }
2965- const gchar *tip;
2966- if (_vector[i][Y] >=3000 && _vector[i][Y] < 4000){
2967- tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
2968- "<b>Shift+Click</b> open dialog, "
2969- "<b>Ctrl+Alt+Click</b> reset");
2970- } else if (_vector[i][Y] >=4000 && _vector[i][Y] < 5000) {
2971- tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
2972- "<b>Shift+Click</b> open dialog, "
2973- "<b>Ctrl+Alt+Click</b> reset");
2974- } else if (_vector[i][Y] == 2) {
2975- tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, "
2976- "<b>Shift+Click</b> open dialog, "
2977- "<b>Ctrl+Alt+Click</b> reset");
2978- } else {
2979- tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, "
2980- "<b>Shift+Click</b> open dialog, "
2981- "<b>Ctrl+Alt+Click</b> reset");
2982- }
2983- FilletChamferPointArrayParamKnotHolderEntity *e =
2984- new FilletChamferPointArrayParamKnotHolderEntity(this, i);
2985- e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),
2986- knot_shape, knot_mode, knot_color);
2987- knotholder->add(e);
2988- }
2989- updateCanvasIndicators();
2990-}
2991-
2992-} /* namespace LivePathEffect */
2993-
2994-} /* namespace Inkscape */
2995-
2996-/*
2997- Local Variables:
2998- mode:c++
2999- c-file-style:"stroustrup"
3000- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3001- indent-tabs-mode:nil
3002- fill-column:99
3003- End:
3004-*/
3005-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
3006
3007=== removed file 'src/live_effects/parameter/filletchamferpointarray.h'
3008--- src/live_effects/parameter/filletchamferpointarray.h 2017-04-29 00:01:22 +0000
3009+++ src/live_effects/parameter/filletchamferpointarray.h 1970-01-01 00:00:00 +0000
3010@@ -1,123 +0,0 @@
3011-#ifndef INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
3012-#define INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
3013-
3014-/*
3015- * Inkscape::LivePathEffectParameters
3016- * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
3017- * Special thanks to Johan Engelen for the base of the effect -powerstroke-
3018- * Also to ScislaC for point me to the idea
3019- * Also su_v for his construvtive feedback and time
3020- * and finaly to Liam P. White for his big help on coding, that save me a lot of
3021- * hours
3022- * Released under GNU GPL, read the file 'COPYING' for more information
3023- */
3024-
3025-#include <glib.h>
3026-#include <2geom/point.h>
3027-
3028-#include "live_effects/parameter/array.h"
3029-
3030-#include "knot-holder-entity.h"
3031-
3032-namespace Inkscape {
3033-
3034-namespace LivePathEffect {
3035-
3036-class FilletChamferPointArrayParamKnotHolderEntity;
3037-
3038-class FilletChamferPointArrayParam : public ArrayParam<Geom::Point> {
3039-public:
3040- FilletChamferPointArrayParam(const Glib::ustring &label,
3041- const Glib::ustring &tip,
3042- const Glib::ustring &key,
3043- Inkscape::UI::Widget::Registry *wr,
3044- Effect *effect);
3045- virtual ~FilletChamferPointArrayParam();
3046-
3047- virtual Gtk::Widget *param_newWidget();
3048-
3049- virtual void param_transform_multiply(Geom::Affine const &postmul,
3050- bool /*set*/);
3051-
3052- void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode,
3053- guint32 color);
3054- virtual double to_time(int index, double A);
3055- virtual double to_len(int index, double A);
3056- virtual double rad_to_len(int index, double rad);
3057- virtual double len_to_rad(int index, double len);
3058- virtual double len_to_time(int index, double len);
3059- virtual double time_to_len(int index, double time);
3060- virtual std::pair<std::size_t, std::size_t> get_positions(int index, Geom::PathVector subpaths);
3061- virtual int last_index(int index, Geom::PathVector subpaths);
3062- std::vector<double> get_times(int index, Geom::PathVector subpaths, bool last);
3063- virtual void set_helper_size(int hs);
3064- virtual void set_use_distance(bool use_knot_distance);
3065- virtual void set_chamfer_steps(int value_chamfer_steps);
3066- virtual void addCanvasIndicators(SPLPEItem const *lpeitem,
3067- std::vector<Geom::PathVector> &hp_vec);
3068- virtual void param_update_default(const gchar * default_value){};
3069- virtual bool providesKnotHolderEntities() const {
3070- return true;
3071- }
3072- virtual void updateCanvasIndicators();
3073- virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
3074-
3075- void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in,
3076- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_normal_in);
3077- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2() const {
3078- return last_pwd2;
3079- }
3080- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2_normal() const {
3081- return last_pwd2_normal;
3082- }
3083-
3084- void recalculate_controlpoints_for_new_pwd2(
3085- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in);
3086- void recalculate_knots(
3087- Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in);
3088- friend class FilletChamferPointArrayParamKnotHolderEntity;
3089-
3090-private:
3091- FilletChamferPointArrayParam(const FilletChamferPointArrayParam &);
3092- FilletChamferPointArrayParam &operator=(const FilletChamferPointArrayParam &);
3093-
3094- SPKnotShapeType knot_shape;
3095- SPKnotModeType knot_mode;
3096- guint32 knot_color;
3097- int helper_size;
3098- int chamfer_steps;
3099- bool use_distance;
3100- Geom::PathVector hp;
3101-
3102- Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2;
3103- Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal;
3104-};
3105-
3106-class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity {
3107-public:
3108- FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam *p,
3109- unsigned int index);
3110- virtual ~FilletChamferPointArrayParamKnotHolderEntity() {}
3111-
3112- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin,
3113- guint state);
3114- virtual Geom::Point knot_get() const;
3115- virtual void knot_click(guint state);
3116- virtual void knot_set_offset(Geom::Point offset);
3117-
3118- /*Checks whether the index falls within the size of the parameter's vector*/
3119- bool valid_index(unsigned int index) const {
3120- return (_pparam->_vector.size() > index);
3121- }
3122- ;
3123-
3124-private:
3125- FilletChamferPointArrayParam *_pparam;
3126- unsigned int _index;
3127-};
3128-
3129-} //namespace LivePathEffect
3130-
3131-} //namespace Inkscape
3132-
3133-#endif
3134
3135=== added file 'src/live_effects/parameter/satellitesarray.cpp'
3136--- src/live_effects/parameter/satellitesarray.cpp 1970-01-01 00:00:00 +0000
3137+++ src/live_effects/parameter/satellitesarray.cpp 2017-05-06 17:46:29 +0000
3138@@ -0,0 +1,583 @@
3139+/*
3140+ * Author(s):
3141+ * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
3142+ *
3143+ * Copyright (C) 2014 Author(s)
3144+ * Released under GNU GPL, read the file 'COPYING' for more information
3145+ */
3146+
3147+#include "knotholder.h"
3148+#include "ui/dialog/lpe-fillet-chamfer-properties.h"
3149+#include "live_effects/parameter/satellitesarray.h"
3150+#include "live_effects/effect.h"
3151+#include "sp-lpe-item.h"
3152+#include "inkscape.h"
3153+#include <preferences.h>
3154+// TODO due to internal breakage in glibmm headers,
3155+// this has to be included last.
3156+#include <glibmm/i18n.h>
3157+
3158+namespace Inkscape {
3159+
3160+namespace LivePathEffect {
3161+
3162+SatellitesArrayParam::SatellitesArrayParam(const Glib::ustring &label,
3163+ const Glib::ustring &tip,
3164+ const Glib::ustring &key,
3165+ Inkscape::UI::Widget::Registry *wr,
3166+ Effect *effect)
3167+ : ArrayParam<std::vector<Satellite> >(label, tip, key, wr, effect, 0), _knoth(NULL)
3168+{
3169+ _knot_shape = SP_KNOT_SHAPE_DIAMOND;
3170+ _knot_mode = SP_KNOT_MODE_XOR;
3171+ _knot_color = 0xAAFF8800;
3172+ _helper_size = 0;
3173+ _use_distance = false;
3174+ _global_knot_hide = false;
3175+ _current_zoom = 0;
3176+ _effectType = FILLET_CHAMFER;
3177+ _last_pathvector_satellites = NULL;
3178+}
3179+
3180+
3181+void SatellitesArrayParam::set_oncanvas_looks(SPKnotShapeType shape,
3182+ SPKnotModeType mode,
3183+ guint32 color)
3184+{
3185+ _knot_shape = shape;
3186+ _knot_mode = mode;
3187+ _knot_color = color;
3188+}
3189+
3190+void SatellitesArrayParam::setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write)
3191+{
3192+ _last_pathvector_satellites = pathVectorSatellites;
3193+ if (write) {
3194+ param_set_and_write_new_value(_last_pathvector_satellites->getSatellites());
3195+ } else {
3196+ param_setValue(_last_pathvector_satellites->getSatellites());
3197+ }
3198+}
3199+
3200+void SatellitesArrayParam::setUseDistance(bool use_knot_distance)
3201+{
3202+ _use_distance = use_knot_distance;
3203+}
3204+
3205+void SatellitesArrayParam::setCurrentZoom(double current_zoom)
3206+{
3207+ _current_zoom = current_zoom;
3208+}
3209+
3210+void SatellitesArrayParam::setGlobalKnotHide(bool global_knot_hide)
3211+{
3212+ _global_knot_hide = global_knot_hide;
3213+}
3214+void SatellitesArrayParam::setEffectType(EffectType et)
3215+{
3216+ _effectType = et;
3217+}
3218+
3219+void SatellitesArrayParam::setHelperSize(int hs)
3220+{
3221+ _helper_size = hs;
3222+ updateCanvasIndicators();
3223+}
3224+
3225+void SatellitesArrayParam::updateCanvasIndicators(bool mirror)
3226+{
3227+ if (!_last_pathvector_satellites) {
3228+ return;
3229+ }
3230+
3231+ if (!_hp.empty()) {
3232+ _hp.clear();
3233+ }
3234+ Geom::PathVector pathv = _last_pathvector_satellites->getPathVector();
3235+ if (pathv.empty()) {
3236+ return;
3237+ }
3238+ if (mirror == true) {
3239+ _hp.clear();
3240+ }
3241+ if (_effectType == FILLET_CHAMFER) {
3242+ for (size_t i = 0; i < _vector.size(); ++i) {
3243+ for (size_t j = 0; j < _vector[i].size(); ++j) {
3244+ if (_vector[i][j].hidden || //Ignore if hidden
3245+ (!_vector[i][j].has_mirror && mirror == true) || //Ignore if not have mirror and we are in mirror loop
3246+ _vector[i][j].amount == 0 || //no helper in 0 value
3247+ pathv[i].size() == j || //ignore last satellite in open paths with fillet chamfer effect
3248+ (!pathv[i].closed() && j == 0)) //ignore first satellites on open paths
3249+ {
3250+ continue;
3251+ }
3252+ Geom::Curve *curve_in = pathv[i][j].duplicate();
3253+ double pos = 0;
3254+ bool overflow = false;
3255+ double size_out = _vector[i][j].arcDistance(*curve_in);
3256+ double lenght_out = curve_in->length();
3257+ gint previous_index = j - 1; //Always are previous index because we skip first satellite on open paths
3258+ if (j == 0 && pathv[i].closed()) {
3259+ previous_index = pathv[i].size() - 1;
3260+ }
3261+ if ( previous_index < 0 ) {
3262+ return;
3263+ }
3264+ double lenght_in = pathv.curveAt(previous_index).length();
3265+ if (mirror) {
3266+ curve_in = const_cast<Geom::Curve *>(&pathv.curveAt(previous_index));
3267+ pos = _vector[i][j].time(size_out, true, *curve_in);
3268+ if (lenght_out < size_out) {
3269+ overflow = true;
3270+ }
3271+ } else {
3272+ pos = _vector[i][j].time(*curve_in);
3273+ if (lenght_in < size_out) {
3274+ overflow = true;
3275+ }
3276+ }
3277+ if (pos <= 0 || pos >= 1) {
3278+ continue;
3279+ }
3280+ Geom::Point point_a = curve_in->pointAt(pos);
3281+ Geom::Point deriv_a = unit_vector(derivative(curve_in->toSBasis()).pointAt(pos));
3282+ Geom::Rotate rot(Geom::Rotate::from_degrees(-90));
3283+ deriv_a = deriv_a * rot;
3284+ Geom::Point point_c = point_a - deriv_a * _helper_size;
3285+ Geom::Point point_d = point_a + deriv_a * _helper_size;
3286+ Geom::Ray ray_1(point_c, point_d);
3287+ char const *svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5";
3288+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
3289+ Geom::Affine aff = Geom::Affine();
3290+ aff *= Geom::Scale(_helper_size);
3291+ if (mirror) {
3292+ aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90));
3293+ } else {
3294+ aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270));
3295+ }
3296+ aff *= Geom::Translate(curve_in->pointAt(pos));
3297+ pathv *= aff;
3298+ _hp.push_back(pathv[0]);
3299+ _hp.push_back(pathv[1]);
3300+ if (overflow) {
3301+ double diameter = _helper_size;
3302+ if (_helper_size == 0) {
3303+ diameter = 15;
3304+ char const *svgd;
3305+ svgd = "M 0.7,0.35 A 0.35,0.35 0 0 1 0.35,0.7 0.35,0.35 0 0 1 0,0.35 "
3306+ "0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z";
3307+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
3308+ aff = Geom::Affine();
3309+ aff *= Geom::Scale(diameter);
3310+ aff *= Geom::Translate(point_a - Geom::Point(diameter * 0.35, diameter * 0.35));
3311+ pathv *= aff;
3312+ _hp.push_back(pathv[0]);
3313+ } else {
3314+ char const *svgd;
3315+ svgd = "M 0 -1.32 A 1.32 1.32 0 0 0 -1.32 0 A 1.32 1.32 0 0 0 0 1.32 A "
3316+ "1.32 1.32 0 0 0 1.18 0.59 L 0 0 L 1.18 -0.59 A 1.32 1.32 0 0 0 "
3317+ "0 -1.32 z";
3318+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
3319+ aff = Geom::Affine();
3320+ aff *= Geom::Scale(_helper_size / 2.0);
3321+ if (mirror) {
3322+ aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90));
3323+ } else {
3324+ aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270));
3325+ }
3326+ aff *= Geom::Translate(curve_in->pointAt(pos));
3327+ pathv *= aff;
3328+ _hp.push_back(pathv[0]);
3329+ }
3330+ }
3331+ }
3332+ }
3333+ }
3334+ if (!_knot_reset_helper.empty()) {
3335+ _hp.insert(_hp.end(), _knot_reset_helper.begin(), _knot_reset_helper.end() );
3336+ }
3337+ if (mirror) {
3338+ updateCanvasIndicators(false);
3339+ }
3340+}
3341+void SatellitesArrayParam::updateCanvasIndicators()
3342+{
3343+ updateCanvasIndicators(true);
3344+}
3345+
3346+void SatellitesArrayParam::addCanvasIndicators(
3347+ SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
3348+{
3349+ hp_vec.push_back(_hp);
3350+}
3351+
3352+void SatellitesArrayParam::param_transform_multiply(Geom::Affine const &postmul, bool /*set*/)
3353+{
3354+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3355+
3356+ if (prefs->getBool("/options/transform/rectcorners", true)) {
3357+ for (size_t i = 0; i < _vector.size(); ++i) {
3358+ for (size_t j = 0; j < _vector[i].size(); ++j) {
3359+ if (!_vector[i][j].is_time && _vector[i][j].amount > 0) {
3360+ _vector[i][j].amount = _vector[i][j].amount * ((postmul.expansionX() + postmul.expansionY()) / 2);
3361+ }
3362+ }
3363+ }
3364+ param_set_and_write_new_value(_vector);
3365+ }
3366+}
3367+
3368+void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
3369+ SPItem *item,
3370+ bool mirror)
3371+{
3372+ if (!_last_pathvector_satellites) {
3373+ return;
3374+ }
3375+ Geom::PathVector pathv = _last_pathvector_satellites->getPathVector();
3376+ size_t index = 0;
3377+ for (size_t i = 0; i < _vector.size(); ++i) {
3378+ for (size_t j = 0; j < _vector[i].size(); ++j) {
3379+ if (!_vector[i][j].has_mirror && mirror) {
3380+ continue;
3381+ }
3382+ SatelliteType type = _vector[i][j].satellite_type;
3383+ if (mirror && i == 0 && j == 0) {
3384+ index = index + _last_pathvector_satellites->getTotalSatellites();
3385+ }
3386+ using namespace Geom;
3387+ //If is for filletChamfer effect...
3388+ if (_effectType == FILLET_CHAMFER) {
3389+ const gchar *tip;
3390+ if (type == CHAMFER) {
3391+ tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
3392+ "<b>Shift+Click</b> open dialog, "
3393+ "<b>Ctrl+Alt+Click</b> reset");
3394+ } else if (type == INVERSE_CHAMFER) {
3395+ tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
3396+ "<b>Shift+Click</b> open dialog, "
3397+ "<b>Ctrl+Alt+Click</b> reset");
3398+ } else if (type == INVERSE_FILLET) {
3399+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, "
3400+ "<b>Shift+Click</b> open dialog, "
3401+ "<b>Ctrl+Alt+Click</b> reset");
3402+ } else {
3403+ tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, "
3404+ "<b>Shift+Click</b> open dialog, "
3405+ "<b>Ctrl+Alt+Click</b> reset");
3406+ }
3407+ FilletChamferKnotHolderEntity *e = new FilletChamferKnotHolderEntity(this, index);
3408+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),_knot_shape, _knot_mode, _knot_color);
3409+ knotholder->add(e);
3410+ }
3411+ index++;
3412+ }
3413+ }
3414+ if (mirror) {
3415+ addKnotHolderEntities(knotholder, item, false);
3416+ }
3417+}
3418+
3419+void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
3420+ SPItem *item)
3421+{
3422+ _knoth = knotholder;
3423+ addKnotHolderEntities(knotholder, item, true);
3424+}
3425+
3426+FilletChamferKnotHolderEntity::FilletChamferKnotHolderEntity(
3427+ SatellitesArrayParam *p, size_t index)
3428+ : _pparam(p), _index(index) {}
3429+
3430+void FilletChamferKnotHolderEntity::knot_set(Geom::Point const &p,
3431+ Geom::Point const &/*origin*/,
3432+ guint state)
3433+{
3434+ if (!_pparam->_last_pathvector_satellites) {
3435+ return;
3436+ }
3437+ size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
3438+ bool is_mirror = false;
3439+ size_t index = _index;
3440+ if (_index >= total_satellites) {
3441+ index = _index - total_satellites;
3442+ is_mirror = true;
3443+ }
3444+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
3445+ size_t path_index = index_data.first;
3446+ size_t curve_index = index_data.second;
3447+
3448+ Geom::Point s = snap_knot_position(p, state);
3449+ if (!valid_index(path_index, curve_index)) {
3450+ return;
3451+ }
3452+ Satellite satellite = _pparam->_vector[path_index][curve_index];
3453+ Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
3454+ if (satellite.hidden ||
3455+ (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
3456+ pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
3457+ {
3458+ return;
3459+ }
3460+ gint previous_index = curve_index - 1;
3461+ if (curve_index == 0 && pathv[path_index].closed()) {
3462+ previous_index = pathv[path_index].size() - 1;
3463+ }
3464+ if ( previous_index < 0 ) {
3465+ return;
3466+ }
3467+ Geom::Curve const &curve_in = pathv[path_index][previous_index];
3468+ double mirror_time = Geom::nearest_time(s, curve_in);
3469+ Geom::Point mirror = curve_in.pointAt(mirror_time);
3470+ double normal_time = Geom::nearest_time(s, pathv[path_index][curve_index]);
3471+ Geom::Point normal = pathv[path_index][curve_index].pointAt(normal_time);
3472+ double distance_mirror = Geom::distance(mirror,s);
3473+ double distance_normal = Geom::distance(normal,s);
3474+ if (Geom::are_near(s, pathv[path_index][curve_index].initialPoint(), 1.5 / _pparam->_current_zoom)) {
3475+ satellite.amount = 0;
3476+ } else if (distance_mirror < distance_normal) {
3477+ double time_start = 0;
3478+ Satellites satellites = _pparam->_last_pathvector_satellites->getSatellites();
3479+ time_start = satellites[path_index][previous_index].time(curve_in);
3480+ if (time_start > mirror_time) {
3481+ mirror_time = time_start;
3482+ }
3483+ double size = arcLengthAt(mirror_time, curve_in);
3484+ double amount = curve_in.length() - size;
3485+ if (satellite.is_time) {
3486+ amount = timeAtArcLength(amount, pathv[path_index][curve_index]);
3487+ }
3488+ satellite.amount = amount;
3489+ } else {
3490+ satellite.setPosition(s, pathv[path_index][curve_index]);
3491+ }
3492+ _pparam->_knot_reset_helper.clear();
3493+ if (satellite.amount == 0) {
3494+ char const *svgd;
3495+ svgd = "M -5.39,8.78 -9.13,5.29 -10.38,10.28 Z M -7.22,7.07 -3.43,3.37 m -1.95,-12.16 -3.74,3.5 -1.26,-5 z "
3496+ "m -1.83,1.71 3.78,3.7 M 5.24,8.78 8.98,5.29 10.24,10.28 Z "
3497+ "M 7.07,7.07 3.29,3.37 M 5.24,-8.78 l 3.74,3.5 1.26,-5 z M 7.07,-7.07 3.29,-3.37";
3498+ _pparam->_knot_reset_helper = sp_svg_read_pathv(svgd);
3499+ _pparam->_knot_reset_helper *= Geom::Affine(_pparam->_helper_size * 0.1,0,0,_pparam->_helper_size * 0.1,0,0) * Geom::Translate(pathv[path_index][curve_index].initialPoint());
3500+ }
3501+ _pparam->_vector[path_index][curve_index] = satellite;
3502+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
3503+}
3504+
3505+Geom::Point FilletChamferKnotHolderEntity::knot_get() const
3506+{
3507+ if (!_pparam->_last_pathvector_satellites || _pparam->_global_knot_hide) {
3508+ return Geom::Point(Geom::infinity(), Geom::infinity());
3509+ }
3510+ Geom::Point tmp_point;
3511+ size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
3512+ bool is_mirror = false;
3513+ size_t index = _index;
3514+ if (_index >= total_satellites) {
3515+ index = _index - total_satellites;
3516+ is_mirror = true;
3517+ }
3518+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
3519+ size_t path_index = index_data.first;
3520+ size_t curve_index = index_data.second;
3521+ if (!valid_index(path_index, curve_index)) {
3522+ return Geom::Point(Geom::infinity(), Geom::infinity());
3523+ }
3524+ Satellite satellite = _pparam->_vector[path_index][curve_index];
3525+ Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
3526+ if (satellite.hidden ||
3527+ (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
3528+ pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
3529+ {
3530+ return Geom::Point(Geom::infinity(), Geom::infinity());
3531+ }
3532+ this->knot->show();
3533+ if (is_mirror) {
3534+ gint previous_index = curve_index - 1;
3535+ if (curve_index == 0 && pathv[path_index].closed()) {
3536+ previous_index = pathv[path_index].size() - 1;
3537+ }
3538+ if ( previous_index < 0 ) {
3539+ return Geom::Point(Geom::infinity(), Geom::infinity());
3540+ }
3541+ Geom::Curve const &curve_in = pathv[path_index][previous_index];
3542+ double s = satellite.arcDistance(pathv[path_index][curve_index]);
3543+ double t = satellite.time(s, true, curve_in);
3544+ if (t > 1) {
3545+ t = 1;
3546+ }
3547+ if (t < 0) {
3548+ t = 0;
3549+ }
3550+ double time_start = 0;
3551+ time_start = _pparam->_last_pathvector_satellites->getSatellites()[path_index][previous_index].time(curve_in);
3552+ if (time_start > t) {
3553+ t = time_start;
3554+ }
3555+ tmp_point = (curve_in).pointAt(t);
3556+ } else {
3557+ tmp_point = satellite.getPosition(pathv[path_index][curve_index]);
3558+ }
3559+ Geom::Point const canvas_point = tmp_point;
3560+ _pparam->updateCanvasIndicators();
3561+ return canvas_point;
3562+}
3563+
3564+void FilletChamferKnotHolderEntity::knot_click(guint state)
3565+{
3566+ if (!_pparam->_last_pathvector_satellites) {
3567+ return;
3568+ }
3569+ size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
3570+ bool is_mirror = false;
3571+ size_t index = _index;
3572+ if (_index >= total_satellites) {
3573+ index = _index - total_satellites;
3574+ is_mirror = true;
3575+ }
3576+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
3577+ size_t path_index = index_data.first;
3578+ size_t curve_index = index_data.second;
3579+ if (!valid_index(path_index, curve_index)) {
3580+ return;
3581+ }
3582+ Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
3583+ if ((!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
3584+ pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
3585+ {
3586+ return;
3587+ }
3588+ if (state & GDK_CONTROL_MASK) {
3589+ if (state & GDK_MOD1_MASK) {
3590+ _pparam->_vector[path_index][curve_index].amount = 0.0;
3591+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
3592+ } else {
3593+ using namespace Geom;
3594+ SatelliteType type = _pparam->_vector[path_index][curve_index].satellite_type;
3595+ switch (type) {
3596+ case FILLET:
3597+ type = INVERSE_FILLET;
3598+ break;
3599+ case INVERSE_FILLET:
3600+ type = CHAMFER;
3601+ break;
3602+ case CHAMFER:
3603+ type = INVERSE_CHAMFER;
3604+ break;
3605+ default:
3606+ type = FILLET;
3607+ break;
3608+ }
3609+ _pparam->_vector[path_index][curve_index].satellite_type = type;
3610+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
3611+ const gchar *tip;
3612+ if (type == CHAMFER) {
3613+ tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
3614+ "<b>Shift+Click</b> open dialog, "
3615+ "<b>Ctrl+Alt+Click</b> resets");
3616+ } else if (type == INVERSE_CHAMFER) {
3617+ tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
3618+ "<b>Shift+Click</b> open dialog, "
3619+ "<b>Ctrl+Alt+Click</b> resets");
3620+ } else if (type == INVERSE_FILLET) {
3621+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, "
3622+ "<b>Shift+Click</b> open dialog, "
3623+ "<b>Ctrl+Alt+Click</b> resets");
3624+ } else {
3625+ tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, "
3626+ "<b>Shift+Click</b> open dialog, "
3627+ "<b>Ctrl+Alt+Click</b> resets");
3628+ }
3629+ this->knot->tip = g_strdup(tip);
3630+ this->knot->show();
3631+ }
3632+ } else if (state & GDK_SHIFT_MASK) {
3633+ double amount = _pparam->_vector[path_index][curve_index].amount;
3634+ gint previous_index = curve_index - 1;
3635+ if (curve_index == 0 && pathv[path_index].closed()) {
3636+ previous_index = pathv[path_index].size() - 1;
3637+ }
3638+ if ( previous_index < 0 ) {
3639+ return;
3640+ }
3641+ if (!_pparam->_use_distance && !_pparam->_vector[path_index][curve_index].is_time) {
3642+ amount = _pparam->_vector[path_index][curve_index].lenToRad(amount, pathv[path_index][previous_index], pathv[path_index][curve_index], _pparam->_vector[path_index][previous_index]);
3643+ }
3644+ bool aprox = false;
3645+ Geom::D2<Geom::SBasis> d2_out = pathv[path_index][curve_index].toSBasis();
3646+ Geom::D2<Geom::SBasis> d2_in = pathv[path_index][previous_index].toSBasis();
3647+ aprox = ((d2_in)[0].degreesOfFreedom() != 2 ||
3648+ d2_out[0].degreesOfFreedom() != 2) &&
3649+ !_pparam->_use_distance
3650+ ? true
3651+ : false;
3652+ Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog(
3653+ this->desktop, amount, this, _pparam->_use_distance,
3654+ aprox, _pparam->_vector[path_index][curve_index]);
3655+
3656+ }
3657+}
3658+
3659+void FilletChamferKnotHolderEntity::knot_set_offset(Satellite satellite)
3660+{
3661+ if (!_pparam->_last_pathvector_satellites) {
3662+ return;
3663+ }
3664+ size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
3665+ bool is_mirror = false;
3666+ size_t index = _index;
3667+ if (_index >= total_satellites) {
3668+ index = _index - total_satellites;
3669+ is_mirror = true;
3670+ }
3671+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
3672+ size_t path_index = index_data.first;
3673+ size_t curve_index = index_data.second;
3674+ if (!valid_index(path_index, curve_index)) {
3675+ return;
3676+ }
3677+ Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
3678+ if (satellite.hidden ||
3679+ (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
3680+ pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
3681+ {
3682+ return;
3683+ }
3684+ double amount = satellite.amount;
3685+ double max_amount = amount;
3686+ if (!_pparam->_use_distance && !satellite.is_time) {
3687+ gint previous_index = curve_index - 1;
3688+ if (curve_index == 0 && pathv[path_index].closed()) {
3689+ previous_index = pathv[path_index].size() - 1;
3690+ }
3691+ if ( previous_index < 0 ) {
3692+ return;
3693+ }
3694+ amount = _pparam->_vector[path_index][curve_index].radToLen(amount, pathv[path_index][previous_index], pathv[path_index][curve_index]);
3695+ if (max_amount > 0 && amount == 0) {
3696+ amount = _pparam->_vector[path_index][curve_index].amount;
3697+ }
3698+ }
3699+ satellite.amount = amount;
3700+ _pparam->_vector[path_index][curve_index] = satellite;
3701+ this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
3702+ SPLPEItem *splpeitem = dynamic_cast<SPLPEItem *>(item);
3703+ if (splpeitem) {
3704+ sp_lpe_item_update_patheffect(splpeitem, false, false);
3705+ }
3706+}
3707+
3708+} /* namespace LivePathEffect */
3709+
3710+} /* namespace Inkscape */
3711+
3712+/*
3713+ Local Variables:
3714+ mode:c++
3715+ c-file-style:"stroustrup"
3716+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3717+ indent-tabs-mode:nil
3718+ fill-column:99
3719+ End:
3720+*/
3721+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
3722
3723=== added file 'src/live_effects/parameter/satellitesarray.h'
3724--- src/live_effects/parameter/satellitesarray.h 1970-01-01 00:00:00 +0000
3725+++ src/live_effects/parameter/satellitesarray.h 2017-05-06 17:46:29 +0000
3726@@ -0,0 +1,114 @@
3727+#ifndef INKSCAPE_LIVEPATHEFFECT_SATELLITES_ARRAY_H
3728+#define INKSCAPE_LIVEPATHEFFECT_SATELLITES_ARRAY_H
3729+
3730+/*
3731+ * Inkscape::LivePathEffectParameters
3732+ * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
3733+ * Special thanks to Johan Engelen for the base of the effect -powerstroke-
3734+ * Also to ScislaC for point me to the idea
3735+ * Also su_v for his construvtive feedback and time
3736+ * To Nathan Hurst for his review and help on refactor
3737+ * and finaly to Liam P. White for his big help on coding, that save me a lot of
3738+ * hours
3739+ *
3740+ *
3741+ * This parameter act as bridge from pathVectorSatellites class to serialize it as a LPE
3742+ * parameter
3743+ *
3744+ * Released under GNU GPL, read the file 'COPYING' for more information
3745+ */
3746+
3747+#include "live_effects/parameter/array.h"
3748+#include "live_effects/effect-enum.h"
3749+#include "helper/geom-pathvectorsatellites.h"
3750+#include "knot-holder-entity.h"
3751+#include <glib.h>
3752+
3753+namespace Inkscape {
3754+
3755+namespace LivePathEffect {
3756+
3757+class FilletChamferKnotHolderEntity;
3758+
3759+class SatellitesArrayParam : public ArrayParam<std::vector<Satellite> > {
3760+public:
3761+ SatellitesArrayParam(const Glib::ustring &label, const Glib::ustring &tip,
3762+ const Glib::ustring &key,
3763+ Inkscape::UI::Widget::Registry *wr, Effect *effect);
3764+
3765+ virtual Gtk::Widget *param_newWidget()
3766+ {
3767+ return NULL;
3768+ }
3769+ virtual void setHelperSize(int hs);
3770+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
3771+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item, bool mirror);
3772+ virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
3773+ virtual void updateCanvasIndicators();
3774+ virtual void updateCanvasIndicators(bool mirror);
3775+ virtual bool providesKnotHolderEntities() const
3776+ {
3777+ return true;
3778+ }
3779+ void param_transform_multiply(Geom::Affine const &postmul, bool /*set*/);
3780+ void setUseDistance(bool use_knot_distance);
3781+ void setCurrentZoom(double current_zoom);
3782+ void setGlobalKnotHide(bool global_knot_hide);
3783+ void setEffectType(EffectType et);
3784+ void setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write = true);
3785+ void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
3786+
3787+ friend class FilletChamferKnotHolderEntity;
3788+ friend class LPEFilletChamfer;
3789+
3790+protected:
3791+ KnotHolder *_knoth;
3792+
3793+private:
3794+ SatellitesArrayParam(const SatellitesArrayParam &);
3795+ SatellitesArrayParam &operator=(const SatellitesArrayParam &);
3796+
3797+ SPKnotShapeType _knot_shape;
3798+ SPKnotModeType _knot_mode;
3799+ guint32 _knot_color;
3800+ Geom::PathVector _hp;
3801+ Geom::PathVector _knot_reset_helper;
3802+ int _helper_size;
3803+ bool _use_distance;
3804+ bool _global_knot_hide;
3805+ double _current_zoom;
3806+ EffectType _effectType;
3807+ PathVectorSatellites *_last_pathvector_satellites;
3808+
3809+};
3810+
3811+class FilletChamferKnotHolderEntity : public KnotHolderEntity {
3812+public:
3813+ FilletChamferKnotHolderEntity(SatellitesArrayParam *p, size_t index);
3814+ virtual ~FilletChamferKnotHolderEntity()
3815+ {
3816+ _pparam->_knoth = NULL;
3817+ }
3818+
3819+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin,
3820+ guint state);
3821+ virtual Geom::Point knot_get() const;
3822+ virtual void knot_click(guint state);
3823+ void knot_set_offset(Satellite);
3824+ /** Checks whether the index falls within the size of the parameter's vector
3825+ */
3826+ bool valid_index(size_t index,size_t subindex) const
3827+ {
3828+ return (_pparam->_vector.size() > index && _pparam->_vector[index].size() > subindex);
3829+ };
3830+
3831+private:
3832+ SatellitesArrayParam *_pparam;
3833+ size_t _index;
3834+};
3835+
3836+} //namespace LivePathEffect
3837+
3838+} //namespace Inkscape
3839+
3840+#endif
3841
3842=== modified file 'src/ui/dialog/lpe-fillet-chamfer-properties.cpp'
3843--- src/ui/dialog/lpe-fillet-chamfer-properties.cpp 2017-03-12 13:45:15 +0000
3844+++ src/ui/dialog/lpe-fillet-chamfer-properties.cpp 2017-05-06 17:46:29 +0000
3845@@ -43,7 +43,6 @@
3846 //todo: get tha max aloable infinity freeze the widget
3847 _fillet_chamfer_position_numeric.set_range(0., SCALARPARAM_G_MAXDOUBLE);
3848 _fillet_chamfer_position_numeric.set_hexpand();
3849-
3850 _fillet_chamfer_position_label.set_label(_("Radius (pixels):"));
3851 _fillet_chamfer_position_label.set_alignment(1.0, 0.5);
3852
3853@@ -54,7 +53,6 @@
3854 //todo: get tha max aloable infinity freeze the widget
3855 _fillet_chamfer_chamfer_subdivisions.set_range(0, SCALARPARAM_G_MAXDOUBLE);
3856 _fillet_chamfer_chamfer_subdivisions.set_hexpand();
3857-
3858 _fillet_chamfer_chamfer_subdivisions_label.set_label(_("Chamfer subdivisions:"));
3859 _fillet_chamfer_chamfer_subdivisions_label.set_alignment(1.0, 0.5);
3860
3861@@ -104,23 +102,26 @@
3862 FilletChamferPropertiesDialog::~FilletChamferPropertiesDialog()
3863 {
3864
3865- _set_desktop(NULL);
3866+ _setDesktop(NULL);
3867 }
3868
3869 void FilletChamferPropertiesDialog::showDialog(
3870- SPDesktop *desktop, Geom::Point knotpoint,
3871+ SPDesktop *desktop,
3872+ double _amount,
3873 const Inkscape::LivePathEffect::
3874- FilletChamferPointArrayParamKnotHolderEntity *pt,
3875- bool use_distance,
3876- bool aprox_radius)
3877+ FilletChamferKnotHolderEntity *pt,
3878+ bool _use_distance,
3879+ bool _aprox_radius,
3880+ Satellite _satellite)
3881 {
3882 FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog();
3883
3884- dialog->_set_desktop(desktop);
3885- dialog->_set_use_distance(use_distance);
3886- dialog->_set_aprox(aprox_radius);
3887- dialog->_set_knot_point(knotpoint);
3888- dialog->_set_pt(pt);
3889+ dialog->_setDesktop(desktop);
3890+ dialog->_setUseDistance(_use_distance);
3891+ dialog->_setAprox(_aprox_radius);
3892+ dialog->_setAmount(_amount);
3893+ dialog->_setSatellite(_satellite);
3894+ dialog->_setPt(pt);
3895
3896 dialog->set_title(_("Modify Fillet-Chamfer"));
3897 dialog->_apply_button.set_label(_("_Modify"));
3898@@ -135,34 +136,38 @@
3899
3900 void FilletChamferPropertiesDialog::_apply()
3901 {
3902- double d_width;
3903+
3904 double d_pos = _fillet_chamfer_position_numeric.get_value();
3905- if (d_pos) {
3906+ if (d_pos >= 0) {
3907 if (_fillet_chamfer_type_fillet.get_active() == true) {
3908- d_width = 1;
3909+ _satellite.satellite_type = FILLET;
3910 } else if (_fillet_chamfer_type_inverse_fillet.get_active() == true) {
3911- d_width = 2;
3912+ _satellite.satellite_type = INVERSE_FILLET;
3913 } else if (_fillet_chamfer_type_inverse_chamfer.get_active() == true) {
3914- d_width = _fillet_chamfer_chamfer_subdivisions.get_value() + 4000;
3915+ _satellite.satellite_type = INVERSE_CHAMFER;
3916 } else {
3917- d_width = _fillet_chamfer_chamfer_subdivisions.get_value() + 3000;
3918+ _satellite.satellite_type = CHAMFER;
3919 }
3920 if (_flexible) {
3921 if (d_pos > 99.99999 || d_pos < 0) {
3922 d_pos = 0;
3923 }
3924- d_pos = _index + (d_pos / 100);
3925- } else {
3926- d_pos = d_pos * -1;
3927- }
3928- _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width));
3929+ d_pos = d_pos / 100;
3930+ }
3931+ _satellite.amount = d_pos;
3932+ size_t steps = (size_t)_fillet_chamfer_chamfer_subdivisions.get_value();
3933+ if (steps < 1) {
3934+ steps = 1;
3935+ }
3936+ _satellite.steps = steps;
3937+ _knotpoint->knot_set_offset(_satellite);
3938 }
3939 _close();
3940 }
3941
3942 void FilletChamferPropertiesDialog::_close()
3943 {
3944- _set_desktop(NULL);
3945+ _setDesktop(NULL);
3946 destroy_();
3947 Glib::signal_idle().connect(
3948 sigc::bind_return(
3949@@ -184,62 +189,68 @@
3950 }
3951 }
3952
3953-void FilletChamferPropertiesDialog::_set_knot_point(Geom::Point knotpoint)
3954+void FilletChamferPropertiesDialog::_setSatellite(Satellite satellite)
3955 {
3956 double position;
3957 std::string distance_or_radius = std::string(_("Radius"));
3958- if(aprox){
3959+ if (_aprox) {
3960 distance_or_radius = std::string(_("Radius approximated"));
3961 }
3962- if(use_distance){
3963+ if (_use_distance) {
3964 distance_or_radius = std::string(_("Knot distance"));
3965 }
3966- if (knotpoint.x() > 0) {
3967- double intpart;
3968- position = modf(knotpoint[Geom::X], &intpart) * 100;
3969+ if (satellite.is_time) {
3970+ position = _amount * 100;
3971 _flexible = true;
3972- _index = intpart;
3973 _fillet_chamfer_position_label.set_label(_("Position (%):"));
3974 } else {
3975 _flexible = false;
3976 std::string posConcat = Glib::ustring::compose (_("%1:"), distance_or_radius);
3977 _fillet_chamfer_position_label.set_label(_(posConcat.c_str()));
3978- position = knotpoint[Geom::X] * -1;
3979+ position = _amount;
3980 }
3981 _fillet_chamfer_position_numeric.set_value(position);
3982- if (knotpoint.y() == 1) {
3983+ _fillet_chamfer_chamfer_subdivisions.set_value(satellite.steps);
3984+ if (satellite.satellite_type == FILLET) {
3985 _fillet_chamfer_type_fillet.set_active(true);
3986- } else if (knotpoint.y() == 2) {
3987+ } else if (satellite.satellite_type == INVERSE_FILLET) {
3988 _fillet_chamfer_type_inverse_fillet.set_active(true);
3989- } else if (knotpoint.y() >= 3000 && knotpoint.y() < 4000) {
3990- _fillet_chamfer_chamfer_subdivisions.set_value(knotpoint.y() - 3000);
3991+ } else if (satellite.satellite_type == CHAMFER) {
3992 _fillet_chamfer_type_chamfer.set_active(true);
3993- } else if (knotpoint.y() >= 4000 && knotpoint.y() < 5000) {
3994- _fillet_chamfer_chamfer_subdivisions.set_value(knotpoint.y() - 4000);
3995+ } else if (satellite.satellite_type == INVERSE_CHAMFER) {
3996 _fillet_chamfer_type_inverse_chamfer.set_active(true);
3997 }
3998+ _satellite = satellite;
3999 }
4000
4001-void FilletChamferPropertiesDialog::_set_pt(
4002+void FilletChamferPropertiesDialog::_setPt(
4003 const Inkscape::LivePathEffect::
4004- FilletChamferPointArrayParamKnotHolderEntity *pt)
4005+ FilletChamferKnotHolderEntity *pt)
4006 {
4007 _knotpoint = const_cast<
4008- Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *>(
4009+ Inkscape::LivePathEffect::FilletChamferKnotHolderEntity *>(
4010 pt);
4011 }
4012
4013-void FilletChamferPropertiesDialog::_set_use_distance(bool use_knot_distance)
4014-{
4015- use_distance = use_knot_distance;
4016-}
4017-
4018-void FilletChamferPropertiesDialog::_set_aprox(bool aprox_radius)
4019-{
4020- aprox = aprox_radius;
4021-}
4022-
4023-void FilletChamferPropertiesDialog::_set_desktop(SPDesktop *desktop)
4024+
4025+void FilletChamferPropertiesDialog::_setAmount(double amount)
4026+{
4027+ _amount = amount;
4028+}
4029+
4030+
4031+
4032+void FilletChamferPropertiesDialog::_setUseDistance(bool use_knot_distance)
4033+{
4034+ _use_distance = use_knot_distance;
4035+}
4036+
4037+void FilletChamferPropertiesDialog::_setAprox(bool _aprox_radius)
4038+{
4039+ _aprox = _aprox_radius;
4040+}
4041+
4042+void FilletChamferPropertiesDialog::_setDesktop(SPDesktop *desktop)
4043 {
4044 if (desktop) {
4045 Inkscape::GC::anchor(desktop);
4046
4047=== modified file 'src/ui/dialog/lpe-fillet-chamfer-properties.h'
4048--- src/ui/dialog/lpe-fillet-chamfer-properties.h 2017-03-12 13:37:33 +0000
4049+++ src/ui/dialog/lpe-fillet-chamfer-properties.h 2017-05-06 17:46:29 +0000
4050@@ -10,7 +10,7 @@
4051
4052 #include <2geom/point.h>
4053 #include <gtkmm.h>
4054-#include "live_effects/parameter/filletchamferpointarray.h"
4055+#include "live_effects/parameter/satellitesarray.h"
4056
4057 class SPDesktop;
4058
4059@@ -23,20 +23,22 @@
4060 FilletChamferPropertiesDialog();
4061 virtual ~FilletChamferPropertiesDialog();
4062
4063- Glib::ustring getName() const {
4064+ Glib::ustring getName() const
4065+ {
4066 return "LayerPropertiesDialog";
4067 }
4068
4069- static void showDialog(SPDesktop *desktop, Geom::Point knotpoint,
4070+ static void showDialog(SPDesktop *desktop, double _amount,
4071 const Inkscape::LivePathEffect::
4072- FilletChamferPointArrayParamKnotHolderEntity *pt,
4073- bool use_distance,
4074- bool aprox_radius);
4075+ FilletChamferKnotHolderEntity *pt,
4076+ bool _use_distance,
4077+ bool _aprox_radius,
4078+ Satellite _satellite);
4079
4080 protected:
4081
4082 SPDesktop *_desktop;
4083- Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *
4084+ Inkscape::LivePathEffect::FilletChamferKnotHolderEntity *
4085 _knotpoint;
4086
4087 Gtk::Label _fillet_chamfer_position_label;
4088@@ -51,36 +53,40 @@
4089
4090 Gtk::Grid _layout_table;
4091 bool _position_visible;
4092- double _index;
4093
4094 Gtk::Button _close_button;
4095 Gtk::Button _apply_button;
4096
4097 sigc::connection _destroy_connection;
4098
4099- static FilletChamferPropertiesDialog &_instance() {
4100+ static FilletChamferPropertiesDialog &_instance()
4101+ {
4102 static FilletChamferPropertiesDialog instance;
4103 return instance;
4104 }
4105
4106- void _set_desktop(SPDesktop *desktop);
4107- void _set_pt(const Inkscape::LivePathEffect::
4108- FilletChamferPointArrayParamKnotHolderEntity *pt);
4109- void _set_use_distance(bool use_knot_distance);
4110- void _set_aprox(bool aprox_radius);
4111+ void _setDesktop(SPDesktop *desktop);
4112+ void _setPt(const Inkscape::LivePathEffect::
4113+ FilletChamferKnotHolderEntity *pt);
4114+ void _setUseDistance(bool use_knot_distance);
4115+ void _setAprox(bool aprox_radius);
4116+ void _setAmount(double amount);
4117+ void _setSatellite(Satellite satellite);
4118+ void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row);
4119+
4120+ bool _handleKeyEvent(GdkEventKey *event);
4121+ void _handleButtonEvent(GdkEventButton *event);
4122+
4123 void _apply();
4124 void _close();
4125 bool _flexible;
4126- bool use_distance;
4127- bool aprox;
4128- void _set_knot_point(Geom::Point knotpoint);
4129- void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row);
4130-
4131- bool _handleKeyEvent(GdkEventKey *event);
4132- void _handleButtonEvent(GdkEventButton *event);
4133+ Satellite _satellite;
4134+ bool _use_distance;
4135+ double _amount;
4136+ bool _aprox;
4137
4138 friend class Inkscape::LivePathEffect::
4139- FilletChamferPointArrayParamKnotHolderEntity;
4140+ FilletChamferKnotHolderEntity;
4141
4142 private:
4143 FilletChamferPropertiesDialog(
4144
4145=== modified file 'src/ui/tool/path-manipulator.cpp'
4146--- src/ui/tool/path-manipulator.cpp 2016-12-06 21:22:02 +0000
4147+++ src/ui/tool/path-manipulator.cpp 2017-05-06 17:46:29 +0000
4148@@ -12,7 +12,6 @@
4149
4150 #include "live_effects/lpe-powerstroke.h"
4151 #include "live_effects/lpe-bspline.h"
4152-#include "live_effects/lpe-fillet-chamfer.h"
4153 #include <2geom/bezier-utils.h>
4154 #include <2geom/path-sink.h>
4155 #include "ui/tool/path-manipulator.h"
4156@@ -1364,13 +1363,6 @@
4157 lpe_pwr->adjustForNewPath(pathv);
4158 }
4159 }
4160- this_effect = _path->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER);
4161- if(this_effect){
4162- LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(this_effect->getLPEObj()->get_lpe());
4163- if (lpe_fll) {
4164- lpe_fll->adjustForNewPath(pathv);
4165- }
4166- }
4167 }
4168 }
4169