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
=== modified file 'po/POTFILES.in'
--- po/POTFILES.in 2016-12-27 15:49:22 +0000
+++ po/POTFILES.in 2017-05-06 17:46:29 +0000
@@ -153,7 +153,7 @@
153src/live_effects/lpe-vonkoch.cpp153src/live_effects/lpe-vonkoch.cpp
154src/live_effects/parameter/bool.cpp154src/live_effects/parameter/bool.cpp
155src/live_effects/parameter/enum.h155src/live_effects/parameter/enum.h
156src/live_effects/parameter/filletchamferpointarray.cpp156src/live_effects/parameter/satellitearray.cpp
157src/live_effects/parameter/fontbutton.cpp157src/live_effects/parameter/fontbutton.cpp
158src/live_effects/parameter/originalpath.cpp158src/live_effects/parameter/originalpath.cpp
159src/live_effects/parameter/originalpatharray.cpp159src/live_effects/parameter/originalpatharray.cpp
160160
=== modified file 'src/helper/CMakeLists.txt'
--- src/helper/CMakeLists.txt 2015-03-19 01:41:26 +0000
+++ src/helper/CMakeLists.txt 2017-05-06 17:46:29 +0000
@@ -14,6 +14,8 @@
14 geom.cpp14 geom.cpp
15 geom-nodetype.cpp15 geom-nodetype.cpp
16 geom-pathstroke.cpp16 geom-pathstroke.cpp
17 geom-pathvectorsatellites.cpp
18 geom-satellite.cpp
17 gnome-utils.cpp19 gnome-utils.cpp
18 pixbuf-ops.cpp20 pixbuf-ops.cpp
19 png-write.cpp21 png-write.cpp
@@ -32,6 +34,8 @@
32 geom-curves.h34 geom-curves.h
33 geom-nodetype.h35 geom-nodetype.h
34 geom-pathstroke.h36 geom-pathstroke.h
37 geom-pathvectorsatellites.h
38 geom-satellite.h
35 geom.h39 geom.h
36 gnome-utils.h40 gnome-utils.h
37 mathfns.h41 mathfns.h
3842
=== added file 'src/helper/geom-pathvectorsatellites.cpp'
--- src/helper/geom-pathvectorsatellites.cpp 1970-01-01 00:00:00 +0000
+++ src/helper/geom-pathvectorsatellites.cpp 2017-05-06 17:46:29 +0000
@@ -0,0 +1,244 @@
1/**
2 * \file
3 * \brief PathVectorSatellites a class to manage satellites -per node extra data- in a pathvector
4 */ /*
5 * Authors:
6 * Jabiertxof
7 * Nathan Hurst
8 * Johan Engelen
9 * Josh Andler
10 * suv
11 * Mc-
12 * Liam P. White
13 * Krzysztof Kosiński
14 * This code is in public domain
15 */
16
17#include <helper/geom-pathvectorsatellites.h>
18#include "util/units.h"
19
20Geom::PathVector PathVectorSatellites::getPathVector() const
21{
22 return _pathvector;
23}
24
25void PathVectorSatellites::setPathVector(Geom::PathVector pathv)
26{
27 _pathvector = pathv;
28}
29
30Satellites PathVectorSatellites::getSatellites()
31{
32 return _satellites;
33}
34
35void PathVectorSatellites::setSatellites(Satellites satellites)
36{
37 _satellites = satellites;
38}
39
40size_t PathVectorSatellites::getTotalSatellites()
41{
42 size_t counter = 0;
43 for (size_t i = 0; i < _satellites.size(); ++i) {
44 for (size_t j = 0; j < _satellites[i].size(); ++j) {
45 counter++;
46 }
47 }
48 return counter;
49}
50
51std::pair<size_t, size_t> PathVectorSatellites::getIndexData(size_t index)
52{
53 size_t counter = 0;
54 for (size_t i = 0; i < _satellites.size(); ++i) {
55 for (size_t j = 0; j < _satellites[i].size(); ++j) {
56 if (index == counter) {
57 return std::make_pair(i,j);
58 }
59 counter++;
60 }
61 }
62 return std::make_pair(0,0);
63}
64
65void PathVectorSatellites::setSelected(std::vector<size_t> selected)
66{
67 size_t counter = 0;
68 for (size_t i = 0; i < _satellites.size(); ++i) {
69 for (size_t j = 0; j < _satellites[i].size(); ++j) {
70 if (find (selected.begin(), selected.end(), counter) != selected.end()) {
71 _satellites[i][j].setSelected(true);
72 } else {
73 _satellites[i][j].setSelected(false);
74 }
75 counter++;
76 }
77 }
78}
79
80void PathVectorSatellites::updateSteps(size_t steps, bool apply_no_radius, bool apply_with_radius, bool only_selected)
81{
82 for (size_t i = 0; i < _satellites.size(); ++i) {
83 for (size_t j = 0; j < _satellites[i].size(); ++j) {
84 if ((!apply_no_radius && _satellites[i][j].amount == 0) ||
85 (!apply_with_radius && _satellites[i][j].amount != 0))
86 {
87 continue;
88 }
89 if (only_selected) {
90 if (_satellites[i][j].selected) {
91 _satellites[i][j].steps = steps;
92 }
93 } else {
94 _satellites[i][j].steps = steps;
95 }
96 }
97 }
98}
99
100void PathVectorSatellites::updateAmount(double radius, bool apply_no_radius, bool apply_with_radius, bool only_selected,
101 bool use_knot_distance, bool flexible)
102{
103 double power = 0;
104 if (!flexible) {
105 power = radius;
106 } else {
107 power = radius / 100;
108 }
109 for (size_t i = 0; i < _satellites.size(); ++i) {
110 for (size_t j = 0; j < _satellites[i].size(); ++j) {
111 boost::optional<size_t> previous_index = boost::none;
112 if (j == 0 && _pathvector[i].closed()) {
113 previous_index = _pathvector[i].size() - 1;
114 } else if (!_pathvector[i].closed() || j != 0) {
115 previous_index = j - 1;
116 }
117 if (!_pathvector[i].closed() && j == 0) {
118 _satellites[i][j].amount = 0;
119 continue;
120 }
121 if (_pathvector[i].size() == j) {
122 continue;
123 }
124 if ((!apply_no_radius && _satellites[i][j].amount == 0) ||
125 (!apply_with_radius && _satellites[i][j].amount != 0))
126 {
127 continue;
128 }
129
130 Geom::Point satellite_point = _pathvector[i].pointAt(j);
131 if (_satellites[i][j].selected || !only_selected) {
132 if (!use_knot_distance && !flexible) {
133 if (previous_index) {
134 _satellites[i][j].amount = _satellites[i][j].radToLen(power, _pathvector[i][*previous_index], _pathvector[i][j]);
135 if (power && !_satellites[i][j].amount) {
136 g_warning("Seems a too high radius value");
137 }
138 } else {
139 _satellites[i][j].amount = 0.0;
140 }
141 } else {
142 _satellites[i][j].amount = power;
143 }
144 }
145 }
146 }
147}
148
149void PathVectorSatellites::convertUnit(Glib::ustring in, Glib::ustring to, bool apply_no_radius, bool apply_with_radius)
150{
151 for (size_t i = 0; i < _satellites.size(); ++i) {
152 for (size_t j = 0; j < _satellites[i].size(); ++j) {
153 if (!_pathvector[i].closed() && j == 0) {
154 _satellites[i][j].amount = 0;
155 continue;
156 }
157 if (_pathvector[i].size() == j) {
158 continue;
159 }
160 if ((!apply_no_radius && _satellites[i][j].amount == 0) ||
161 (!apply_with_radius && _satellites[i][j].amount != 0))
162 {
163 continue;
164 }
165 _satellites[i][j].amount = Inkscape::Util::Quantity::convert(_satellites[i][j].amount, in.c_str(), to.c_str());
166 }
167 }
168}
169
170void PathVectorSatellites::updateSatelliteType(SatelliteType satellitetype, bool apply_no_radius, bool apply_with_radius,
171 bool only_selected)
172{
173 for (size_t i = 0; i < _satellites.size(); ++i) {
174 for (size_t j = 0; j < _satellites[i].size(); ++j) {
175 if ((!apply_no_radius && _satellites[i][j].amount == 0) ||
176 (!apply_with_radius && _satellites[i][j].amount != 0))
177 {
178 continue;
179 }
180 if (_pathvector[i].size() == j) {
181 if (!only_selected) {
182 _satellites[i][j].satellite_type = satellitetype;
183 }
184 continue;
185 }
186 if (only_selected) {
187 Geom::Point satellite_point = _pathvector[i].pointAt(j);
188 if (_satellites[i][j].selected) {
189 _satellites[i][j].satellite_type = satellitetype;
190 }
191 } else {
192 _satellites[i][j].satellite_type = satellitetype;
193 }
194 }
195 }
196}
197
198void PathVectorSatellites::recalculateForNewPathVector(Geom::PathVector const pathv, Satellite const S)
199{
200 Satellites satellites;
201 bool found = false;
202 //TODO evaluate fix on nodes at same position
203 size_t number_nodes = pathv.nodes().size();
204 size_t previous_number_nodes = _pathvector.nodes().size();
205 for (size_t i = 0; i < pathv.size(); i++) {
206 std::vector<Satellite> path_satellites;
207 for (size_t j = 0; j < pathv[i].size_closed(); j++) {
208 found = false;
209 for (size_t k = 0; k < _pathvector.size(); k++) {
210 for (size_t l = 0; l < _pathvector[k].size_closed(); l++) {
211 if (Geom::are_near(_pathvector[k][l].initialPoint(), pathv[i][j].initialPoint()))
212 {
213 path_satellites.push_back(_satellites[k][l]);
214 found = true;
215 break;
216 }
217 }
218 if (found) {
219 break;
220 }
221 }
222
223 if (!found && previous_number_nodes < number_nodes) {
224 path_satellites.push_back(S);
225 }
226 }
227 satellites.push_back(path_satellites);
228 }
229 setPathVector(pathv);
230 setSatellites(satellites);
231}
232
233/*
234 Local Variables:
235 mode:c++
236 c-file-style:"stroustrup"
237 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
238 indent-tabs-mode:nil
239 fill-column:99
240 End:
241*/
242// vim:
243// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
244// :
0245
=== added file 'src/helper/geom-pathvectorsatellites.h'
--- src/helper/geom-pathvectorsatellites.h 1970-01-01 00:00:00 +0000
+++ src/helper/geom-pathvectorsatellites.h 2017-05-06 17:46:29 +0000
@@ -0,0 +1,58 @@
1/**
2 * \file
3 * \brief PathVectorSatellites a class to manage satellites -per node extra data- in a pathvector
4 */ /*
5 * Authors:
6 * Jabiertxof
7 * Nathan Hurst
8 * Johan Engelen
9 * Josh Andler
10 * suv
11 * Mc-
12 * Liam P. White
13 * Krzysztof Kosiński
14 * This code is in public domain
15 */
16
17#ifndef SEEN_PATHVECTORSATELLITES_H
18#define SEEN_PATHVECTORSATELLITES_H
19
20#include <helper/geom-satellite.h>
21#include <2geom/path.h>
22#include <2geom/pathvector.h>
23
24typedef std::vector<std::vector<Satellite> > Satellites;
25///@brief PathVectorSatellites a class to manage satellites in a pathvector
26class PathVectorSatellites {
27public:
28 Geom::PathVector getPathVector() const;
29 void setPathVector(Geom::PathVector pathv);
30 Satellites getSatellites();
31 void setSatellites(Satellites satellites);
32 size_t getTotalSatellites();
33 void setSelected(std::vector<size_t> selected);
34 void updateSteps(size_t steps, bool apply_no_radius, bool apply_with_radius, bool only_selected);
35 void updateAmount(double radius, bool apply_no_radius, bool apply_with_radius, bool only_selected,
36 bool use_knot_distance, bool flexible);
37 void convertUnit(Glib::ustring in, Glib::ustring to, bool apply_no_radius, bool apply_with_radius);
38 void updateSatelliteType(SatelliteType satellitetype, bool apply_no_radius, bool apply_with_radius, bool only_selected);
39 std::pair<size_t, size_t> getIndexData(size_t index);
40 void recalculateForNewPathVector(Geom::PathVector const pathv, Satellite const S);
41private:
42 Geom::PathVector _pathvector;
43 Satellites _satellites;
44};
45
46#endif //SEEN_PATHVECTORSATELLITES_H
47/*
48 Local Variables:
49 mode:c++
50 c-file-style:"stroustrup"
51 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
52 indent-tabs-mode:nil
53 fill-column:99
54 End:
55*/
56// vim:
57// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
58// :
059
=== added file 'src/helper/geom-satellite.cpp'
--- src/helper/geom-satellite.cpp 1970-01-01 00:00:00 +0000
+++ src/helper/geom-satellite.cpp 2017-05-06 17:46:29 +0000
@@ -0,0 +1,245 @@
1/**
2 * \file
3 * \brief Satellite a per node holder of data.
4 */ /*
5 * Authors:
6 * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es>
7 *
8 * This code is in public domain
9 */
10
11#include <helper/geom-satellite.h>
12#include <2geom/curve.h>
13#include <2geom/nearest-time.h>
14#include <2geom/path-intersection.h>
15#include <2geom/sbasis-to-bezier.h>
16#include <2geom/ray.h>
17#include <boost/optional.hpp>
18//log cache
19#ifdef _WIN32
20#include <Windows.h>
21#else
22#include <sys/time.h>
23#include <ctime>
24#endif
25
26///@brief Satellite a per node holder of data.
27Satellite::Satellite() {}
28
29
30Satellite::Satellite(SatelliteType satellite_type)
31 : satellite_type(satellite_type),
32 is_time(false),
33 selected(false),
34 has_mirror(false),
35 hidden(true),
36 amount(0.0),
37 angle(0.0),
38 steps(0)
39{}
40
41Satellite::~Satellite() {}
42
43///Calculate the time in curve_in with a size of A
44//TODO: find a better place to it
45double timeAtArcLength(double const A, Geom::Curve const &curve_in)
46{
47 if ( A == 0 || curve_in.isDegenerate()) {
48 return 0;
49 }
50
51 Geom::D2<Geom::SBasis> d2_in = curve_in.toSBasis();
52 double t = 0;
53 double length_part = curve_in.length();
54 if (A >= length_part || curve_in.isLineSegment()) {
55 if (length_part != 0) {
56 t = A / length_part;
57 }
58 } else if (!curve_in.isLineSegment()) {
59 std::vector<double> t_roots = roots(Geom::arcLengthSb(d2_in) - A);
60 if (!t_roots.empty()) {
61 t = t_roots[0];
62 }
63 }
64 return t;
65}
66
67///Calculate the size in curve_in with a point at A
68//TODO: find a better place to it
69double arcLengthAt(double const A, Geom::Curve const &curve_in)
70{
71 if ( A == 0 || curve_in.isDegenerate()) {
72 return 0;
73 }
74
75 double s = 0;
76 double length_part = curve_in.length();
77 if (A > length_part || curve_in.isLineSegment()) {
78 s = (A * length_part);
79 } else if (!curve_in.isLineSegment()) {
80 Geom::Curve *curve = curve_in.portion(0.0, A);
81 s = curve->length();
82 delete curve;
83 }
84 return s;
85}
86
87///Convert a arc radius of a fillet/chamfer to his satellite length -point position where fillet/chamfer knot be on original curve
88double Satellite::radToLen(
89 double const A, Geom::Curve const &curve_in,
90 Geom::Curve const &curve_out) const
91{
92 double len = 0;
93 Geom::D2<Geom::SBasis> d2_in = curve_in.toSBasis();
94 Geom::D2<Geom::SBasis> d2_out = curve_out.toSBasis();
95 Geom::Piecewise<Geom::D2<Geom::SBasis> > offset_curve0 =
96 Geom::Piecewise<Geom::D2<Geom::SBasis> >(d2_in) +
97 rot90(unitVector(derivative(d2_in))) * (A);
98 Geom::Piecewise<Geom::D2<Geom::SBasis> > offset_curve1 =
99 Geom::Piecewise<Geom::D2<Geom::SBasis> >(d2_out) +
100 rot90(unitVector(derivative(d2_out))) * (A);
101 Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0];
102 Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0];
103 Geom::Crossings cs = Geom::crossings(p0, p1);
104 if (cs.size() > 0) {
105 Geom::Point cp = p0(cs[0].ta);
106 double p0pt = nearest_time(cp, curve_out);
107 len = arcLengthAt(p0pt, curve_out);
108 } else {
109 if (A > 0) {
110 len = radToLen(A * -1, curve_in, curve_out);
111 }
112 }
113 return len;
114}
115
116///Convert a satelite length -point position where fillet/chamfer knot be on original curve- to a arc radius of fillet/chamfer
117double Satellite::lenToRad(
118 double const A, Geom::Curve const &curve_in,
119 Geom::Curve const &curve_out,
120 Satellite const previousSatellite) const
121{
122 double time_in = (previousSatellite).time(A, true, curve_in);
123 double time_out = timeAtArcLength(A, curve_out);
124 Geom::Point start_arc_point = curve_in.pointAt(time_in);
125 Geom::Point end_arc_point = curve_out.pointAt(time_out);
126 Geom::Curve *knot_curve1 = curve_in.portion(0, time_in);
127 Geom::Curve *knot_curve2 = curve_out.portion(time_out, 1);
128 Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve1);
129 Geom::Ray ray1(start_arc_point, curve_in.pointAt(1));
130 if (cubic1) {
131 ray1.setPoints((*cubic1)[2], start_arc_point);
132 }
133 Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve2);
134 Geom::Ray ray2(curve_out.pointAt(0), end_arc_point);
135 if (cubic2) {
136 ray2.setPoints(end_arc_point, (*cubic2)[1]);
137 }
138 bool ccw_toggle = cross(curve_in.pointAt(1) - start_arc_point,
139 end_arc_point - start_arc_point) < 0;
140 double distance_arc =
141 Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point));
142 double angle = angle_between(ray1, ray2, ccw_toggle);
143 double divisor = std::sin(angle / 2.0);
144 if (divisor > 0) {
145 return distance_arc / divisor;
146 }
147 return 0;
148}
149
150///Get the time position of the satellite in curve_in
151double Satellite::time(Geom::Curve const &curve_in, bool inverse) const
152{
153 double t = amount;
154 if (!is_time) {
155 t = time(t, inverse, curve_in);
156 } else if (inverse) {
157 t = 1-t;
158 }
159 if (t > 1) {
160 t = 1;
161 }
162 return t;
163}
164
165///Get the time from a length A in other curve, a bolean inverse gived to reverse time
166double Satellite::time(double A, bool inverse,
167 Geom::Curve const &curve_in) const
168{
169 if (A == 0 && inverse) {
170 return 1;
171 }
172 if (A == 0 && !inverse) {
173 return 0;
174 }
175 if (!inverse) {
176 return timeAtArcLength(A, curve_in);
177 }
178 double length_part = curve_in.length();
179 A = length_part - A;
180 return timeAtArcLength(A, curve_in);
181}
182
183///Get the length of the satellite in curve_in
184double Satellite::arcDistance(Geom::Curve const &curve_in) const
185{
186 double s = amount;
187 if (is_time) {
188 s = arcLengthAt(s, curve_in);
189 }
190 return s;
191}
192
193///Get the point position of the satellite
194Geom::Point Satellite::getPosition(Geom::Curve const &curve_in, bool inverse) const
195{
196 double t = time(curve_in, inverse);
197 return curve_in.pointAt(t);
198}
199
200///Set the position of the satellite from a gived point P
201void Satellite::setPosition(Geom::Point const p, Geom::Curve const &curve_in, bool inverse)
202{
203 Geom::Curve * curve = const_cast<Geom::Curve *>(&curve_in);
204 if (inverse) {
205 curve = curve->reverse();
206 }
207 double A = Geom::nearest_time(p, *curve);
208 if (!is_time) {
209 A = arcLengthAt(A, *curve);
210 }
211 amount = A;
212}
213
214
215///Map a satellite type with gchar
216void Satellite::setSatelliteType(gchar const *A)
217{
218 std::map<std::string, SatelliteType> gchar_map_to_satellite_type =
219 boost::assign::map_list_of("F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE);
220 std::map<std::string, SatelliteType>::iterator it = gchar_map_to_satellite_type.find(std::string(A));
221 if (it != gchar_map_to_satellite_type.end()) {
222 satellite_type = it->second;
223 }
224}
225
226///Map a gchar with satelliteType
227gchar const *Satellite::getSatelliteTypeGchar() const
228{
229 std::map<SatelliteType, gchar const *> satellite_type_to_gchar_map =
230 boost::assign::map_list_of(FILLET, "F")(INVERSE_FILLET, "IF")(CHAMFER, "C")(INVERSE_CHAMFER, "IC")(INVALID_SATELLITE, "KO");
231 return satellite_type_to_gchar_map.at(satellite_type);
232}
233
234/*
235 Local Variables:
236 mode:c++
237 c-file-style:"stroustrup"
238 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
239 indent-tabs-mode:nil
240 fill-column:99
241 End:
242*/
243// vim:
244// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
245// :
0246
=== added file 'src/helper/geom-satellite.h'
--- src/helper/geom-satellite.h 1970-01-01 00:00:00 +0000
+++ src/helper/geom-satellite.h 2017-05-06 17:46:29 +0000
@@ -0,0 +1,110 @@
1/**
2 * \file
3 * \brief Satellite a per node holder of data.
4 */ /*
5 * Authors:
6 * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es>
7 *
8 * This code is in public domain
9 */
10
11#ifndef SEEN_SATELLITE_H
12#define SEEN_SATELLITE_H
13
14#include <map>
15#include <boost/assign.hpp>
16#include <2geom/sbasis-geometric.h>
17#include "util/enums.h"
18
19
20enum SatelliteType {
21 FILLET = 0, //Fillet
22 INVERSE_FILLET, //Inverse Fillet
23 CHAMFER, //Chamfer
24 INVERSE_CHAMFER, //Inverse Chamfer
25 INVALID_SATELLITE // Invalid Satellite
26};
27/**
28 * @brief Satellite a per node holder of data.
29 */
30
31class Satellite {
32public:
33
34 Satellite();
35 Satellite(SatelliteType satellite_type);
36
37 virtual ~Satellite();
38 void setIsTime(bool set_is_time)
39 {
40 is_time = set_is_time;
41 }
42 void setSelected(bool set_selected)
43 {
44 selected = set_selected;
45 }
46 void setHasMirror(bool set_has_mirror)
47 {
48 has_mirror = set_has_mirror;
49 }
50 void setHidden(bool set_hidden)
51 {
52 hidden = set_hidden;
53 }
54 void setAmount(bool set_amount)
55 {
56 amount = set_amount;
57 }
58 void setAngle(bool set_angle)
59 {
60 angle = set_angle;
61 }
62 void setSteps(bool set_steps)
63 {
64 steps = set_steps;
65 }
66 double lenToRad(double const A, Geom::Curve const &curve_in,
67 Geom::Curve const &curve_out,
68 Satellite const previousSatellite) const;
69 double radToLen(double const A, Geom::Curve const &curve_in,
70 Geom::Curve const &curve_out) const;
71
72 double time(Geom::Curve const &curve_in, bool inverse = false) const;
73 double time(double A, bool inverse, Geom::Curve const &curve_in) const;
74 double arcDistance(Geom::Curve const &curve_in) const;
75
76 void setPosition(Geom::Point const p, Geom::Curve const &curve_in, bool inverse = false);
77 Geom::Point getPosition(Geom::Curve const &curve_in, bool inverse = false) const;
78
79 void setSatelliteType(gchar const *A);
80 gchar const *getSatelliteTypeGchar() const;
81 SatelliteType satellite_type;
82 //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
83 //"is_time" tell is if is a time or lenght value
84 bool is_time;
85 bool selected;
86 bool has_mirror;
87 bool hidden;
88 //in "amount" we store the time or distance used in the satellite
89 double amount;
90 double angle;
91 size_t steps;
92};
93
94double timeAtArcLength(double const A, Geom::Curve const &curve_in);
95double arcLengthAt(double const A, Geom::Curve const &curve_in);
96
97#endif // SEEN_SATELLITE_H
98
99/*
100 Local Variables:
101 mode:c++
102 c-file-style:"stroustrup"
103 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
104 indent-tabs-mode:nil
105 fill-column:99
106 End:
107*/
108// vim:
109// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
110// :
0111
=== modified file 'src/knotholder.h'
--- src/knotholder.h 2016-07-30 17:04:34 +0000
+++ src/knotholder.h 2017-05-06 17:46:29 +0000
@@ -30,7 +30,8 @@
30}30}
31namespace LivePathEffect {31namespace LivePathEffect {
32class PowerStrokePointArrayParamKnotHolderEntity;32class PowerStrokePointArrayParamKnotHolderEntity;
33class FilletPointArrayParamKnotHolderEntity;33class SatellitesArrayParam;
34class FilletChamferKnotHolderEntity;
34}35}
35}36}
3637
@@ -63,7 +64,7 @@
6364
64 friend class Inkscape::UI::ShapeEditor; // FIXME why?65 friend class Inkscape::UI::ShapeEditor; // FIXME why?
65 friend class Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity; // why?66 friend class Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity; // why?
66 friend class Inkscape::LivePathEffect::FilletPointArrayParamKnotHolderEntity; // why?67 friend class Inkscape::LivePathEffect::FilletChamferKnotHolderEntity; // why?
6768
68protected:69protected:
6970
7071
=== modified file 'src/live_effects/CMakeLists.txt'
--- src/live_effects/CMakeLists.txt 2017-01-24 09:44:10 +0000
+++ src/live_effects/CMakeLists.txt 2017-05-06 17:46:29 +0000
@@ -59,7 +59,6 @@
5959
60 parameter/array.cpp60 parameter/array.cpp
61 parameter/bool.cpp61 parameter/bool.cpp
62 parameter/filletchamferpointarray.cpp
63 parameter/item-reference.cpp62 parameter/item-reference.cpp
64 parameter/item.cpp63 parameter/item.cpp
65 parameter/originalitem.cpp64 parameter/originalitem.cpp
@@ -70,6 +69,7 @@
70 parameter/path.cpp69 parameter/path.cpp
71 parameter/point.cpp70 parameter/point.cpp
72 parameter/powerstrokepointarray.cpp71 parameter/powerstrokepointarray.cpp
72 parameter/satellitesarray.cpp
73 parameter/random.cpp73 parameter/random.cpp
74 parameter/text.cpp74 parameter/text.cpp
75 parameter/fontbutton.cpp75 parameter/fontbutton.cpp
@@ -144,7 +144,6 @@
144 parameter/array.h144 parameter/array.h
145 parameter/bool.h145 parameter/bool.h
146 parameter/enum.h146 parameter/enum.h
147 parameter/filletchamferpointarray.h
148 parameter/item.h147 parameter/item.h
149 parameter/item-reference.h148 parameter/item-reference.h
150 parameter/originalitem.h149 parameter/originalitem.h
@@ -155,6 +154,7 @@
155 parameter/path.h154 parameter/path.h
156 parameter/point.h155 parameter/point.h
157 parameter/powerstrokepointarray.h156 parameter/powerstrokepointarray.h
157 parameter/satellitesarray.h
158 parameter/random.h158 parameter/random.h
159 parameter/text.h159 parameter/text.h
160 parameter/fontbutton.h160 parameter/fontbutton.h
161161
=== modified file 'src/live_effects/effect.cpp'
--- src/live_effects/effect.cpp 2017-05-05 14:45:16 +0000
+++ src/live_effects/effect.cpp 2017-05-06 17:46:29 +0000
@@ -101,7 +101,6 @@
101 {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"},101 {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"},
102 {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},102 {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},
103 {TEXT_LABEL, N_("Text label"), "text_label"},103 {TEXT_LABEL, N_("Text label"), "text_label"},
104 {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"},
105#endif104#endif
106/* 0.46 */105/* 0.46 */
107 {BEND_PATH, N_("Bend"), "bend_path"},106 {BEND_PATH, N_("Bend"), "bend_path"},
@@ -142,6 +141,7 @@
142 {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"},141 {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"},
143/* 9.93 */142/* 9.93 */
144 {MEASURE_LINE, N_("Measure Line"), "measure_line"},143 {MEASURE_LINE, N_("Measure Line"), "measure_line"},
144 {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"},
145};145};
146const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));146const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
147147
148148
=== modified file 'src/live_effects/lpe-fillet-chamfer.cpp'
--- src/live_effects/lpe-fillet-chamfer.cpp 2017-04-28 19:42:36 +0000
+++ src/live_effects/lpe-fillet-chamfer.cpp 2017-05-06 17:46:29 +0000
@@ -4,86 +4,131 @@
4 *4 *
5 * Copyright (C) 2014 Author(s)5 * Copyright (C) 2014 Author(s)
6 *6 *
7 * Special thanks to Johan Engelen for the base of the effect -powerstroke-
8 * Also to ScislaC for point me to the idea
9 * Also su_v for his construvtive feedback and time
10 * Also to Mc- (IRC nick) for his important contribution to find real time
11 * values based on
12 * and finaly to Liam P. White for his big help on coding, that save me a lot of hours
13 *7 *
14 * Released under GNU GPL, read the file 'COPYING' for more information8 * Released under GNU GPL, read the file 'COPYING' for more information
15 */9 */
10
16#include "live_effects/lpe-fillet-chamfer.h"11#include "live_effects/lpe-fillet-chamfer.h"
17 12#include "helper/geom.h"
18#include <2geom/sbasis-to-bezier.h>
19#include <2geom/elliptical-arc.h>
20
21#include "display/curve.h"13#include "display/curve.h"
22#include "helper/geom-nodetype.h"
23#include "helper/geom-curves.h"14#include "helper/geom-curves.h"
24#include "helper/geom.h"15#include "helper/geom-satellite.h"
16#include <2geom/elliptical-arc.h>
17#include "knotholder.h"
18#include <boost/optional.hpp>
2519
26// for programmatically updating knots
27#include "ui/tools-switch.h"
28// TODO due to internal breakage in glibmm headers, this must be last:20// TODO due to internal breakage in glibmm headers, this must be last:
29#include <glibmm/i18n.h>21#include <glibmm/i18n.h>
3022
31using namespace Geom;
32namespace Inkscape {23namespace Inkscape {
33namespace LivePathEffect {24namespace LivePathEffect {
3425
35static const Util::EnumData<FilletMethod> FilletMethodData[FM_END] = {26static const Util::EnumData<Filletmethod> FilletmethodData[] = {
36 { FM_AUTO, N_("Auto"), "auto" },27 { FM_AUTO, N_("Auto"), "auto" },
37 { FM_ARC, N_("Force arc"), "arc" },28 { FM_ARC, N_("Force arc"), "arc" },
38 { FM_BEZIER, N_("Force bezier"), "bezier" }29 { FM_BEZIER, N_("Force bezier"), "bezier" }
39};30};
40static const Util::EnumDataConverter<FilletMethod>31static const Util::EnumDataConverter<Filletmethod> FMConverter(FilletmethodData, FM_END);
41FMConverter(FilletMethodData, FM_END);32
4233LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject)
43const double tolerance = 0.001;34 : Effect(lpeobject),
44const double gapHelper = 0.00001;35 unit(_("Unit"), _("Unit"), "unit", &wr, this, "px"),
4536 satellites_param("Satellites_param", "Satellites_param",
46LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) :37 "satellites_param", &wr, this),
47 Effect(lpeobject),38 method(_("Method:"), _("Methods to calculate the fillet or chamfer"),
48 fillet_chamfer_values(_("Fillet point"), _("Fillet point"), "fillet_chamfer_values", &wr, this),39 "method", FMConverter, &wr, this, FM_AUTO),
49 hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, false),40 radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr,
50 ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), "ignore_radius_0", &wr, this, false),41 this, 0.0),
51 only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false),42 chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps",
52 flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false),43 &wr, this, 1),
53 use_knot_distance(_("Use knots distance instead radius"), _("Use knots distance instead radius"), "use_knot_distance", &wr, this, false),44 flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"),
54 method(_("Method:"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO),45 "flexible", &wr, this, false),
55 radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr, this, 0.),46 mirror_knots(_("Mirror Knots"), _("Mirror Knots"), "mirror_knots", &wr,
56 chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps", &wr, this, 0),47 this, true),
57 48 only_selected(_("Change only selected nodes"),
58 helper_size(_("Helper size with direction:"), _("Helper size with direction"), "helper_size", &wr, this, 0)49 _("Change only selected nodes"), "only_selected", &wr, this,
50 false),
51 use_knot_distance(_("Use knots distance instead radius"),
52 _("Use knots distance instead radius"),
53 "use_knot_distance", &wr, this, false),
54 hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this,
55 false),
56 apply_no_radius(_("Apply changes if radius = 0"), _("Apply changes if radius = 0"), "apply_no_radius", &wr, this, true),
57 apply_with_radius(_("Apply changes if radius > 0"), _("Apply changes if radius > 0"), "apply_with_radius", &wr, this, true),
58 helper_size(_("Helper path size with direction to node:"),
59 _("Helper path size with direction to node"), "helper_size", &wr, this, 0),
60 _pathvector_satellites(NULL),
61 _degenerate_hide(false)
59{62{
60 registerParameter(&fillet_chamfer_values);63 registerParameter(&satellites_param);
64 registerParameter(&unit);
61 registerParameter(&method);65 registerParameter(&method);
62 registerParameter(&radius);66 registerParameter(&radius);
63 registerParameter(&chamfer_steps);67 registerParameter(&chamfer_steps);
64 registerParameter(&helper_size);68 registerParameter(&helper_size);
65 registerParameter(&flexible);69 registerParameter(&flexible);
66 registerParameter(&use_knot_distance);70 registerParameter(&use_knot_distance);
67 registerParameter(&ignore_radius_0);71 registerParameter(&mirror_knots);
72 registerParameter(&apply_no_radius);
73 registerParameter(&apply_with_radius);
68 registerParameter(&only_selected);74 registerParameter(&only_selected);
69 registerParameter(&hide_knots);75 registerParameter(&hide_knots);
7076
71 radius.param_set_range(0., infinity());77 radius.param_set_range(0.0, Geom::infinity());
72 radius.param_set_increments(1, 1);78 radius.param_set_increments(1, 1);
73 radius.param_set_digits(4);79 radius.param_set_digits(4);
74 radius.param_overwrite_widget(true);80 radius.param_overwrite_widget(true);
75 chamfer_steps.param_set_range(1, 999);81 chamfer_steps.param_set_range(1, 999);
76 chamfer_steps.param_set_increments(1, 1);82 chamfer_steps.param_set_increments(1, 1);
77 chamfer_steps.param_set_digits(0);83 chamfer_steps.param_set_digits(0);
78 chamfer_steps.param_overwrite_widget(true);84 helper_size.param_set_range(0, 999);
79 helper_size.param_set_range(0, infinity());
80 helper_size.param_set_increments(5, 5);85 helper_size.param_set_increments(5, 5);
81 helper_size.param_set_digits(0);86 helper_size.param_set_digits(0);
82 helper_size.param_overwrite_widget(true);87 _provides_knotholder_entities = true;
83 fillet_chamfer_values.set_chamfer_steps(3);
84}88}
8589
86LPEFilletChamfer::~LPEFilletChamfer() {}90void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem)
91{
92 SPLPEItem *splpeitem = const_cast<SPLPEItem *>(lpeItem);
93 SPShape *shape = dynamic_cast<SPShape *>(splpeitem);
94 if (shape) {
95 Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(shape->getCurve()->get_pathvector());
96 Satellites satellites;
97 for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
98 if (path_it->empty()) {
99 continue;
100 }
101 std::vector<Satellite> subpath_satellites;
102 for (Geom::Path::const_iterator curve_it = path_it->begin(); curve_it != path_it->end(); ++curve_it) {
103 //Maybe we want this satellites...
104 //if (curve_it->isDegenerate()) {
105 // continue
106 //}
107 Satellite satellite(FILLET);
108 satellite.setSteps(chamfer_steps);
109 subpath_satellites.push_back(satellite);
110 }
111 //we add the last satellite on open path because _pathvector_satellites is related to nodes, not curves
112 //so maybe in the future we can need this last satellite in other effects
113 //dont remove for this effect because _pathvector_satellites class has methods when the path is modiffied
114 //and we want one method for all uses
115 if (!path_it->closed()) {
116 Satellite satellite(FILLET);
117 satellite.setSteps(chamfer_steps);
118 subpath_satellites.push_back(satellite);
119 }
120 satellites.push_back(subpath_satellites);
121 }
122 _pathvector_satellites = new PathVectorSatellites();
123 _pathvector_satellites->setPathVector(pathv);
124 _pathvector_satellites->setSatellites(satellites);
125 satellites_param.setPathVectorSatellites(_pathvector_satellites);
126 } else {
127 g_warning("LPE Fillet/Chamfer can only be applied to shapes (not groups).");
128 SPLPEItem *item = const_cast<SPLPEItem *>(lpeItem);
129 item->removeCurrentPathEffect(false);
130 }
131}
87132
88Gtk::Widget *LPEFilletChamfer::newWidget()133Gtk::Widget *LPEFilletChamfer::newWidget()
89{134{
@@ -94,54 +139,50 @@
94 vbox->set_border_width(5);139 vbox->set_border_width(5);
95 vbox->set_homogeneous(false);140 vbox->set_homogeneous(false);
96 vbox->set_spacing(2);141 vbox->set_spacing(2);
97 Gtk::HBox *advertaising = Gtk::manage(new Gtk::HBox(true, 0));
98 Gtk::Button *advert = Gtk::manage(new Gtk::Button(Glib::ustring(_("IMPORTANT! New version soon..."))));
99 advertaising->pack_start(*advert, true, true, 2);
100 vbox->pack_start(*advertaising, true, true, 2);
101 Gtk::HBox *advertaising2 = Gtk::manage(new Gtk::HBox(true, 0));
102 Gtk::Button *advert2 = Gtk::manage(new Gtk::Button(Glib::ustring(_("Not compatible. Convert to path after."))));
103 advertaising2->pack_start(*advert2, true, true, 2);
104 vbox->pack_start(*advertaising2, true, true, 2);
105 std::vector<Parameter *>::iterator it = param_vector.begin();142 std::vector<Parameter *>::iterator it = param_vector.begin();
106 while (it != param_vector.end()) {143 while (it != param_vector.end()) {
107 if ((*it)->widget_is_visible) {144 if ((*it)->widget_is_visible) {
108 Parameter *param = *it;145 Parameter *param = *it;
109 Gtk::Widget *widg = param->param_newWidget();146 Gtk::Widget *widg = param->param_newWidget();
110 if (param->param_key == "radius") {147 if (param->param_key == "radius") {
111 Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));148 Inkscape::UI::Widget::Scalar *widg_registered =
112 widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::updateFillet));149 Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
113 widg = widgRegistered;150 widg_registered->signal_value_changed().connect(
151 sigc::mem_fun(*this, &LPEFilletChamfer::updateAmount));
152 widg = widg_registered;
114 if (widg) {153 if (widg) {
115 Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg);154 Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg);
116 std::vector<Gtk::Widget *> childList = scalarParameter->get_children();155 std::vector<Gtk::Widget *> childList = scalar_parameter->get_children();
117 Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);156 Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]);
118 entryWidg->set_width_chars(6);157 entry_widget->set_width_chars(6);
119 }158 }
159// } else if (param->param_key == "unit") {
160// Inkscape::UI::Widget::RegisteredUnitMenu* widg_registered =
161// Gtk::manage(dynamic_cast< Inkscape::UI::Widget::RegisteredUnitMenu *>(widg));
162// widg_registered->setUnit(unit.get_abbreviation());
163// widg_registered->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change unit parameter"));
164// widg_registered->getUnitMenu()->signal_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::convertUnit));
165// widg = widg_registered;
120 } else if (param->param_key == "chamfer_steps") {166 } else if (param->param_key == "chamfer_steps") {
121 Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));167 Inkscape::UI::Widget::Scalar *widg_registered =
122 widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamferSubdivisions));168 Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
123 widg = widgRegistered;169 widg_registered->signal_value_changed().connect(
170 sigc::mem_fun(*this, &LPEFilletChamfer::updateChamferSteps));
171 widg = widg_registered;
124 if (widg) {172 if (widg) {
125 Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg);173 Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg);
126 std::vector<Gtk::Widget *> childList = scalarParameter->get_children();174 std::vector<Gtk::Widget *> childList = scalar_parameter->get_children();
127 Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);175 Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]);
128 entryWidg->set_width_chars(3);176 entry_widget->set_width_chars(3);
129 }177 }
130 } else if (param->param_key == "flexible") {
131 Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
132 widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleFlexFixed));
133 } else if (param->param_key == "helper_size") {178 } else if (param->param_key == "helper_size") {
134 Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));179 Inkscape::UI::Widget::Scalar *widg_registered =
135 widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots));180 Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
136 } else if (param->param_key == "hide_knots") {181 widg_registered->signal_value_changed().connect(
137 Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));182 sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots));
138 widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleHide));
139 } else if (param->param_key == "only_selected") {183 } else if (param->param_key == "only_selected") {
140 Gtk::manage(widg);184 Gtk::manage(widg);
141 } else if (param->param_key == "ignore_radius_0") {
142 Gtk::manage(widg);
143 }185 }
144
145 Glib::ustring *tip = param->param_getTooltip();186 Glib::ustring *tip = param->param_getTooltip();
146 if (widg) {187 if (widg) {
147 vbox->pack_start(*widg, true, true, 2);188 vbox->pack_start(*widg, true, true, 2);
@@ -153,504 +194,386 @@
153 }194 }
154 }195 }
155 }196 }
156
157 ++it;197 ++it;
158 }198 }
159 Gtk::HBox *filletContainer = Gtk::manage(new Gtk::HBox(true, 0));199
160 Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet"))));200 Gtk::HBox *fillet_container = Gtk::manage(new Gtk::HBox(true, 0));
161 fillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet));201 Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet"))));
162202 fillet->signal_clicked()
163 filletContainer->pack_start(*fillet, true, true, 2);203 .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),FILLET));
164 Gtk::Button *inverseFillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet"))));204
165 inverseFillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseFillet));205 fillet_container->pack_start(*fillet, true, true, 2);
166 filletContainer->pack_start(*inverseFillet, true, true, 2);206 Gtk::Button *inverse_fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet"))));
167 207 inverse_fillet->signal_clicked()
168 Gtk::HBox *chamferContainer = Gtk::manage(new Gtk::HBox(true, 0));208 .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_FILLET));
209 fillet_container->pack_start(*inverse_fillet, true, true, 2);
210
211 Gtk::HBox *chamfer_container = Gtk::manage(new Gtk::HBox(true, 0));
169 Gtk::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer"))));212 Gtk::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer"))));
170 chamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer));213 chamfer->signal_clicked()
171214 .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),CHAMFER));
172 chamferContainer->pack_start(*chamfer, true, true, 2);215
173 Gtk::Button *inverseChamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer"))));216 chamfer_container->pack_start(*chamfer, true, true, 2);
174 inverseChamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseChamfer));217 Gtk::Button *inverse_chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer"))));
175 chamferContainer->pack_start(*inverseChamfer, true, true, 2);218 inverse_chamfer->signal_clicked()
176219 .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_CHAMFER));
177 vbox->pack_start(*filletContainer, true, true, 2);220 chamfer_container->pack_start(*inverse_chamfer, true, true, 2);
178 vbox->pack_start(*chamferContainer, true, true, 2);221
222 vbox->pack_start(*fillet_container, true, true, 2);
223 vbox->pack_start(*chamfer_container, true, true, 2);
179224
180 return vbox;225 return vbox;
181}226}
182227
183void LPEFilletChamfer::toggleHide()228void LPEFilletChamfer::refreshKnots()
184{229{
185 std::vector<Point> filletChamferData = fillet_chamfer_values.data();230 if (satellites_param._knoth) {
186 std::vector<Geom::Point> result;231 satellites_param._knoth->update_knots();
187 for (std::vector<Point>::const_iterator point_it = filletChamferData.begin();232 }
188 point_it != filletChamferData.end(); ++point_it) {233}
189 if (hide_knots) {234
190 result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y]) * -1));235void LPEFilletChamfer::updateAmount()
191 } else {236{
192 result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y])));237 setSelected(_pathvector_satellites);
193 }238 double power = radius;
194 }
195 fillet_chamfer_values.param_set_and_write_new_value(result);
196 refreshKnots();
197}
198
199void LPEFilletChamfer::toggleFlexFixed()
200{
201 std::vector<Point> filletChamferData = fillet_chamfer_values.data();
202 std::vector<Geom::Point> result;
203 unsigned int i = 0;
204 for (std::vector<Point>::const_iterator point_it = filletChamferData.begin();
205 point_it != filletChamferData.end(); ++point_it) {
206 if (flexible) {
207 result.push_back(Point(fillet_chamfer_values.to_time(i, (*point_it)[X]),
208 (*point_it)[Y]));
209 } else {
210 result.push_back(Point(fillet_chamfer_values.to_len(i, (*point_it)[X]),
211 (*point_it)[Y]));
212 }
213 i++;
214 }
215 if (flexible) {
216 radius.param_set_range(0., 100);
217 radius.param_set_value(0);
218 } else {
219 radius.param_set_range(0., infinity());
220 radius.param_set_value(0);
221 }
222 fillet_chamfer_values.param_set_and_write_new_value(result);
223}
224
225void LPEFilletChamfer::updateFillet()
226{
227 double power = 0;
228 if (!flexible) {239 if (!flexible) {
229 power = radius * -1;240 SPDocument * document = SP_ACTIVE_DOCUMENT;
230 } else {241 SPNamedView *nv = sp_document_namedview(document, NULL);
231 power = radius;242 Glib::ustring display_unit = nv->display_units->abbr;
232 }243 power = Inkscape::Util::Quantity::convert(power, unit.get_abbreviation(), display_unit.c_str());
233 Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();244 }
234 doUpdateFillet(path_from_piecewise(pwd2, tolerance), power);245 _pathvector_satellites->updateAmount(power, apply_no_radius, apply_with_radius, only_selected,
235 DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));246 use_knot_distance, flexible);
236}247 satellites_param.setPathVectorSatellites(_pathvector_satellites);
237248}
238void LPEFilletChamfer::fillet()249
239{250//void LPEFilletChamfer::convertUnit()
240 Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();251//{
241 doChangeType(path_from_piecewise(pwd2, tolerance), 1);252// SPDocument * document = SP_ACTIVE_DOCUMENT;
242 DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to fillet"));253// SPNamedView *nv = sp_document_namedview(document, NULL);
243}254// Glib::ustring display_unit = nv->display_units->abbr;
244255// _pathvector_satellites->convertUnit(unit.get_abbreviation(), display_unit, apply_no_radius, apply_with_radius);
245void LPEFilletChamfer::inverseFillet()256// satellites_param.setPathVectorSatellites(_pathvector_satellites);
246{257//}
247 Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();258
248 doChangeType(path_from_piecewise(pwd2, tolerance), 2);259void LPEFilletChamfer::updateChamferSteps()
249 DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet"));260{
250}261 setSelected(_pathvector_satellites);
251262 _pathvector_satellites->updateSteps(chamfer_steps, apply_no_radius, apply_with_radius, only_selected);
252void LPEFilletChamfer::chamferSubdivisions()263 satellites_param.setPathVectorSatellites(_pathvector_satellites);
253{264}
254 fillet_chamfer_values.set_chamfer_steps(chamfer_steps);265
255 Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();266void LPEFilletChamfer::updateSatelliteType(SatelliteType satellitetype)
256 doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 5000);267{
257 DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));268 setSelected(_pathvector_satellites);
258}269 _pathvector_satellites->updateSatelliteType(satellitetype, apply_no_radius, apply_with_radius, only_selected);
259270 satellites_param.setPathVectorSatellites(_pathvector_satellites);
260void LPEFilletChamfer::chamfer()271}
261{272
262 fillet_chamfer_values.set_chamfer_steps(chamfer_steps);273void LPEFilletChamfer::setSelected(PathVectorSatellites *_pathvector_satellites){
263 Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();274 Geom::PathVector const pathv = _pathvector_satellites->getPathVector();
264 doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3000);275 Satellites satellites = _pathvector_satellites->getSatellites();
265 DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to chamfer"));276 for (size_t i = 0; i < satellites.size(); ++i) {
266}277 for (size_t j = 0; j < satellites[i].size(); ++j) {
267278 Geom::Curve const &curve_in = pathv[i][j];
268void LPEFilletChamfer::inverseChamfer()279 if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){
269{280 satellites[i][j].setSelected(true);
270 fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
271 Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
272 doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 4000);
273 DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet"));
274}
275
276void LPEFilletChamfer::refreshKnots()
277{
278 Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
279 fillet_chamfer_values.recalculate_knots(pwd2);
280 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
281 if (tools_isactive(desktop, TOOLS_NODES)) {
282 tools_switch(desktop, TOOLS_SELECT);
283 tools_switch(desktop, TOOLS_NODES);
284 }
285 DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Knots and helper paths refreshed"));
286}
287
288void LPEFilletChamfer::doUpdateFillet(Geom::PathVector const &original_pathv, double power)
289{
290 std::vector<Point> filletChamferData = fillet_chamfer_values.data();
291 std::vector<Geom::Point> result;
292 Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv);
293 int counter = 0;
294 for (PathVector::const_iterator path_it = original_pathv_processed.begin();
295 path_it != original_pathv_processed.end(); ++path_it) {
296 if (path_it->empty())
297 continue;
298
299 Geom::Path::const_iterator curve_it1 = path_it->begin();
300 Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
301 Geom::Path::const_iterator curve_endit = path_it->end_default();
302 if (path_it->closed() && path_it->back_closed().isDegenerate()) {
303 const Curve &closingline = path_it->back_closed();
304 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
305 curve_endit = path_it->end_open();
306 }
307 }
308 double powerend = 0;
309 while (curve_it1 != curve_endit) {
310 powerend = power;
311 if (power < 0 && !use_knot_distance) {
312 powerend = fillet_chamfer_values.rad_to_len(counter,powerend);
313 }
314 if (power > 0) {
315 powerend = counter + (power / 100);
316 }
317 if (ignore_radius_0 && (filletChamferData[counter][X] == 0 ||
318 filletChamferData[counter][X] == counter)) {
319 powerend = filletChamferData[counter][X];
320 }
321 if (filletChamferData[counter][Y] == 0) {
322 powerend = filletChamferData[counter][X];
323 }
324 if (only_selected && !isNodePointSelected(curve_it1->initialPoint())) {
325 powerend = filletChamferData[counter][X];
326 }
327 result.push_back(Point(powerend, filletChamferData[counter][Y]));
328 ++curve_it1;
329 ++curve_it2;
330 counter++;
331 }
332 }
333 fillet_chamfer_values.param_set_and_write_new_value(result);
334}
335
336void LPEFilletChamfer::doChangeType(Geom::PathVector const &original_pathv, int type)
337{
338 std::vector<Point> filletChamferData = fillet_chamfer_values.data();
339 std::vector<Geom::Point> result;
340 Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv);
341 int counter = 0;
342 for (PathVector::const_iterator path_it = original_pathv_processed.begin(); path_it != original_pathv_processed.end(); ++path_it) {
343 int pathCounter = 0;
344 if (path_it->empty())
345 continue;
346
347 Geom::Path::const_iterator curve_it1 = path_it->begin();
348 Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
349 Geom::Path::const_iterator curve_endit = path_it->end_default();
350 if (path_it->closed() && path_it->back_closed().isDegenerate()) {
351 const Curve &closingline = path_it->back_closed();
352 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
353 curve_endit = path_it->end_open();
354 }
355 }
356 while (curve_it1 != curve_endit) {
357 bool toggle = true;
358 if (filletChamferData[counter][Y] == 0 ||
359 (ignore_radius_0 && (filletChamferData[counter][X] == 0 ||
360 filletChamferData[counter][X] == counter)) ||
361 (only_selected && !isNodePointSelected(curve_it1->initialPoint()))) {
362 toggle = false;
363 }
364 if (toggle) {
365 if(type >= 5000){
366 if(filletChamferData[counter][Y] >= 3000 && filletChamferData[counter][Y] < 4000){
367 type = type - 2000;
368 } else if (filletChamferData[counter][Y] >= 4000 && filletChamferData[counter][Y] < 5000){
369 type = type - 1000;
370 }
371 }
372 result.push_back(Point(filletChamferData[counter][X], type));
373 } else {281 } else {
374 result.push_back(filletChamferData[counter]);282 satellites[i][j].setSelected(false);
375 }283 }
376 ++curve_it1;284 }
377 if (curve_it2 != curve_endit) {285 }
378 ++curve_it2;286 _pathvector_satellites->setSatellites(satellites);
379 }
380 counter++;
381 pathCounter++;
382 }
383 }
384 fillet_chamfer_values.param_set_and_write_new_value(result);
385}
386
387void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem)
388{
389 if (SP_IS_SHAPE(lpeItem)) {
390 std::vector<Point> point;
391 PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeItem)->_curve->get_pathvector());
392 Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv);
393 for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) {
394 if (path_it->empty())
395 continue;
396
397 Geom::Path::const_iterator curve_it1 = path_it->begin();
398 Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
399 Geom::Path::const_iterator curve_endit = path_it->end_default();
400 if (path_it->closed()) {
401 const Geom::Curve &closingline = path_it->back_closed();
402 // the closing line segment is always of type
403 // Geom::LineSegment.
404 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
405 // closingline.isDegenerate() did not work, because it only checks for
406 // *exact* zero length, which goes wrong for relative coordinates and
407 // rounding errors...
408 // the closing line segment has zero-length. So stop before that one!
409 curve_endit = path_it->end_open();
410 }
411 }
412 int counter = 0;
413 while (curve_it1 != curve_endit) {
414 std::pair<std::size_t, std::size_t> positions = fillet_chamfer_values.get_positions(counter, original_pathv);
415 Geom::NodeType nodetype;
416 if (positions.second == 0) {
417 if (path_it->closed()) {
418 Piecewise<D2<SBasis> > u;
419 u.push_cut(0);
420 u.push(pwd2_in[fillet_chamfer_values.last_index(counter, original_pathv)], 1);
421 Geom::Curve const * A = path_from_piecewise(u, 0.1)[0][0].duplicate();
422 nodetype = get_nodetype(*A, *curve_it1);
423 } else {
424 nodetype = NODE_NONE;
425 }
426 } else {
427 nodetype = get_nodetype((*path_it)[counter - 1], *curve_it1);
428 }
429 if (nodetype == NODE_CUSP) {
430 point.push_back(Point(0, 1));
431 } else {
432 point.push_back(Point(0, 0));
433 }
434 ++curve_it1;
435 if (curve_it2 != curve_endit) {
436 ++curve_it2;
437 }
438 counter++;
439 }
440 }
441 fillet_chamfer_values.param_set_and_write_new_value(point);
442 } else {
443 g_warning("LPE Fillet can only be applied to shapes (not groups).");
444 SPLPEItem * item = const_cast<SPLPEItem*>(lpeItem);
445 item->removeCurrentPathEffect(false);
446 }
447}287}
448288
449void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem)289void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem)
450{290{
451 if (SP_IS_SHAPE(lpeItem)) {291 if (sp_curve) {
452 if(hide_knots){292 //fillet chamfer specific calls
453 fillet_chamfer_values.set_helper_size(0);293 satellites_param.setUseDistance(use_knot_distance);
454 } else {294 satellites_param.setCurrentZoom(current_zoom);
455 fillet_chamfer_values.set_helper_size(helper_size);295 //mandatory call
456 }296 satellites_param.setEffectType(effectType());
457 fillet_chamfer_values.set_use_distance(use_knot_distance);297 Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(sp_curve->get_pathvector());
458 SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast<SPPath const *>(lpeItem)298 //if are diferent sizes call to recalculate
459 ->get_original_curve()299 //TODO: Update the satellite data in paths modified,
460 : SP_SHAPE(lpeItem)->getCurve();300 Satellites satellites = satellites_param.data();
461 std::vector<Point> filletChamferData = fillet_chamfer_values.data();301 if (satellites.empty()) {
462 if (!filletChamferData.empty() && getKnotsNumber(c) != (int)302 doOnApply(lpeItem);
463 filletChamferData.size()) {303 satellites = satellites_param.data();
464 PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(c->get_pathvector());304 }
465 Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv);305 if (_pathvector_satellites) {
466 fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in);306 size_t number_nodes = pathv.nodes().size();
467 }307 size_t previous_number_nodes = _pathvector_satellites->getTotalSatellites();
308 if (number_nodes != previous_number_nodes) {
309 Satellite satellite(FILLET);
310 satellite.setIsTime(flexible);
311 satellite.setHasMirror(mirror_knots);
312 satellite.setHidden(hide_knots);
313 _pathvector_satellites->recalculateForNewPathVector(pathv, satellite);
314 satellites = _pathvector_satellites->getSatellites();
315 }
316 }
317 if (_degenerate_hide) {
318 satellites_param.setGlobalKnotHide(true);
319 } else {
320 satellites_param.setGlobalKnotHide(false);
321 }
322 if (hide_knots) {
323 satellites_param.setHelperSize(0);
324 } else {
325 satellites_param.setHelperSize(helper_size);
326 }
327 for (size_t i = 0; i < satellites.size(); ++i) {
328 for (size_t j = 0; j < satellites[i].size(); ++j) {
329 Geom::Curve const &curve_in = pathv[i][j];
330 if (satellites[i][j].is_time != flexible) {
331 satellites[i][j].is_time = flexible;
332 double amount = satellites[i][j].amount;
333 if (pathv[i].size() == j) {
334 continue;
335 }
336 if (satellites[i][j].is_time) {
337 double time = timeAtArcLength(amount, curve_in);
338 satellites[i][j].amount = time;
339 } else {
340 double size = arcLengthAt(amount, curve_in);
341 satellites[i][j].amount = size;
342 }
343 }
344 if (satellites[i][j].has_mirror != mirror_knots) {
345 satellites[i][j].has_mirror = mirror_knots;
346 }
347 satellites[i][j].hidden = hide_knots;
348 if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){
349 satellites[i][j].setSelected(true);
350 }
351 }
352 }
353 if (!_pathvector_satellites) {
354 _pathvector_satellites = new PathVectorSatellites();
355 }
356 _pathvector_satellites->setPathVector(pathv);
357 _pathvector_satellites->setSatellites(satellites);
358 satellites_param.setPathVectorSatellites(_pathvector_satellites, false);
359 refreshKnots();
468 } else {360 } else {
469 g_warning("LPE Fillet can only be applied to shapes (not groups).");361 g_warning("LPE Fillet can only be applied to shapes (not groups).");
470 }362 }
471}363}
472364
473int LPEFilletChamfer::getKnotsNumber(SPCurve const *c)365void
366LPEFilletChamfer::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
474{367{
475 int nKnots = c->nodes_in_path();368 hp_vec.push_back(_hp);
476 PathVector const pv = pathv_to_linear_and_cubic_beziers(c->get_pathvector());
477 for (Geom::PathVector::const_iterator path_it = pv.begin();
478 path_it != pv.end(); ++path_it) {
479 if (!(*path_it).closed()) {
480 nKnots--;
481 }
482 }
483 return nKnots;
484}369}
485370
486void371void
487LPEFilletChamfer::adjustForNewPath(Geom::PathVector const &path_in)372LPEFilletChamfer::addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps)
488{373{
489 if (!path_in.empty()) {374 setSelected(_pathvector_satellites);
490 fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb());375 double path_subdivision = 1.0 / steps;
376 for (size_t i = 1; i < steps; i++) {
377 Geom::Point chamfer_step = path_chamfer.pointAt(path_subdivision * i);
378 tmp_path.appendNew<Geom::LineSegment>(chamfer_step);
491 }379 }
380 tmp_path.appendNew<Geom::LineSegment>(end_arc_point);
492}381}
493382
494Geom::PathVector383Geom::PathVector
495LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in)384LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in)
496{385{
497 Geom::PathVector pathvector_out;386 const double GAP_HELPER = 0.00001;
498 Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(pathv_to_linear_and_cubic_beziers(path_in));387 Geom::PathVector path_out;
499 pwd2_in = remove_short_cuts(pwd2_in, .01);388 size_t path = 0;
500 Piecewise<D2<SBasis> > der = derivative(pwd2_in);
501 Piecewise<D2<SBasis> > n = rot90(unitVector(der));
502 fillet_chamfer_values.set_pwd2(pwd2_in, n);
503 std::vector<Point> filletChamferData = fillet_chamfer_values.data();
504 unsigned int counter = 0;
505 const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0);389 const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0);
506 Geom::PathVector path_in_processed = pathv_to_linear_and_cubic_beziers(path_in);390 _degenerate_hide = false;
507 for (PathVector::const_iterator path_it = path_in_processed.begin();391 Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(path_in);
508 path_it != path_in_processed.end(); ++path_it) {392 Satellites satellites = _pathvector_satellites->getSatellites();
509 if (path_it->empty())393 for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
510 continue;394 if (path_it->empty()) {
511 Geom::Path path_out;395 continue;
512 Geom::Path::const_iterator curve_it1 = path_it->begin();396 }
513 Geom::Path::const_iterator curve_it2 = ++(path_it->begin());397 Geom::Path tmp_path;
514 Geom::Path::const_iterator curve_endit = path_it->end_default();398 if (path_it->size() == 1) {
399 path++;
400 tmp_path.start(path_it[0].pointAt(0));
401 tmp_path.append(path_it[0]);
402 path_out.push_back(tmp_path);
403 continue;
404 }
405 double time0 = 0;
406 size_t curve = 0;
407 for (Geom::Path::const_iterator curve_it1 = path_it->begin(); curve_it1 != path_it->end(); ++curve_it1) {
408 size_t next_index = curve + 1;
409 if (curve == pathv[path].size() - 1 && pathv[path].closed()) {
410 next_index = 0;
411 }
412 //append last extreme of paths on open paths
413 if (curve == pathv[path].size() -1 && !pathv[path].closed()) { //the path is open and we are at end of path
414 if (time0 != 1) { //Previous satellite not at 100% amount
415 Geom::Curve *last_curve = curve_it1->portion(time0, 1);
416 last_curve->setInitial(tmp_path.finalPoint());
417 tmp_path.append(*last_curve);
418 }
419 continue;
420 }
421 Geom::Curve const &curve_it2 = pathv[path][next_index];
422 Satellite satellite = satellites[path][next_index];
423 if (Geom::are_near((*curve_it1).initialPoint(), (*curve_it1).finalPoint())) {
424 _degenerate_hide = true;
425 g_warning("Knots hidded if consecutive nodes has the same position.");
426 return path_in;
427 }
428 if (!curve) { //curve == 0
429 if (!path_it->closed()) {
430 time0 = 0;
431 } else {
432 time0 = satellites[path][0].time(*curve_it1);
433 }
434 }
435 double s = satellite.arcDistance(curve_it2);
436 double time1 = satellite.time(s, true, (*curve_it1));
437 double time2 = satellite.time(curve_it2);
438 if (time1 <= time0) {
439 time1 = time0;
440 }
441 if (time2 > 1) {
442 time2 = 1;
443 }
444 Geom::Curve *knot_curve_1 = curve_it1->portion(time0, time1);
445 Geom::Curve *knot_curve_2 = curve_it2.portion(time2, 1);
446 if (curve > 0) {
447 knot_curve_1->setInitial(tmp_path.finalPoint());
448 } else {
449 tmp_path.start((*curve_it1).pointAt(time0));
450 }
451
452 Geom::Point start_arc_point = knot_curve_1->finalPoint();
453 Geom::Point end_arc_point = curve_it2.pointAt(time2);
454 //add a gap helper
455 if (time2 == 1) {
456 end_arc_point = curve_it2.pointAt(time2 - GAP_HELPER);
457 }
458 if (time1 == time0) {
459 start_arc_point = curve_it1->pointAt(time1 + GAP_HELPER);
460 }
461
462 double k1 = distance(start_arc_point, curve_it1->finalPoint()) * K;
463 double k2 = distance(curve_it2.initialPoint(), end_arc_point) * K;
464 Geom::CubicBezier const *cubic_1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_1);
465 Geom::CubicBezier const *cubic_2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_2);
466 Geom::Ray ray_1(start_arc_point, curve_it1->finalPoint());
467 Geom::Ray ray_2(curve_it2.initialPoint(), end_arc_point);
468 if (cubic_1) {
469 ray_1.setPoints((*cubic_1)[2], start_arc_point);
470 }
471 if (cubic_2) {
472 ray_2.setPoints(end_arc_point, (*cubic_2)[1]);
473 }
474 bool ccw_toggle = cross(curve_it1->finalPoint() - start_arc_point, end_arc_point - start_arc_point) < 0;
475 double angle = angle_between(ray_1, ray_2, ccw_toggle);
476 double handle_angle_1 = ray_1.angle() - angle;
477 double handle_angle_2 = ray_2.angle() + angle;
478 if (ccw_toggle) {
479 handle_angle_1 = ray_1.angle() + angle;
480 handle_angle_2 = ray_2.angle() - angle;
481 }
482 Geom::Point handle_1 = Geom::Point::polar(ray_1.angle(), k1) + start_arc_point;
483 Geom::Point handle_2 = end_arc_point - Geom::Point::polar(ray_2.angle(), k2);
484 Geom::Point inverse_handle_1 = Geom::Point::polar(handle_angle_1, k1) + start_arc_point;
485 Geom::Point inverse_handle_2 = end_arc_point - Geom::Point::polar(handle_angle_2, k2);
486 if (time0 == 1) {
487 handle_1 = start_arc_point;
488 inverse_handle_1 = start_arc_point;
489 }
490 //remove gap helper
491 if (time2 == 1) {
492 end_arc_point = curve_it2.pointAt(time2);
493 }
494 if (time1 == time0) {
495 start_arc_point = curve_it1->pointAt(time0);
496 }
497 if (time1 != 1) {
498 if (time1 != time0 || (time1 == 1 && time0 == 1)) {
499 if (!knot_curve_1->isDegenerate()) {
500 tmp_path.append(*knot_curve_1);
501 }
502 }
503 SatelliteType type = satellite.satellite_type;
504 size_t steps = satellite.steps;
505 if (!steps) steps = 1;
506 Geom::Line const x_line(Geom::Point(0, 0), Geom::Point(1, 0));
507 Geom::Line const angled_line(start_arc_point, end_arc_point);
508 double arc_angle = Geom::angle_between(x_line, angled_line);
509 double radius = Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point)) /
510 sin(angle / 2.0);
511 Geom::Coord rx = radius;
512 Geom::Coord ry = rx;
513 bool eliptical = (is_straight_curve(*curve_it1) &&
514 is_straight_curve(curve_it2) && method != FM_BEZIER) ||
515 method == FM_ARC;
516 switch (type) {
517 case CHAMFER:
518 {
519 Geom::Path path_chamfer;
520 path_chamfer.start(tmp_path.finalPoint());
521 if (eliptical) {
522 ccw_toggle = ccw_toggle ? 0 : 1;
523 path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
524 } else {
525 path_chamfer.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point);
526 }
527 addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps);
528 }
529 break;
530 case INVERSE_CHAMFER:
531 {
532 Geom::Path path_chamfer;
533 path_chamfer.start(tmp_path.finalPoint());
534 if (eliptical) {
535 path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
536 } else {
537 path_chamfer.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point);
538 }
539 addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps);
540 }
541 break;
542 case INVERSE_FILLET:
543 {
544 if (eliptical) {
545 tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
546 } else {
547 tmp_path.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point);
548 }
549 }
550 break;
551 default: //fillet
552 {
553 if (eliptical) {
554 ccw_toggle = ccw_toggle ? 0 : 1;
555 tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point);
556 } else {
557 tmp_path.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point);
558 }
559 }
560 break;
561 }
562 } else {
563 if (!knot_curve_1->isDegenerate()) {
564 tmp_path.append(*knot_curve_1);
565 }
566 }
567 curve++;
568 time0 = time2;
569 }
515 if (path_it->closed()) {570 if (path_it->closed()) {
516 const Geom::Curve &closingline = path_it->back_closed(); 571 tmp_path.close();
517 // the closing line segment is always of type 572 }
518 // Geom::LineSegment.573 path++;
519 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {574 path_out.push_back(tmp_path);
520 // closingline.isDegenerate() did not work, because it only checks for
521 // *exact* zero length, which goes wrong for relative coordinates and
522 // rounding errors...
523 // the closing line segment has zero-length. So stop before that one!
524 curve_endit = path_it->end_open();
525 }
526 }
527 unsigned int counterCurves = 0;
528 while (curve_it1 != curve_endit) {
529 Curve *curve_it2Fixed = (*path_it->begin()).duplicate();
530 if(!path_it->closed() || curve_it2 != curve_endit){
531 curve_it2Fixed = (*curve_it2).duplicate();
532 }
533 bool last = curve_it2 == curve_endit;
534 std::vector<double> times = fillet_chamfer_values.get_times(counter, path_in, last);
535 Curve *knotCurve1 = curve_it1->portion(times[0], times[1]);
536 if (counterCurves > 0) {
537 knotCurve1->setInitial(path_out.finalPoint());
538 } else {
539 path_out.start((*curve_it1).pointAt(times[0]));
540 }
541 Curve *knotCurve2 = curve_it2Fixed->portion(times[2], 1);
542 Point startArcPoint = knotCurve1->finalPoint();
543 Point endArcPoint = curve_it2Fixed->pointAt(times[2]);
544 double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K;
545 double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K;
546 Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1);
547 Ray ray1(startArcPoint, curve_it1->finalPoint());
548 if (cubic1) {
549 ray1.setPoints((*cubic1)[2], startArcPoint);
550 }
551 Point handle1 = Point::polar(ray1.angle(),k1) + startArcPoint;
552 Geom::CubicBezier const *cubic2 =
553 dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2);
554 Ray ray2(curve_it1->finalPoint(), endArcPoint);
555 if (cubic2) {
556 ray2.setPoints(endArcPoint, (*cubic2)[1]);
557 }
558 Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2);
559 bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0;
560 double angle = angle_between(ray1, ray2, ccwToggle);
561 double handleAngle = ray1.angle() - angle;
562 if (ccwToggle) {
563 handleAngle = ray1.angle() + angle;
564 }
565 Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint;
566 handleAngle = ray2.angle() + angle;
567 if (ccwToggle) {
568 handleAngle = ray2.angle() - angle;
569 }
570 Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2);
571 //straigth lines arc based
572 Line const x_line(Geom::Point(0,0),Geom::Point(1,0));
573 Line const angled_line(startArcPoint,endArcPoint);
574 double angleArc = Geom::angle_between( x_line,angled_line);
575 double radius = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint))/sin(angle/2.0);
576 Coord rx = radius;
577 Coord ry = rx;
578
579 if (times[1] != 1) {
580 if (times[1] != gapHelper && times[1] != times[0] + gapHelper) {
581 path_out.append(*knotCurve1);
582 }
583 int type = 0;
584 if(path_it->closed() && last){
585 type = std::abs(filletChamferData[counter - counterCurves][Y]);
586 } else if (!path_it->closed() && last){
587 //0
588 } else {
589 type = std::abs(filletChamferData[counter + 1][Y]);
590 }
591 if(are_near(middle_point(startArcPoint,endArcPoint),curve_it1->finalPoint(), 0.0001)){
592 path_out.appendNew<Geom::LineSegment>(endArcPoint);
593 } else if (type >= 3000 && type < 4000) {
594 unsigned int chamferSubs = type-3000;
595 Geom::Path path_chamfer;
596 path_chamfer.start(path_out.finalPoint());
597 if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
598 path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
599 } else {
600 path_chamfer.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint);
601 }
602 double chamfer_stepsTime = 1.0/chamferSubs;
603 for(unsigned int i = 1; i < chamferSubs; i++){
604 Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i);
605 path_out.appendNew<Geom::LineSegment>(chamferStep);
606 }
607 path_out.appendNew<Geom::LineSegment>(endArcPoint);
608 } else if (type >= 4000 && type < 5000) {
609 unsigned int chamferSubs = type-4000;
610 Geom::Path path_chamfer;
611 path_chamfer.start(path_out.finalPoint());
612 if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
613 ccwToggle = ccwToggle?0:1;
614 path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
615 }else{
616 path_chamfer.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint);
617 }
618 double chamfer_stepsTime = 1.0/chamferSubs;
619 for(unsigned int i = 1; i < chamferSubs; i++){
620 Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i);
621 path_out.appendNew<Geom::LineSegment>(chamferStep);
622 }
623 path_out.appendNew<Geom::LineSegment>(endArcPoint);
624 } else if (type == 2) {
625 if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
626 ccwToggle = ccwToggle?0:1;
627 path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
628 }else{
629 path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint);
630 }
631 } else if (type == 1){
632 if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){
633 path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint);
634 } else {
635 path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint);
636 }
637 }
638 } else {
639 path_out.append(*knotCurve1);
640 }
641 if (path_it->closed() && last) {
642 path_out.close();
643 }
644 ++curve_it1;
645 if (curve_it2 != curve_endit) {
646 ++curve_it2;
647 }
648 counter++;
649 counterCurves++;
650 }
651 pathvector_out.push_back(path_out);
652 }575 }
653 return pathvector_out;576 return path_out;
654}577}
655578
656}; //namespace LivePathEffect579}; //namespace LivePathEffect
657580
=== modified file 'src/live_effects/lpe-fillet-chamfer.h'
--- src/live_effects/lpe-fillet-chamfer.h 2015-07-24 18:50:50 +0000
+++ src/live_effects/lpe-fillet-chamfer.h 2017-05-06 17:46:29 +0000
@@ -7,25 +7,22 @@
7 *7 *
8 * Copyright (C) 2014 Author(s)8 * Copyright (C) 2014 Author(s)
9 *9 *
10 * Special thanks to Johan Engelen for the base of the effect -powerstroke-10 * Jabiertxof:Thanks to all people help me
11 * Also to ScislaC for point me to the idea
12 * Also su_v for his construvtive feedback and time
13 * and finaly to Liam P. White for his big help on coding, that save me a lot of hours
14 *11 *
15 * Released under GNU GPL, read the file 'COPYING' for more information12 * Released under GNU GPL, read the file 'COPYING' for more information
16 */13 */
1714
18#include "live_effects/parameter/enum.h"15#include "live_effects/parameter/enum.h"
19#include "live_effects/parameter/bool.h"16#include "live_effects/parameter/satellitesarray.h"
17#include "live_effects/effect.h"
20#include "live_effects/parameter/unit.h"18#include "live_effects/parameter/unit.h"
2119#include "helper/geom-pathvectorsatellites.h"
22#include "live_effects/parameter/filletchamferpointarray.h"20#include "helper/geom-satellite.h"
23#include "live_effects/effect.h"
2421
25namespace Inkscape {22namespace Inkscape {
26namespace LivePathEffect {23namespace LivePathEffect {
2724
28enum FilletMethod {25enum Filletmethod {
29 FM_AUTO,26 FM_AUTO,
30 FM_ARC,27 FM_ARC,
31 FM_BEZIER,28 FM_BEZIER,
@@ -35,41 +32,38 @@
35class LPEFilletChamfer : public Effect {32class LPEFilletChamfer : public Effect {
36public:33public:
37 LPEFilletChamfer(LivePathEffectObject *lpeobject);34 LPEFilletChamfer(LivePathEffectObject *lpeobject);
38 virtual ~LPEFilletChamfer();35 virtual void doBeforeEffect(SPLPEItem const *lpeItem);
39
40 virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in);36 virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in);
41
42 virtual void doOnApply(SPLPEItem const *lpeItem);37 virtual void doOnApply(SPLPEItem const *lpeItem);
43 virtual void doBeforeEffect(SPLPEItem const *lpeItem);38 virtual Gtk::Widget *newWidget();
44 virtual void adjustForNewPath(Geom::PathVector const &path_in);39 Geom::Ray getRay(Geom::Point start, Geom::Point end, Geom::Curve *curve, bool reverse);
45 virtual Gtk::Widget* newWidget();40 void addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps);
4641 void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
47 int getKnotsNumber(SPCurve const *c);42 void updateSatelliteType(SatelliteType satellitetype);
48 void toggleHide();43 void setSelected(PathVectorSatellites *_pathvector_satellites);
49 void toggleFlexFixed();44 //void convertUnit();
50 void chamfer();45 void updateChamferSteps();
51 void chamferSubdivisions();46 void updateAmount();
52 void inverseChamfer();
53 void fillet();
54 void inverseFillet();
55 void updateFillet();
56 void doUpdateFillet(Geom::PathVector const& original_pathv, double power);
57 void doChangeType(Geom::PathVector const& original_pathv, int type);
58 void refreshKnots();47 void refreshKnots();
5948
60 FilletChamferPointArrayParam fillet_chamfer_values;49 SatellitesArrayParam satellites_param;
6150
62private:51private:
6352 UnitParam unit;
64 BoolParam hide_knots;53 EnumParam<Filletmethod> method;
65 BoolParam ignore_radius_0;54 ScalarParam radius;
55 ScalarParam chamfer_steps;
56 BoolParam flexible;
57 BoolParam mirror_knots;
66 BoolParam only_selected;58 BoolParam only_selected;
67 BoolParam flexible;
68 BoolParam use_knot_distance;59 BoolParam use_knot_distance;
69 EnumParam<FilletMethod> method;60 BoolParam hide_knots;
70 ScalarParam radius;61 BoolParam apply_no_radius;
71 ScalarParam chamfer_steps;62 BoolParam apply_with_radius;
72 ScalarParam helper_size;63 ScalarParam helper_size;
64 bool _degenerate_hide;
65 PathVectorSatellites *_pathvector_satellites;
66 Geom::PathVector _hp;
7367
74 LPEFilletChamfer(const LPEFilletChamfer &);68 LPEFilletChamfer(const LPEFilletChamfer &);
75 LPEFilletChamfer &operator=(const LPEFilletChamfer &);69 LPEFilletChamfer &operator=(const LPEFilletChamfer &);
7670
=== modified file 'src/live_effects/parameter/array.cpp'
--- src/live_effects/parameter/array.cpp 2014-03-27 01:33:44 +0000
+++ src/live_effects/parameter/array.cpp 2017-05-06 17:46:29 +0000
@@ -5,10 +5,7 @@
5 */5 */
66
7#include "live_effects/parameter/array.h"7#include "live_effects/parameter/array.h"
88#include "helper-fns.h"
9#include "svg/svg.h"
10#include "svg/stringstream.h"
11
12#include <2geom/coord.h>9#include <2geom/coord.h>
13#include <2geom/point.h>10#include <2geom/point.h>
1411
@@ -49,6 +46,45 @@
49 return Geom::Point(Geom::infinity(),Geom::infinity());46 return Geom::Point(Geom::infinity(),Geom::infinity());
50}47}
5148
49
50template <>
51std::vector<Satellite>
52ArrayParam<std::vector<Satellite > >::readsvg(const gchar * str)
53{
54 std::vector<Satellite> subpath_satellites;
55 if (!str) {
56 return subpath_satellites;
57 }
58 gchar ** strarray = g_strsplit(str, "@", 0);
59 gchar ** iter = strarray;
60 while (*iter != NULL) {
61 gchar ** strsubarray = g_strsplit(*iter, ",", 8);
62 if (*strsubarray[7]) {//steps always > 0
63 Satellite *satellite = new Satellite();
64 satellite->setSatelliteType(g_strstrip(strsubarray[0]));
65 satellite->is_time = strncmp(strsubarray[1],"1",1) == 0;
66 satellite->selected = strncmp(strsubarray[2],"1",1) == 0;
67 satellite->has_mirror = strncmp(strsubarray[3],"1",1) == 0;
68 satellite->hidden = strncmp(strsubarray[4],"1",1) == 0;
69 double amount,angle;
70 float stepsTmp;
71 sp_svg_number_read_d(strsubarray[5], &amount);
72 sp_svg_number_read_d(strsubarray[6], &angle);
73 sp_svg_number_read_f(g_strstrip(strsubarray[7]), &stepsTmp);
74 unsigned int steps = (unsigned int)stepsTmp;
75 satellite->amount = amount;
76 satellite->angle = angle;
77 satellite->steps = steps;
78 subpath_satellites.push_back(*satellite);
79 }
80 g_strfreev (strsubarray);
81 iter++;
82 }
83 g_strfreev (strarray);
84 return subpath_satellites;
85}
86
87
52} /* namespace LivePathEffect */88} /* namespace LivePathEffect */
5389
54} /* namespace Inkscape */90} /* namespace Inkscape */
5591
=== modified file 'src/live_effects/parameter/array.h'
--- src/live_effects/parameter/array.h 2017-04-29 00:01:22 +0000
+++ src/live_effects/parameter/array.h 2017-05-06 17:46:29 +0000
@@ -15,6 +15,7 @@
1515
16#include "live_effects/parameter/parameter.h"16#include "live_effects/parameter/parameter.h"
1717
18#include "helper/geom-satellite.h"
18#include "svg/svg.h"19#include "svg/svg.h"
19#include "svg/stringstream.h"20#include "svg/stringstream.h"
2021
@@ -93,7 +94,43 @@
93 // separate items with pipe symbol94 // separate items with pipe symbol
94 str << " | ";95 str << " | ";
95 }96 }
96 str << vector[i];97 writesvgData(str,vector[i]);
98 }
99 }
100
101 void writesvgData(SVGOStringStream &str, float const &vector_data) const {
102 str << vector_data;
103 }
104
105 void writesvgData(SVGOStringStream &str, double const &vector_data) const {
106 str << vector_data;
107 }
108
109 void writesvgData(SVGOStringStream &str, Geom::Point const &vector_data) const {
110 str << vector_data;
111 }
112
113 void writesvgData(SVGOStringStream &str, std::vector<Satellite> const &vector_data) const {
114 for (size_t i = 0; i < vector_data.size(); ++i) {
115 if (i != 0) {
116 // separate items with @ symbol ¿Any other?
117 str << " @ ";
118 }
119 str << vector_data[i].getSatelliteTypeGchar();
120 str << ",";
121 str << vector_data[i].is_time;
122 str << ",";
123 str << vector_data[i].selected;
124 str << ",";
125 str << vector_data[i].has_mirror;
126 str << ",";
127 str << vector_data[i].hidden;
128 str << ",";
129 str << vector_data[i].amount;
130 str << ",";
131 str << vector_data[i].angle;
132 str << ",";
133 str << vector_data[i].steps;
97 }134 }
98 }135 }
99136
100137
=== removed file 'src/live_effects/parameter/filletchamferpointarray.cpp'
--- src/live_effects/parameter/filletchamferpointarray.cpp 2016-12-19 20:54:42 +0000
+++ src/live_effects/parameter/filletchamferpointarray.cpp 1970-01-01 00:00:00 +0000
@@ -1,873 +0,0 @@
1/*
2 * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
3 * Special thanks to Johan Engelen for the base of the effect -powerstroke-
4 * Also to ScislaC for point me to the idea
5 * Also su_v for his construvtive feedback and time
6 * and finaly to Liam P. White for his big help on coding, that save me a lot of
7 * hours
8 * Released under GNU GPL, read the file 'COPYING' for more information
9 */
10
11#include <2geom/piecewise.h>
12#include <2geom/sbasis-to-bezier.h>
13#include <2geom/sbasis-geometric.h>
14#include <2geom/line.h>
15#include <2geom/path-intersection.h>
16
17#include "ui/dialog/lpe-fillet-chamfer-properties.h"
18#include "live_effects/parameter/filletchamferpointarray.h"
19#include "live_effects/effect.h"
20#include "svg/svg.h"
21#include "svg/stringstream.h"
22#include "knotholder.h"
23#include "sp-lpe-item.h"
24#include "selection.h"
25
26// needed for on-canvas editting:
27#include "live_effects/lpeobject.h"
28#include "helper/geom-nodetype.h"
29#include "helper/geom-curves.h"
30#include "ui/tools/node-tool.h"
31
32// TODO due to internal breakage in glibmm headers,
33// this has to be included last.
34#include <glibmm/i18n.h>
35
36
37using namespace Geom;
38
39namespace Inkscape {
40
41namespace LivePathEffect {
42
43FilletChamferPointArrayParam::FilletChamferPointArrayParam(
44 const Glib::ustring &label, const Glib::ustring &tip,
45 const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr,
46 Effect *effect)
47 : ArrayParam<Point>(label, tip, key, wr, effect, 0)
48{
49 knot_shape = SP_KNOT_SHAPE_DIAMOND;
50 knot_mode = SP_KNOT_MODE_XOR;
51 knot_color = 0x00ff0000;
52}
53
54FilletChamferPointArrayParam::~FilletChamferPointArrayParam() {}
55
56Gtk::Widget *FilletChamferPointArrayParam::param_newWidget()
57{
58 return NULL;
59 /*
60 Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg =
61 Gtk::manage(
62 new Inkscape::UI::Widget::RegisteredTransformedPoint(
63 param_label,
64 param_tooltip,
65 param_key,
66 *param_wr,
67 param_effect->getRepr(),
68 param_effect->getSPDoc()
69 ) );
70 // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP)
71 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
72 Affine transf = desktop->doc2dt();
73 pointwdg->setTransform(transf);
74 pointwdg->setValue( *this );
75 pointwdg->clearProgrammatically();
76 pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT,
77 _("Change point parameter"));
78
79 Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() );
80 static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true);
81 static_cast<Gtk::HBox*>(hbox)->show_all_children();
82
83 return dynamic_cast<Gtk::Widget *> (hbox);
84 */
85}
86
87void
88FilletChamferPointArrayParam::param_transform_multiply(Affine const &postmul,
89 bool /*set*/)
90{
91 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
92
93 if (prefs->getBool("/options/transform/rectcorners", true) &&
94 _vector[1][X] <= 0) {
95 std::vector<Geom::Point> result;
96 for (std::vector<Point>::const_iterator point_it = _vector.begin();
97 point_it != _vector.end(); ++point_it) {
98 Coord A =
99 (*point_it)[X] * ((postmul.expansionX() + postmul.expansionY()) / 2);
100 result.push_back(Point(A, (*point_it)[Y]));
101 }
102 param_set_and_write_new_value(result);
103 }
104
105 // param_set_and_write_new_value( (*this) * postmul );
106}
107
108/** call this method to recalculate the controlpoints such that they stay at the
109 * same location relative to the new path. Useful after adding/deleting nodes to
110 * the path.*/
111void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2(
112 Piecewise<D2<SBasis> > const &pwd2_in)
113{
114 if (!last_pwd2.empty()) {
115 PathVector const pathv =
116 path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001);
117 PathVector last_pathv =
118 path_from_piecewise(remove_short_cuts(last_pwd2, 0.1), 0.001);
119 std::vector<Point> result;
120 unsigned long counter = 0;
121 unsigned long counterPaths = 0;
122 unsigned long counterCurves = 0;
123 long offset = 0;
124 long offsetPaths = 0;
125 Geom::NodeType nodetype;
126 for (PathVector::const_iterator path_it = pathv.begin();
127 path_it != pathv.end(); ++path_it) {
128 if (path_it->empty()) {
129 counterPaths++;
130 counter++;
131 continue;
132 }
133 Geom::Path::const_iterator curve_it1 = path_it->begin();
134 Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
135 Geom::Path::const_iterator curve_endit = path_it->end_default();
136 if (path_it->closed() && path_it->back_closed().isDegenerate()) {
137 const Curve &closingline = path_it->back_closed();
138 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
139 curve_endit = path_it->end_open();
140 }
141 }
142 counterCurves = 0;
143 while (curve_it1 != curve_endit) {
144 //if start a path get node type
145 if (counterCurves == 0) {
146 if (path_it->closed()) {
147 if (path_it->back_closed().isDegenerate()) {
148 nodetype = get_nodetype(path_it->back_open(), *curve_it1);
149 } else {
150 nodetype = get_nodetype(path_it->back_closed(), *curve_it1);
151 }
152 } else {
153 nodetype = NODE_NONE;
154 }
155 } else {
156 //check node type also whith straight lines because get_nodetype
157 //return non cusp node in a node inserted inside a straight line
158 //todo: if the path remove some nodes whith the result of a straight
159 //line but with handles, the node inserted into dont fire the knot
160 // because is not handle as cusp node by get_nodetype function
161 bool next_is_line = is_straight_curve(*curve_it1);
162 bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
163 nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
164 if (this_is_line || next_is_line) {
165 nodetype = NODE_CUSP;
166 }
167 }
168 if (last_pathv.size() > pathv.size() ||
169 (last_pathv.size() > counterPaths &&
170 last_pathv[counterPaths].size() > counter - offset &&
171 !are_near(curve_it1->initialPoint(),
172 last_pathv[counterPaths][counter - offset].initialPoint(),
173 0.1))) {
174 if ( curve_it2 == curve_endit) {
175 if (last_pathv[counterPaths].size() != pathv[counterPaths].size()) {
176 offset = (last_pathv[counterPaths].size() - pathv[counterPaths].size()) * -1;
177 } else {
178 offset = 0;
179 }
180 offsetPaths += offset;
181 offset = offsetPaths;
182 } else if (counterCurves == 0 && last_pathv.size() <= pathv.size() &&
183 counter - offset <= last_pathv[counterPaths].size() &&
184 are_near(curve_it1->initialPoint(),
185 last_pathv[counterPaths].finalPoint(), 0.1) &&
186 !last_pathv[counterPaths].closed()) {
187 long e = counter - offset + 1;
188 std::vector<Point> tmp = _vector;
189 for (unsigned long i =
190 last_pathv[counterPaths].size() + counter - offset;
191 i > counterCurves - offset + 1; i--) {
192
193 if (tmp[i - 1][X] > 0) {
194 double fractpart, intpart;
195 fractpart = modf(tmp[i - 1][X], &intpart);
196 _vector[e] = Point(e + fractpart, tmp[i - 1][Y]);
197 } else {
198 _vector[e] = Point(tmp[i - 1][X], tmp[i - 1][Y]);
199 }
200 e++;
201 }
202 //delete temp vector
203 std::vector<Point>().swap(tmp);
204 if (last_pathv.size() > counterPaths) {
205 last_pathv[counterPaths] = last_pathv[counterPaths].reversed();
206 }
207 } else {
208 if (last_pathv.size() > counterPaths) {
209 if (last_pathv[counterPaths].size() <
210 pathv[counterPaths].size()) {
211 offset++;
212 } else if (last_pathv[counterPaths].size() >
213 pathv[counterPaths].size()) {
214 offset--;
215 continue;
216 }
217 } else {
218 offset++;
219 }
220 }
221 double xPos = 0;
222 if (_vector[1][X] > 0) {
223 xPos = nearest_time(curve_it1->initialPoint(), pwd2_in);
224 }
225 if (nodetype == NODE_CUSP) {
226 result.push_back(Point(xPos, 1));
227 } else {
228 result.push_back(Point(xPos, 0));
229 }
230 } else {
231 double xPos = _vector[counter - offset][X];
232 if (_vector.size() <= (unsigned)(counter - offset)) {
233 if (_vector[1][X] > 0) {
234 xPos = nearest_time(curve_it1->initialPoint(), pwd2_in);
235 } else {
236 xPos = 0;
237 }
238 }
239 if (nodetype == NODE_CUSP) {
240 double vectorY = _vector[counter - offset][Y];
241 if (_vector.size() <= (unsigned)(counter - offset) || vectorY == 0) {
242 vectorY = 1;
243 }
244 result.push_back(Point(xPos, vectorY));
245 } else {
246 if (_vector[1][X] < 0) {
247 xPos = 0;
248 }
249 result.push_back(Point(floor(xPos), 0));
250 }
251 }
252 ++curve_it1;
253 if (curve_it2 != curve_endit) {
254 ++curve_it2;
255 }
256 counter++;
257 counterCurves++;
258 }
259 counterPaths++;
260 }
261 _vector = result;
262 write_to_SVG();
263 }
264}
265
266void FilletChamferPointArrayParam::recalculate_knots(
267 Piecewise<D2<SBasis> > const &pwd2_in)
268{
269 bool change = false;
270 if(_vector.size() == 0){
271 return;
272 }
273 PathVector pathv = path_from_piecewise(pwd2_in, 0.001);
274 if (!pathv.empty()) {
275 std::vector<Point> result;
276 int counter = 0;
277 int counterCurves = 0;
278 Geom::NodeType nodetype;
279 for (PathVector::const_iterator path_it = pathv.begin();
280 path_it != pathv.end(); ++path_it) {
281 if (path_it->empty()) {
282 counter++;
283 continue;
284 }
285 Geom::Path::const_iterator curve_it1 = path_it->begin();
286 Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
287 Geom::Path::const_iterator curve_endit = path_it->end_default();
288 if (path_it->closed() && path_it->back_closed().isDegenerate()) {
289 const Curve &closingline = path_it->back_closed();
290 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
291 curve_endit = path_it->end_open();
292 }
293 }
294 counterCurves = 0;
295 while (curve_it1 != curve_endit) {
296 //if start a path get node type
297 if (counterCurves == 0) {
298 if (path_it->closed()) {
299 if (path_it->back_closed().isDegenerate()) {
300 nodetype = get_nodetype(path_it->back_open(), *curve_it1);
301 } else {
302 nodetype = get_nodetype(path_it->back_closed(), *curve_it1);
303 }
304 } else {
305 nodetype = NODE_NONE;
306 }
307 } else {
308 bool next_is_line = is_straight_curve(*curve_it1);
309 bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
310 nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
311 if (this_is_line || next_is_line) {
312 nodetype = NODE_CUSP;
313 }
314 }
315 if (nodetype == NODE_CUSP) {
316 double vectorY = _vector[counter][Y];
317 if (vectorY == 0) {
318 vectorY = 1;
319 change = true;
320 }
321 result.push_back(Point(_vector[counter][X], vectorY));
322 } else {
323 double xPos = floor(_vector[counter][X]);
324 if (_vector[1][X] < 0) {
325 xPos = 0;
326 }
327 double vectorY = _vector[counter][Y];
328 if (vectorY != 0) {
329 change = true;
330 }
331 result.push_back(Point(xPos, 0));
332 }
333 ++curve_it1;
334 counter++;
335 if (curve_it2 != curve_endit) {
336 ++curve_it2;
337 }
338 counterCurves++;
339 }
340 }
341 if (change) {
342 _vector = result;
343 write_to_SVG();
344 }
345 }
346}
347
348void FilletChamferPointArrayParam::set_pwd2(
349 Piecewise<D2<SBasis> > const &pwd2_in,
350 Piecewise<D2<SBasis> > const &pwd2_normal_in)
351{
352 last_pwd2 = pwd2_in;
353 last_pwd2_normal = pwd2_normal_in;
354}
355
356void FilletChamferPointArrayParam::set_helper_size(int hs)
357{
358 helper_size = hs;
359}
360
361void FilletChamferPointArrayParam::set_chamfer_steps(int value_chamfer_steps)
362{
363 chamfer_steps = value_chamfer_steps;
364}
365
366void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance )
367{
368 use_distance = use_knot_distance;
369}
370
371void FilletChamferPointArrayParam::updateCanvasIndicators()
372{
373 std::vector<Point> ts = data();
374 hp.clear();
375 unsigned int i = 0;
376 for (std::vector<Point>::const_iterator point_it = ts.begin();
377 point_it != ts.end(); ++point_it) {
378 double Xvalue = to_time(i, (*point_it)[X]) -i;
379 if (Xvalue == 0) {
380 i++;
381 continue;
382 }
383 Geom::Point ptA = last_pwd2[i].valueAt(Xvalue);
384 Geom::Point derivA = unit_vector(derivative(last_pwd2[i]).valueAt(Xvalue));
385 Geom::Rotate rot(Geom::Rotate::from_degrees(-90));
386 derivA = derivA * rot;
387 Geom::Point C = ptA - derivA * helper_size;
388 Geom::Point D = ptA + derivA * helper_size;
389 Geom::Ray ray1(C, D);
390 char const * svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5";
391 Geom::PathVector pathv = sp_svg_read_pathv(svgd);
392 Geom::Affine aff = Geom::Affine();
393 aff *= Geom::Scale(helper_size);
394 aff *= Geom::Rotate(ray1.angle() - rad_from_deg(270));
395 aff *= Geom::Translate(last_pwd2[i].valueAt(Xvalue));
396 pathv *= aff;
397 hp.push_back(pathv[0]);
398 hp.push_back(pathv[1]);
399 i++;
400 }
401}
402
403void FilletChamferPointArrayParam::addCanvasIndicators(
404 SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
405{
406 hp_vec.push_back(hp);
407}
408
409double FilletChamferPointArrayParam::rad_to_len(int index, double rad)
410{
411 double len = 0;
412 Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1);
413 std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
414 D2<SBasis> A = last_pwd2[last_index(index, subpaths)];
415 if(positions.second != 0){
416 A = last_pwd2[index-1];
417 }else{
418 if(!subpaths[positions.first].closed()){
419 return len;
420 }
421 }
422 D2<SBasis> B = last_pwd2[index];
423 Piecewise<D2<SBasis> > offset_curve0 = Piecewise<D2<SBasis> >(A)+rot90(unitVector(derivative(A)))*(rad);
424 Piecewise<D2<SBasis> > offset_curve1 = Piecewise<D2<SBasis> >(B)+rot90(unitVector(derivative(B)))*(rad);
425 Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0];
426 Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0];
427 Geom::Crossings cs = Geom::crossings(p0, p1);
428 if(cs.size() > 0){
429 Point cp =p0(cs[0].ta);
430 double p0pt = nearest_time(cp, B);
431 len = time_to_len(index,p0pt);
432 } else {
433 if(rad < 0){
434 len = rad_to_len(index, rad * -1);
435 }
436 }
437 return len;
438}
439
440double FilletChamferPointArrayParam::len_to_rad(int index, double len)
441{
442 double rad = 0;
443 double tmp_len = _vector[index][X];
444 _vector[index] = Geom::Point(len,_vector[index][Y]);
445 Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1);
446 std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
447 Piecewise<D2<SBasis> > u;
448 u.push_cut(0);
449 u.push(last_pwd2[last_index(index, subpaths)], 1);
450 Geom::Curve * A = path_from_piecewise(u, 0.1)[0][0].duplicate();
451 Geom::Curve * B = subpaths[positions.first][positions.second].duplicate();
452 std::vector<double> times;
453 if(positions.second != 0){
454 A = subpaths[positions.first][positions.second-1].duplicate();
455 times = get_times(index-1, subpaths, false);
456 }else{
457 if(!subpaths[positions.first].closed()){
458 return rad;
459 }
460 times = get_times(last_index(index, subpaths), subpaths, true);
461 }
462 _vector[index] = Geom::Point(tmp_len,_vector[index][Y]);
463 Geom::Point startArcPoint = A->toSBasis().valueAt(times[1]);
464 Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]);
465 Curve *knotCurve1 = A->portion(times[0], times[1]);
466 Curve *knotCurve2 = B->portion(times[2], 1);
467 Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(knotCurve1);
468 Ray ray1(startArcPoint, A->finalPoint());
469 if (cubic1) {
470 ray1.setPoints((*cubic1)[2], startArcPoint);
471 }
472 Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(knotCurve2);
473 Ray ray2(B->initialPoint(), endArcPoint);
474 if (cubic2) {
475 ray2.setPoints(endArcPoint, (*cubic2)[1]);
476 }
477 bool ccwToggle = cross(A->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0;
478 double distanceArc = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint));
479 double angleBetween = angle_between(ray1, ray2, ccwToggle);
480 rad = distanceArc/sin(angleBetween/2.0);
481 return rad * -1;
482}
483
484std::vector<double> FilletChamferPointArrayParam::get_times(int index, Geom::PathVector subpaths, bool last)
485{
486 const double tolerance = 0.001;
487 const double gapHelper = 0.00001;
488 std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
489 Curve *curve_it1;
490 curve_it1 = subpaths[positions.first][positions.second].duplicate();
491 Coord it1_length = (*curve_it1).length(tolerance);
492 double time_it1, time_it2, time_it1_B, intpart;
493 if (static_cast<int>(_vector.size()) <= index){
494 std::vector<double> out;
495 out.push_back(0);
496 out.push_back(1);
497 out.push_back(0);
498 return out;
499 }
500 time_it1 = modf(to_time(index, _vector[index][X]), &intpart);
501 if (_vector[index][Y] == 0) {
502 time_it1 = 0;
503 }
504 double resultLenght = 0;
505 if (subpaths[positions.first].closed() && last) {
506 time_it2 = modf(to_time(index - positions.second , _vector[index - positions.second ][X]), &intpart);
507 resultLenght = it1_length + to_len(index - positions.second, _vector[index - positions.second ][X]);
508 } else if (!subpaths[positions.first].closed() && last){
509 time_it2 = 0;
510 resultLenght = 0;
511 } else {
512 time_it2 = modf(to_time(index + 1, _vector[index + 1][X]), &intpart);
513 resultLenght = it1_length + to_len( index + 1, _vector[index + 1][X]);
514 }
515 if (resultLenght > 0 && time_it2 != 0) {
516 time_it1_B = modf(to_time(index, -resultLenght), &intpart);
517 } else {
518 if (time_it2 == 0) {
519 time_it1_B = 1;
520 } else {
521 time_it1_B = gapHelper;
522 }
523 }
524
525 if ((subpaths[positions.first].closed() && last && _vector[index - positions.second][Y] == 0) || (subpaths[positions.first].size() > positions.second + 1 && _vector[index + 1][Y] == 0)) {
526 time_it1_B = 1;
527 time_it2 = 0;
528 }
529 if (time_it1_B < time_it1) {
530 time_it1_B = time_it1 + gapHelper;
531 }
532 std::vector<double> out;
533 out.push_back(time_it1);
534 out.push_back(time_it1_B);
535 out.push_back(time_it2);
536 return out;
537}
538
539std::pair<std::size_t, std::size_t> FilletChamferPointArrayParam::get_positions(int index, Geom::PathVector subpaths)
540{
541 int counter = -1;
542 std::size_t first = 0;
543 std::size_t second = 0;
544 for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) {
545 if (path_it->empty())
546 continue;
547 Geom::Path::const_iterator curve_it1 = path_it->begin();
548 Geom::Path::const_iterator curve_endit = path_it->end_default();
549 if (path_it->closed()) {
550 const Geom::Curve &closingline = path_it->back_closed();
551 // the closing line segment is always of type
552 // Geom::LineSegment.
553 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
554 // closingline.isDegenerate() did not work, because it only checks for
555 // *exact* zero length, which goes wrong for relative coordinates and
556 // rounding errors...
557 // the closing line segment has zero-length. So stop before that one!
558 curve_endit = path_it->end_open();
559 }
560 }
561 first++;
562 second = 0;
563 while (curve_it1 != curve_endit) {
564 counter++;
565 second++;
566 if(counter == index){
567 break;
568 }
569 ++curve_it1;
570 }
571 if(counter == index){
572 break;
573 }
574 }
575 first--;
576 second--;
577 std::pair<std::size_t, std::size_t> out(first, second);
578 return out;
579}
580
581int FilletChamferPointArrayParam::last_index(int index, Geom::PathVector subpaths)
582{
583 int counter = -1;
584 bool inSubpath = false;
585 for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) {
586 if (path_it->empty())
587 continue;
588 Geom::Path::const_iterator curve_it1 = path_it->begin();
589 Geom::Path::const_iterator curve_endit = path_it->end_default();
590 if (path_it->closed()) {
591 const Geom::Curve &closingline = path_it->back_closed();
592 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
593 curve_endit = path_it->end_open();
594 }
595 }
596 while (curve_it1 != curve_endit) {
597 counter++;
598 if(counter == index){
599 inSubpath = true;
600 }
601 ++curve_it1;
602 }
603 if(inSubpath){
604 break;
605 }
606 }
607 if(!inSubpath){
608 counter = -1;
609 }
610 return counter;
611}
612
613
614double FilletChamferPointArrayParam::len_to_time(int index, double len)
615{
616 double t = 0;
617 if (last_pwd2.size() > (unsigned) index) {
618 if (len != 0) {
619 if (last_pwd2[index][0].degreesOfFreedom() != 2) {
620 Piecewise<D2<SBasis> > u;
621 u.push_cut(0);
622 u.push(last_pwd2[index], 1);
623 std::vector<double> t_roots = roots(arcLengthSb(u) - std::abs(len));
624 if (t_roots.size() > 0) {
625 t = t_roots[0];
626 }
627 } else {
628 double lenghtPart = 0;
629 if (last_pwd2.size() > (unsigned) index) {
630 lenghtPart = length(last_pwd2[index], EPSILON);
631 }
632 if (std::abs(len) < lenghtPart && lenghtPart != 0) {
633 t = std::abs(len) / lenghtPart;
634 }
635 }
636 }
637 t = double(index) + t;
638 } else {
639 t = double(last_pwd2.size() - 1);
640 }
641
642 return t;
643}
644
645double FilletChamferPointArrayParam::time_to_len(int index, double time)
646{
647 double intpart;
648 double len = 0;
649 time = modf(time, &intpart);
650 double lenghtPart = 0;
651 if (last_pwd2.size() <= (unsigned) index || time == 0) {
652 return len;
653 }
654 if (last_pwd2[index][0].degreesOfFreedom() != 2) {
655 Piecewise<D2<SBasis> > u;
656 u.push_cut(0);
657 u.push(last_pwd2[index], 1);
658 u = portion(u, 0, time);
659 return length(u, 0.001) * -1;
660 }
661 lenghtPart = length(last_pwd2[index], EPSILON);
662 return (time * lenghtPart) * -1;
663}
664
665double FilletChamferPointArrayParam::to_time(int index, double A)
666{
667 if (A > 0) {
668 return A;
669 } else {
670 return len_to_time(index, A);
671 }
672}
673
674double FilletChamferPointArrayParam::to_len(int index, double A)
675{
676 if (A > 0) {
677 return time_to_len(index, A);
678 } else {
679 return A;
680 }
681}
682
683void FilletChamferPointArrayParam::set_oncanvas_looks(SPKnotShapeType shape,
684 SPKnotModeType mode,
685 guint32 color)
686{
687 knot_shape = shape;
688 knot_mode = mode;
689 knot_color = color;
690}
691
692FilletChamferPointArrayParamKnotHolderEntity::
693FilletChamferPointArrayParamKnotHolderEntity(
694 FilletChamferPointArrayParam *p, unsigned int index)
695 : _pparam(p), _index(index) {}
696
697void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p,
698 Point const &/*origin*/,
699 guint state)
700{
701 using namespace Geom;
702
703 if (!valid_index(_index)) {
704 return;
705 }
706 Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2();
707 double t = nearest_time(p, pwd2[_index]);
708 Geom::Point const s = snap_knot_position(pwd2[_index].valueAt(t), state);
709 t = nearest_time(s, pwd2[_index]);
710 if (t == 1) {
711 t = 0.9999;
712 }
713 t += _index;
714
715 if (_pparam->_vector.at(_index)[X] <= 0) {
716 _pparam->_vector.at(_index) =
717 Point(_pparam->time_to_len(_index, t), _pparam->_vector.at(_index)[Y]);
718 } else {
719 _pparam->_vector.at(_index) = Point(t, _pparam->_vector.at(_index)[Y]);
720 }
721 sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
722}
723
724Point FilletChamferPointArrayParamKnotHolderEntity::knot_get() const
725{
726 using namespace Geom;
727
728 if (!valid_index(_index)) {
729 return Point(infinity(), infinity());
730 }
731
732 Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2();
733
734 double time_it = _pparam->to_time(_index, _pparam->_vector.at(_index)[X]);
735 Point canvas_point = pwd2.valueAt(time_it);
736
737 _pparam->updateCanvasIndicators();
738 return canvas_point;
739
740}
741
742void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state)
743{
744 if (state & GDK_CONTROL_MASK) {
745 if (state & GDK_MOD1_MASK) {
746 _pparam->_vector.at(_index) = Point(_index, _pparam->_vector.at(_index)[Y]);
747 _pparam->param_set_and_write_new_value(_pparam->_vector);
748 sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
749 }else{
750 using namespace Geom;
751 int type = (int)_pparam->_vector.at(_index)[Y];
752 if (type >=3000 && type < 4000){
753 type = 3;
754 }
755 if (type >=4000 && type < 5000){
756 type = 4;
757 }
758 switch(type){
759 case 1:
760 type = 2;
761 break;
762 case 2:
763 type = _pparam->chamfer_steps + 3000;
764 break;
765 case 3:
766 type = _pparam->chamfer_steps + 4000;
767 break;
768 default:
769 type = 1;
770 break;
771 }
772 _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], (double)type);
773 _pparam->param_set_and_write_new_value(_pparam->_vector);
774 sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
775 const gchar *tip;
776 if (type >=3000 && type < 4000){
777 tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
778 "<b>Shift+Click</b> open dialog, "
779 "<b>Ctrl+Alt+Click</b> reset");
780 } else if (type >=4000 && type < 5000) {
781 tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
782 "<b>Shift+Click</b> open dialog, "
783 "<b>Ctrl+Alt+Click</b> reset");
784 } else if (type == 2) {
785 tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, "
786 "<b>Shift+Click</b> open dialog, "
787 "<b>Ctrl+Alt+Click</b> reset");
788 } else {
789 tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, "
790 "<b>Shift+Click</b> open dialog, "
791 "<b>Ctrl+Alt+Click</b> reset");
792 }
793 this->knot->tip = g_strdup(tip);
794 this->knot->show();
795 }
796 } else if (state & GDK_SHIFT_MASK) {
797 double xModified = _pparam->_vector.at(_index).x();
798 if(xModified < 0 && !_pparam->use_distance){
799 xModified = _pparam->len_to_rad(_index, _pparam->_vector.at(_index).x());
800 }
801 Geom::PathVector subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1);
802 std::pair<std::size_t, std::size_t> positions = _pparam->get_positions(_index, subpaths);
803 D2<SBasis> A = _pparam->last_pwd2[_pparam->last_index(_index, subpaths)];
804 if(positions.second != 0){
805 A = _pparam->last_pwd2[_index-1];
806 }
807 D2<SBasis> B = _pparam->last_pwd2[_index];
808 bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false;
809 Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y());
810 Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog(
811 this->desktop, offset, this, _pparam->use_distance, aprox);
812 }
813
814}
815
816void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset(
817 Geom::Point offset)
818{
819 double xModified = offset.x();
820 if(xModified < 0 && !_pparam->use_distance){
821 xModified = _pparam->rad_to_len(_index, offset.x());
822 }
823 _pparam->_vector.at(_index) = Geom::Point(xModified, offset.y());
824 this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
825}
826
827void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) {
828 recalculate_knots(get_pwd2());
829 for (unsigned int i = 0; i < _vector.size(); ++i) {
830 if (_vector[i][Y] <= 0) {
831 continue;
832 }
833 const gchar *tip;
834 if (_vector[i][Y] >=3000 && _vector[i][Y] < 4000){
835 tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
836 "<b>Shift+Click</b> open dialog, "
837 "<b>Ctrl+Alt+Click</b> reset");
838 } else if (_vector[i][Y] >=4000 && _vector[i][Y] < 5000) {
839 tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, "
840 "<b>Shift+Click</b> open dialog, "
841 "<b>Ctrl+Alt+Click</b> reset");
842 } else if (_vector[i][Y] == 2) {
843 tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, "
844 "<b>Shift+Click</b> open dialog, "
845 "<b>Ctrl+Alt+Click</b> reset");
846 } else {
847 tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, "
848 "<b>Shift+Click</b> open dialog, "
849 "<b>Ctrl+Alt+Click</b> reset");
850 }
851 FilletChamferPointArrayParamKnotHolderEntity *e =
852 new FilletChamferPointArrayParamKnotHolderEntity(this, i);
853 e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),
854 knot_shape, knot_mode, knot_color);
855 knotholder->add(e);
856 }
857 updateCanvasIndicators();
858}
859
860} /* namespace LivePathEffect */
861
862} /* namespace Inkscape */
863
864/*
865 Local Variables:
866 mode:c++
867 c-file-style:"stroustrup"
868 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
869 indent-tabs-mode:nil
870 fill-column:99
871 End:
872*/
873// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
8740
=== removed file 'src/live_effects/parameter/filletchamferpointarray.h'
--- src/live_effects/parameter/filletchamferpointarray.h 2017-04-29 00:01:22 +0000
+++ src/live_effects/parameter/filletchamferpointarray.h 1970-01-01 00:00:00 +0000
@@ -1,123 +0,0 @@
1#ifndef INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
2#define INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
3
4/*
5 * Inkscape::LivePathEffectParameters
6 * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
7 * Special thanks to Johan Engelen for the base of the effect -powerstroke-
8 * Also to ScislaC for point me to the idea
9 * Also su_v for his construvtive feedback and time
10 * and finaly to Liam P. White for his big help on coding, that save me a lot of
11 * hours
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
14
15#include <glib.h>
16#include <2geom/point.h>
17
18#include "live_effects/parameter/array.h"
19
20#include "knot-holder-entity.h"
21
22namespace Inkscape {
23
24namespace LivePathEffect {
25
26class FilletChamferPointArrayParamKnotHolderEntity;
27
28class FilletChamferPointArrayParam : public ArrayParam<Geom::Point> {
29public:
30 FilletChamferPointArrayParam(const Glib::ustring &label,
31 const Glib::ustring &tip,
32 const Glib::ustring &key,
33 Inkscape::UI::Widget::Registry *wr,
34 Effect *effect);
35 virtual ~FilletChamferPointArrayParam();
36
37 virtual Gtk::Widget *param_newWidget();
38
39 virtual void param_transform_multiply(Geom::Affine const &postmul,
40 bool /*set*/);
41
42 void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode,
43 guint32 color);
44 virtual double to_time(int index, double A);
45 virtual double to_len(int index, double A);
46 virtual double rad_to_len(int index, double rad);
47 virtual double len_to_rad(int index, double len);
48 virtual double len_to_time(int index, double len);
49 virtual double time_to_len(int index, double time);
50 virtual std::pair<std::size_t, std::size_t> get_positions(int index, Geom::PathVector subpaths);
51 virtual int last_index(int index, Geom::PathVector subpaths);
52 std::vector<double> get_times(int index, Geom::PathVector subpaths, bool last);
53 virtual void set_helper_size(int hs);
54 virtual void set_use_distance(bool use_knot_distance);
55 virtual void set_chamfer_steps(int value_chamfer_steps);
56 virtual void addCanvasIndicators(SPLPEItem const *lpeitem,
57 std::vector<Geom::PathVector> &hp_vec);
58 virtual void param_update_default(const gchar * default_value){};
59 virtual bool providesKnotHolderEntities() const {
60 return true;
61 }
62 virtual void updateCanvasIndicators();
63 virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
64
65 void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in,
66 Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_normal_in);
67 Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2() const {
68 return last_pwd2;
69 }
70 Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2_normal() const {
71 return last_pwd2_normal;
72 }
73
74 void recalculate_controlpoints_for_new_pwd2(
75 Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in);
76 void recalculate_knots(
77 Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in);
78 friend class FilletChamferPointArrayParamKnotHolderEntity;
79
80private:
81 FilletChamferPointArrayParam(const FilletChamferPointArrayParam &);
82 FilletChamferPointArrayParam &operator=(const FilletChamferPointArrayParam &);
83
84 SPKnotShapeType knot_shape;
85 SPKnotModeType knot_mode;
86 guint32 knot_color;
87 int helper_size;
88 int chamfer_steps;
89 bool use_distance;
90 Geom::PathVector hp;
91
92 Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2;
93 Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal;
94};
95
96class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity {
97public:
98 FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam *p,
99 unsigned int index);
100 virtual ~FilletChamferPointArrayParamKnotHolderEntity() {}
101
102 virtual void knot_set(Geom::Point const &p, Geom::Point const &origin,
103 guint state);
104 virtual Geom::Point knot_get() const;
105 virtual void knot_click(guint state);
106 virtual void knot_set_offset(Geom::Point offset);
107
108 /*Checks whether the index falls within the size of the parameter's vector*/
109 bool valid_index(unsigned int index) const {
110 return (_pparam->_vector.size() > index);
111 }
112 ;
113
114private:
115 FilletChamferPointArrayParam *_pparam;
116 unsigned int _index;
117};
118
119} //namespace LivePathEffect
120
121} //namespace Inkscape
122
123#endif
1240
=== added file 'src/live_effects/parameter/satellitesarray.cpp'
--- src/live_effects/parameter/satellitesarray.cpp 1970-01-01 00:00:00 +0000
+++ src/live_effects/parameter/satellitesarray.cpp 2017-05-06 17:46:29 +0000
@@ -0,0 +1,583 @@
1/*
2 * Author(s):
3 * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
4 *
5 * Copyright (C) 2014 Author(s)
6 * Released under GNU GPL, read the file 'COPYING' for more information
7 */
8
9#include "knotholder.h"
10#include "ui/dialog/lpe-fillet-chamfer-properties.h"
11#include "live_effects/parameter/satellitesarray.h"
12#include "live_effects/effect.h"
13#include "sp-lpe-item.h"
14#include "inkscape.h"
15#include <preferences.h>
16// TODO due to internal breakage in glibmm headers,
17// this has to be included last.
18#include <glibmm/i18n.h>
19
20namespace Inkscape {
21
22namespace LivePathEffect {
23
24SatellitesArrayParam::SatellitesArrayParam(const Glib::ustring &label,
25 const Glib::ustring &tip,
26 const Glib::ustring &key,
27 Inkscape::UI::Widget::Registry *wr,
28 Effect *effect)
29 : ArrayParam<std::vector<Satellite> >(label, tip, key, wr, effect, 0), _knoth(NULL)
30{
31 _knot_shape = SP_KNOT_SHAPE_DIAMOND;
32 _knot_mode = SP_KNOT_MODE_XOR;
33 _knot_color = 0xAAFF8800;
34 _helper_size = 0;
35 _use_distance = false;
36 _global_knot_hide = false;
37 _current_zoom = 0;
38 _effectType = FILLET_CHAMFER;
39 _last_pathvector_satellites = NULL;
40}
41
42
43void SatellitesArrayParam::set_oncanvas_looks(SPKnotShapeType shape,
44 SPKnotModeType mode,
45 guint32 color)
46{
47 _knot_shape = shape;
48 _knot_mode = mode;
49 _knot_color = color;
50}
51
52void SatellitesArrayParam::setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write)
53{
54 _last_pathvector_satellites = pathVectorSatellites;
55 if (write) {
56 param_set_and_write_new_value(_last_pathvector_satellites->getSatellites());
57 } else {
58 param_setValue(_last_pathvector_satellites->getSatellites());
59 }
60}
61
62void SatellitesArrayParam::setUseDistance(bool use_knot_distance)
63{
64 _use_distance = use_knot_distance;
65}
66
67void SatellitesArrayParam::setCurrentZoom(double current_zoom)
68{
69 _current_zoom = current_zoom;
70}
71
72void SatellitesArrayParam::setGlobalKnotHide(bool global_knot_hide)
73{
74 _global_knot_hide = global_knot_hide;
75}
76void SatellitesArrayParam::setEffectType(EffectType et)
77{
78 _effectType = et;
79}
80
81void SatellitesArrayParam::setHelperSize(int hs)
82{
83 _helper_size = hs;
84 updateCanvasIndicators();
85}
86
87void SatellitesArrayParam::updateCanvasIndicators(bool mirror)
88{
89 if (!_last_pathvector_satellites) {
90 return;
91 }
92
93 if (!_hp.empty()) {
94 _hp.clear();
95 }
96 Geom::PathVector pathv = _last_pathvector_satellites->getPathVector();
97 if (pathv.empty()) {
98 return;
99 }
100 if (mirror == true) {
101 _hp.clear();
102 }
103 if (_effectType == FILLET_CHAMFER) {
104 for (size_t i = 0; i < _vector.size(); ++i) {
105 for (size_t j = 0; j < _vector[i].size(); ++j) {
106 if (_vector[i][j].hidden || //Ignore if hidden
107 (!_vector[i][j].has_mirror && mirror == true) || //Ignore if not have mirror and we are in mirror loop
108 _vector[i][j].amount == 0 || //no helper in 0 value
109 pathv[i].size() == j || //ignore last satellite in open paths with fillet chamfer effect
110 (!pathv[i].closed() && j == 0)) //ignore first satellites on open paths
111 {
112 continue;
113 }
114 Geom::Curve *curve_in = pathv[i][j].duplicate();
115 double pos = 0;
116 bool overflow = false;
117 double size_out = _vector[i][j].arcDistance(*curve_in);
118 double lenght_out = curve_in->length();
119 gint previous_index = j - 1; //Always are previous index because we skip first satellite on open paths
120 if (j == 0 && pathv[i].closed()) {
121 previous_index = pathv[i].size() - 1;
122 }
123 if ( previous_index < 0 ) {
124 return;
125 }
126 double lenght_in = pathv.curveAt(previous_index).length();
127 if (mirror) {
128 curve_in = const_cast<Geom::Curve *>(&pathv.curveAt(previous_index));
129 pos = _vector[i][j].time(size_out, true, *curve_in);
130 if (lenght_out < size_out) {
131 overflow = true;
132 }
133 } else {
134 pos = _vector[i][j].time(*curve_in);
135 if (lenght_in < size_out) {
136 overflow = true;
137 }
138 }
139 if (pos <= 0 || pos >= 1) {
140 continue;
141 }
142 Geom::Point point_a = curve_in->pointAt(pos);
143 Geom::Point deriv_a = unit_vector(derivative(curve_in->toSBasis()).pointAt(pos));
144 Geom::Rotate rot(Geom::Rotate::from_degrees(-90));
145 deriv_a = deriv_a * rot;
146 Geom::Point point_c = point_a - deriv_a * _helper_size;
147 Geom::Point point_d = point_a + deriv_a * _helper_size;
148 Geom::Ray ray_1(point_c, point_d);
149 char const *svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5";
150 Geom::PathVector pathv = sp_svg_read_pathv(svgd);
151 Geom::Affine aff = Geom::Affine();
152 aff *= Geom::Scale(_helper_size);
153 if (mirror) {
154 aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90));
155 } else {
156 aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270));
157 }
158 aff *= Geom::Translate(curve_in->pointAt(pos));
159 pathv *= aff;
160 _hp.push_back(pathv[0]);
161 _hp.push_back(pathv[1]);
162 if (overflow) {
163 double diameter = _helper_size;
164 if (_helper_size == 0) {
165 diameter = 15;
166 char const *svgd;
167 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 "
168 "0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z";
169 Geom::PathVector pathv = sp_svg_read_pathv(svgd);
170 aff = Geom::Affine();
171 aff *= Geom::Scale(diameter);
172 aff *= Geom::Translate(point_a - Geom::Point(diameter * 0.35, diameter * 0.35));
173 pathv *= aff;
174 _hp.push_back(pathv[0]);
175 } else {
176 char const *svgd;
177 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 "
178 "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 "
179 "0 -1.32 z";
180 Geom::PathVector pathv = sp_svg_read_pathv(svgd);
181 aff = Geom::Affine();
182 aff *= Geom::Scale(_helper_size / 2.0);
183 if (mirror) {
184 aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90));
185 } else {
186 aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270));
187 }
188 aff *= Geom::Translate(curve_in->pointAt(pos));
189 pathv *= aff;
190 _hp.push_back(pathv[0]);
191 }
192 }
193 }
194 }
195 }
196 if (!_knot_reset_helper.empty()) {
197 _hp.insert(_hp.end(), _knot_reset_helper.begin(), _knot_reset_helper.end() );
198 }
199 if (mirror) {
200 updateCanvasIndicators(false);
201 }
202}
203void SatellitesArrayParam::updateCanvasIndicators()
204{
205 updateCanvasIndicators(true);
206}
207
208void SatellitesArrayParam::addCanvasIndicators(
209 SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
210{
211 hp_vec.push_back(_hp);
212}
213
214void SatellitesArrayParam::param_transform_multiply(Geom::Affine const &postmul, bool /*set*/)
215{
216 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
217
218 if (prefs->getBool("/options/transform/rectcorners", true)) {
219 for (size_t i = 0; i < _vector.size(); ++i) {
220 for (size_t j = 0; j < _vector[i].size(); ++j) {
221 if (!_vector[i][j].is_time && _vector[i][j].amount > 0) {
222 _vector[i][j].amount = _vector[i][j].amount * ((postmul.expansionX() + postmul.expansionY()) / 2);
223 }
224 }
225 }
226 param_set_and_write_new_value(_vector);
227 }
228}
229
230void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
231 SPItem *item,
232 bool mirror)
233{
234 if (!_last_pathvector_satellites) {
235 return;
236 }
237 Geom::PathVector pathv = _last_pathvector_satellites->getPathVector();
238 size_t index = 0;
239 for (size_t i = 0; i < _vector.size(); ++i) {
240 for (size_t j = 0; j < _vector[i].size(); ++j) {
241 if (!_vector[i][j].has_mirror && mirror) {
242 continue;
243 }
244 SatelliteType type = _vector[i][j].satellite_type;
245 if (mirror && i == 0 && j == 0) {
246 index = index + _last_pathvector_satellites->getTotalSatellites();
247 }
248 using namespace Geom;
249 //If is for filletChamfer effect...
250 if (_effectType == FILLET_CHAMFER) {
251 const gchar *tip;
252 if (type == CHAMFER) {
253 tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
254 "<b>Shift+Click</b> open dialog, "
255 "<b>Ctrl+Alt+Click</b> reset");
256 } else if (type == INVERSE_CHAMFER) {
257 tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
258 "<b>Shift+Click</b> open dialog, "
259 "<b>Ctrl+Alt+Click</b> reset");
260 } else if (type == INVERSE_FILLET) {
261 tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, "
262 "<b>Shift+Click</b> open dialog, "
263 "<b>Ctrl+Alt+Click</b> reset");
264 } else {
265 tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, "
266 "<b>Shift+Click</b> open dialog, "
267 "<b>Ctrl+Alt+Click</b> reset");
268 }
269 FilletChamferKnotHolderEntity *e = new FilletChamferKnotHolderEntity(this, index);
270 e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),_knot_shape, _knot_mode, _knot_color);
271 knotholder->add(e);
272 }
273 index++;
274 }
275 }
276 if (mirror) {
277 addKnotHolderEntities(knotholder, item, false);
278 }
279}
280
281void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
282 SPItem *item)
283{
284 _knoth = knotholder;
285 addKnotHolderEntities(knotholder, item, true);
286}
287
288FilletChamferKnotHolderEntity::FilletChamferKnotHolderEntity(
289 SatellitesArrayParam *p, size_t index)
290 : _pparam(p), _index(index) {}
291
292void FilletChamferKnotHolderEntity::knot_set(Geom::Point const &p,
293 Geom::Point const &/*origin*/,
294 guint state)
295{
296 if (!_pparam->_last_pathvector_satellites) {
297 return;
298 }
299 size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
300 bool is_mirror = false;
301 size_t index = _index;
302 if (_index >= total_satellites) {
303 index = _index - total_satellites;
304 is_mirror = true;
305 }
306 std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
307 size_t path_index = index_data.first;
308 size_t curve_index = index_data.second;
309
310 Geom::Point s = snap_knot_position(p, state);
311 if (!valid_index(path_index, curve_index)) {
312 return;
313 }
314 Satellite satellite = _pparam->_vector[path_index][curve_index];
315 Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
316 if (satellite.hidden ||
317 (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
318 pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
319 {
320 return;
321 }
322 gint previous_index = curve_index - 1;
323 if (curve_index == 0 && pathv[path_index].closed()) {
324 previous_index = pathv[path_index].size() - 1;
325 }
326 if ( previous_index < 0 ) {
327 return;
328 }
329 Geom::Curve const &curve_in = pathv[path_index][previous_index];
330 double mirror_time = Geom::nearest_time(s, curve_in);
331 Geom::Point mirror = curve_in.pointAt(mirror_time);
332 double normal_time = Geom::nearest_time(s, pathv[path_index][curve_index]);
333 Geom::Point normal = pathv[path_index][curve_index].pointAt(normal_time);
334 double distance_mirror = Geom::distance(mirror,s);
335 double distance_normal = Geom::distance(normal,s);
336 if (Geom::are_near(s, pathv[path_index][curve_index].initialPoint(), 1.5 / _pparam->_current_zoom)) {
337 satellite.amount = 0;
338 } else if (distance_mirror < distance_normal) {
339 double time_start = 0;
340 Satellites satellites = _pparam->_last_pathvector_satellites->getSatellites();
341 time_start = satellites[path_index][previous_index].time(curve_in);
342 if (time_start > mirror_time) {
343 mirror_time = time_start;
344 }
345 double size = arcLengthAt(mirror_time, curve_in);
346 double amount = curve_in.length() - size;
347 if (satellite.is_time) {
348 amount = timeAtArcLength(amount, pathv[path_index][curve_index]);
349 }
350 satellite.amount = amount;
351 } else {
352 satellite.setPosition(s, pathv[path_index][curve_index]);
353 }
354 _pparam->_knot_reset_helper.clear();
355 if (satellite.amount == 0) {
356 char const *svgd;
357 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 "
358 "m -1.83,1.71 3.78,3.7 M 5.24,8.78 8.98,5.29 10.24,10.28 Z "
359 "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";
360 _pparam->_knot_reset_helper = sp_svg_read_pathv(svgd);
361 _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());
362 }
363 _pparam->_vector[path_index][curve_index] = satellite;
364 sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
365}
366
367Geom::Point FilletChamferKnotHolderEntity::knot_get() const
368{
369 if (!_pparam->_last_pathvector_satellites || _pparam->_global_knot_hide) {
370 return Geom::Point(Geom::infinity(), Geom::infinity());
371 }
372 Geom::Point tmp_point;
373 size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
374 bool is_mirror = false;
375 size_t index = _index;
376 if (_index >= total_satellites) {
377 index = _index - total_satellites;
378 is_mirror = true;
379 }
380 std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
381 size_t path_index = index_data.first;
382 size_t curve_index = index_data.second;
383 if (!valid_index(path_index, curve_index)) {
384 return Geom::Point(Geom::infinity(), Geom::infinity());
385 }
386 Satellite satellite = _pparam->_vector[path_index][curve_index];
387 Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
388 if (satellite.hidden ||
389 (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
390 pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
391 {
392 return Geom::Point(Geom::infinity(), Geom::infinity());
393 }
394 this->knot->show();
395 if (is_mirror) {
396 gint previous_index = curve_index - 1;
397 if (curve_index == 0 && pathv[path_index].closed()) {
398 previous_index = pathv[path_index].size() - 1;
399 }
400 if ( previous_index < 0 ) {
401 return Geom::Point(Geom::infinity(), Geom::infinity());
402 }
403 Geom::Curve const &curve_in = pathv[path_index][previous_index];
404 double s = satellite.arcDistance(pathv[path_index][curve_index]);
405 double t = satellite.time(s, true, curve_in);
406 if (t > 1) {
407 t = 1;
408 }
409 if (t < 0) {
410 t = 0;
411 }
412 double time_start = 0;
413 time_start = _pparam->_last_pathvector_satellites->getSatellites()[path_index][previous_index].time(curve_in);
414 if (time_start > t) {
415 t = time_start;
416 }
417 tmp_point = (curve_in).pointAt(t);
418 } else {
419 tmp_point = satellite.getPosition(pathv[path_index][curve_index]);
420 }
421 Geom::Point const canvas_point = tmp_point;
422 _pparam->updateCanvasIndicators();
423 return canvas_point;
424}
425
426void FilletChamferKnotHolderEntity::knot_click(guint state)
427{
428 if (!_pparam->_last_pathvector_satellites) {
429 return;
430 }
431 size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
432 bool is_mirror = false;
433 size_t index = _index;
434 if (_index >= total_satellites) {
435 index = _index - total_satellites;
436 is_mirror = true;
437 }
438 std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
439 size_t path_index = index_data.first;
440 size_t curve_index = index_data.second;
441 if (!valid_index(path_index, curve_index)) {
442 return;
443 }
444 Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
445 if ((!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
446 pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
447 {
448 return;
449 }
450 if (state & GDK_CONTROL_MASK) {
451 if (state & GDK_MOD1_MASK) {
452 _pparam->_vector[path_index][curve_index].amount = 0.0;
453 sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
454 } else {
455 using namespace Geom;
456 SatelliteType type = _pparam->_vector[path_index][curve_index].satellite_type;
457 switch (type) {
458 case FILLET:
459 type = INVERSE_FILLET;
460 break;
461 case INVERSE_FILLET:
462 type = CHAMFER;
463 break;
464 case CHAMFER:
465 type = INVERSE_CHAMFER;
466 break;
467 default:
468 type = FILLET;
469 break;
470 }
471 _pparam->_vector[path_index][curve_index].satellite_type = type;
472 sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
473 const gchar *tip;
474 if (type == CHAMFER) {
475 tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
476 "<b>Shift+Click</b> open dialog, "
477 "<b>Ctrl+Alt+Click</b> resets");
478 } else if (type == INVERSE_CHAMFER) {
479 tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
480 "<b>Shift+Click</b> open dialog, "
481 "<b>Ctrl+Alt+Click</b> resets");
482 } else if (type == INVERSE_FILLET) {
483 tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, "
484 "<b>Shift+Click</b> open dialog, "
485 "<b>Ctrl+Alt+Click</b> resets");
486 } else {
487 tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, "
488 "<b>Shift+Click</b> open dialog, "
489 "<b>Ctrl+Alt+Click</b> resets");
490 }
491 this->knot->tip = g_strdup(tip);
492 this->knot->show();
493 }
494 } else if (state & GDK_SHIFT_MASK) {
495 double amount = _pparam->_vector[path_index][curve_index].amount;
496 gint previous_index = curve_index - 1;
497 if (curve_index == 0 && pathv[path_index].closed()) {
498 previous_index = pathv[path_index].size() - 1;
499 }
500 if ( previous_index < 0 ) {
501 return;
502 }
503 if (!_pparam->_use_distance && !_pparam->_vector[path_index][curve_index].is_time) {
504 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]);
505 }
506 bool aprox = false;
507 Geom::D2<Geom::SBasis> d2_out = pathv[path_index][curve_index].toSBasis();
508 Geom::D2<Geom::SBasis> d2_in = pathv[path_index][previous_index].toSBasis();
509 aprox = ((d2_in)[0].degreesOfFreedom() != 2 ||
510 d2_out[0].degreesOfFreedom() != 2) &&
511 !_pparam->_use_distance
512 ? true
513 : false;
514 Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog(
515 this->desktop, amount, this, _pparam->_use_distance,
516 aprox, _pparam->_vector[path_index][curve_index]);
517
518 }
519}
520
521void FilletChamferKnotHolderEntity::knot_set_offset(Satellite satellite)
522{
523 if (!_pparam->_last_pathvector_satellites) {
524 return;
525 }
526 size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites();
527 bool is_mirror = false;
528 size_t index = _index;
529 if (_index >= total_satellites) {
530 index = _index - total_satellites;
531 is_mirror = true;
532 }
533 std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index);
534 size_t path_index = index_data.first;
535 size_t curve_index = index_data.second;
536 if (!valid_index(path_index, curve_index)) {
537 return;
538 }
539 Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector();
540 if (satellite.hidden ||
541 (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths
542 pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect
543 {
544 return;
545 }
546 double amount = satellite.amount;
547 double max_amount = amount;
548 if (!_pparam->_use_distance && !satellite.is_time) {
549 gint previous_index = curve_index - 1;
550 if (curve_index == 0 && pathv[path_index].closed()) {
551 previous_index = pathv[path_index].size() - 1;
552 }
553 if ( previous_index < 0 ) {
554 return;
555 }
556 amount = _pparam->_vector[path_index][curve_index].radToLen(amount, pathv[path_index][previous_index], pathv[path_index][curve_index]);
557 if (max_amount > 0 && amount == 0) {
558 amount = _pparam->_vector[path_index][curve_index].amount;
559 }
560 }
561 satellite.amount = amount;
562 _pparam->_vector[path_index][curve_index] = satellite;
563 this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
564 SPLPEItem *splpeitem = dynamic_cast<SPLPEItem *>(item);
565 if (splpeitem) {
566 sp_lpe_item_update_patheffect(splpeitem, false, false);
567 }
568}
569
570} /* namespace LivePathEffect */
571
572} /* namespace Inkscape */
573
574/*
575 Local Variables:
576 mode:c++
577 c-file-style:"stroustrup"
578 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
579 indent-tabs-mode:nil
580 fill-column:99
581 End:
582*/
583// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
0584
=== added file 'src/live_effects/parameter/satellitesarray.h'
--- src/live_effects/parameter/satellitesarray.h 1970-01-01 00:00:00 +0000
+++ src/live_effects/parameter/satellitesarray.h 2017-05-06 17:46:29 +0000
@@ -0,0 +1,114 @@
1#ifndef INKSCAPE_LIVEPATHEFFECT_SATELLITES_ARRAY_H
2#define INKSCAPE_LIVEPATHEFFECT_SATELLITES_ARRAY_H
3
4/*
5 * Inkscape::LivePathEffectParameters
6 * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
7 * Special thanks to Johan Engelen for the base of the effect -powerstroke-
8 * Also to ScislaC for point me to the idea
9 * Also su_v for his construvtive feedback and time
10 * To Nathan Hurst for his review and help on refactor
11 * and finaly to Liam P. White for his big help on coding, that save me a lot of
12 * hours
13 *
14 *
15 * This parameter act as bridge from pathVectorSatellites class to serialize it as a LPE
16 * parameter
17 *
18 * Released under GNU GPL, read the file 'COPYING' for more information
19 */
20
21#include "live_effects/parameter/array.h"
22#include "live_effects/effect-enum.h"
23#include "helper/geom-pathvectorsatellites.h"
24#include "knot-holder-entity.h"
25#include <glib.h>
26
27namespace Inkscape {
28
29namespace LivePathEffect {
30
31class FilletChamferKnotHolderEntity;
32
33class SatellitesArrayParam : public ArrayParam<std::vector<Satellite> > {
34public:
35 SatellitesArrayParam(const Glib::ustring &label, const Glib::ustring &tip,
36 const Glib::ustring &key,
37 Inkscape::UI::Widget::Registry *wr, Effect *effect);
38
39 virtual Gtk::Widget *param_newWidget()
40 {
41 return NULL;
42 }
43 virtual void setHelperSize(int hs);
44 virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
45 virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item, bool mirror);
46 virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
47 virtual void updateCanvasIndicators();
48 virtual void updateCanvasIndicators(bool mirror);
49 virtual bool providesKnotHolderEntities() const
50 {
51 return true;
52 }
53 void param_transform_multiply(Geom::Affine const &postmul, bool /*set*/);
54 void setUseDistance(bool use_knot_distance);
55 void setCurrentZoom(double current_zoom);
56 void setGlobalKnotHide(bool global_knot_hide);
57 void setEffectType(EffectType et);
58 void setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write = true);
59 void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
60
61 friend class FilletChamferKnotHolderEntity;
62 friend class LPEFilletChamfer;
63
64protected:
65 KnotHolder *_knoth;
66
67private:
68 SatellitesArrayParam(const SatellitesArrayParam &);
69 SatellitesArrayParam &operator=(const SatellitesArrayParam &);
70
71 SPKnotShapeType _knot_shape;
72 SPKnotModeType _knot_mode;
73 guint32 _knot_color;
74 Geom::PathVector _hp;
75 Geom::PathVector _knot_reset_helper;
76 int _helper_size;
77 bool _use_distance;
78 bool _global_knot_hide;
79 double _current_zoom;
80 EffectType _effectType;
81 PathVectorSatellites *_last_pathvector_satellites;
82
83};
84
85class FilletChamferKnotHolderEntity : public KnotHolderEntity {
86public:
87 FilletChamferKnotHolderEntity(SatellitesArrayParam *p, size_t index);
88 virtual ~FilletChamferKnotHolderEntity()
89 {
90 _pparam->_knoth = NULL;
91 }
92
93 virtual void knot_set(Geom::Point const &p, Geom::Point const &origin,
94 guint state);
95 virtual Geom::Point knot_get() const;
96 virtual void knot_click(guint state);
97 void knot_set_offset(Satellite);
98 /** Checks whether the index falls within the size of the parameter's vector
99 */
100 bool valid_index(size_t index,size_t subindex) const
101 {
102 return (_pparam->_vector.size() > index && _pparam->_vector[index].size() > subindex);
103 };
104
105private:
106 SatellitesArrayParam *_pparam;
107 size_t _index;
108};
109
110} //namespace LivePathEffect
111
112} //namespace Inkscape
113
114#endif
0115
=== modified file 'src/ui/dialog/lpe-fillet-chamfer-properties.cpp'
--- src/ui/dialog/lpe-fillet-chamfer-properties.cpp 2017-03-12 13:45:15 +0000
+++ src/ui/dialog/lpe-fillet-chamfer-properties.cpp 2017-05-06 17:46:29 +0000
@@ -43,7 +43,6 @@
43 //todo: get tha max aloable infinity freeze the widget43 //todo: get tha max aloable infinity freeze the widget
44 _fillet_chamfer_position_numeric.set_range(0., SCALARPARAM_G_MAXDOUBLE);44 _fillet_chamfer_position_numeric.set_range(0., SCALARPARAM_G_MAXDOUBLE);
45 _fillet_chamfer_position_numeric.set_hexpand();45 _fillet_chamfer_position_numeric.set_hexpand();
46
47 _fillet_chamfer_position_label.set_label(_("Radius (pixels):"));46 _fillet_chamfer_position_label.set_label(_("Radius (pixels):"));
48 _fillet_chamfer_position_label.set_alignment(1.0, 0.5);47 _fillet_chamfer_position_label.set_alignment(1.0, 0.5);
4948
@@ -54,7 +53,6 @@
54 //todo: get tha max aloable infinity freeze the widget53 //todo: get tha max aloable infinity freeze the widget
55 _fillet_chamfer_chamfer_subdivisions.set_range(0, SCALARPARAM_G_MAXDOUBLE);54 _fillet_chamfer_chamfer_subdivisions.set_range(0, SCALARPARAM_G_MAXDOUBLE);
56 _fillet_chamfer_chamfer_subdivisions.set_hexpand();55 _fillet_chamfer_chamfer_subdivisions.set_hexpand();
57
58 _fillet_chamfer_chamfer_subdivisions_label.set_label(_("Chamfer subdivisions:"));56 _fillet_chamfer_chamfer_subdivisions_label.set_label(_("Chamfer subdivisions:"));
59 _fillet_chamfer_chamfer_subdivisions_label.set_alignment(1.0, 0.5);57 _fillet_chamfer_chamfer_subdivisions_label.set_alignment(1.0, 0.5);
6058
@@ -104,23 +102,26 @@
104FilletChamferPropertiesDialog::~FilletChamferPropertiesDialog()102FilletChamferPropertiesDialog::~FilletChamferPropertiesDialog()
105{103{
106104
107 _set_desktop(NULL);105 _setDesktop(NULL);
108}106}
109107
110void FilletChamferPropertiesDialog::showDialog(108void FilletChamferPropertiesDialog::showDialog(
111 SPDesktop *desktop, Geom::Point knotpoint,109 SPDesktop *desktop,
110 double _amount,
112 const Inkscape::LivePathEffect::111 const Inkscape::LivePathEffect::
113 FilletChamferPointArrayParamKnotHolderEntity *pt,112 FilletChamferKnotHolderEntity *pt,
114 bool use_distance,113 bool _use_distance,
115 bool aprox_radius)114 bool _aprox_radius,
115 Satellite _satellite)
116{116{
117 FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog();117 FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog();
118118
119 dialog->_set_desktop(desktop);119 dialog->_setDesktop(desktop);
120 dialog->_set_use_distance(use_distance);120 dialog->_setUseDistance(_use_distance);
121 dialog->_set_aprox(aprox_radius);121 dialog->_setAprox(_aprox_radius);
122 dialog->_set_knot_point(knotpoint);122 dialog->_setAmount(_amount);
123 dialog->_set_pt(pt);123 dialog->_setSatellite(_satellite);
124 dialog->_setPt(pt);
124125
125 dialog->set_title(_("Modify Fillet-Chamfer"));126 dialog->set_title(_("Modify Fillet-Chamfer"));
126 dialog->_apply_button.set_label(_("_Modify"));127 dialog->_apply_button.set_label(_("_Modify"));
@@ -135,34 +136,38 @@
135136
136void FilletChamferPropertiesDialog::_apply()137void FilletChamferPropertiesDialog::_apply()
137{138{
138 double d_width;139
139 double d_pos = _fillet_chamfer_position_numeric.get_value();140 double d_pos = _fillet_chamfer_position_numeric.get_value();
140 if (d_pos) {141 if (d_pos >= 0) {
141 if (_fillet_chamfer_type_fillet.get_active() == true) {142 if (_fillet_chamfer_type_fillet.get_active() == true) {
142 d_width = 1;143 _satellite.satellite_type = FILLET;
143 } else if (_fillet_chamfer_type_inverse_fillet.get_active() == true) {144 } else if (_fillet_chamfer_type_inverse_fillet.get_active() == true) {
144 d_width = 2;145 _satellite.satellite_type = INVERSE_FILLET;
145 } else if (_fillet_chamfer_type_inverse_chamfer.get_active() == true) {146 } else if (_fillet_chamfer_type_inverse_chamfer.get_active() == true) {
146 d_width = _fillet_chamfer_chamfer_subdivisions.get_value() + 4000;147 _satellite.satellite_type = INVERSE_CHAMFER;
147 } else {148 } else {
148 d_width = _fillet_chamfer_chamfer_subdivisions.get_value() + 3000;149 _satellite.satellite_type = CHAMFER;
149 }150 }
150 if (_flexible) {151 if (_flexible) {
151 if (d_pos > 99.99999 || d_pos < 0) {152 if (d_pos > 99.99999 || d_pos < 0) {
152 d_pos = 0;153 d_pos = 0;
153 }154 }
154 d_pos = _index + (d_pos / 100);155 d_pos = d_pos / 100;
155 } else {156 }
156 d_pos = d_pos * -1;157 _satellite.amount = d_pos;
157 }158 size_t steps = (size_t)_fillet_chamfer_chamfer_subdivisions.get_value();
158 _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width));159 if (steps < 1) {
160 steps = 1;
161 }
162 _satellite.steps = steps;
163 _knotpoint->knot_set_offset(_satellite);
159 }164 }
160 _close();165 _close();
161}166}
162167
163void FilletChamferPropertiesDialog::_close()168void FilletChamferPropertiesDialog::_close()
164{169{
165 _set_desktop(NULL);170 _setDesktop(NULL);
166 destroy_();171 destroy_();
167 Glib::signal_idle().connect(172 Glib::signal_idle().connect(
168 sigc::bind_return(173 sigc::bind_return(
@@ -184,62 +189,68 @@
184 }189 }
185}190}
186191
187void FilletChamferPropertiesDialog::_set_knot_point(Geom::Point knotpoint)192void FilletChamferPropertiesDialog::_setSatellite(Satellite satellite)
188{193{
189 double position;194 double position;
190 std::string distance_or_radius = std::string(_("Radius"));195 std::string distance_or_radius = std::string(_("Radius"));
191 if(aprox){196 if (_aprox) {
192 distance_or_radius = std::string(_("Radius approximated"));197 distance_or_radius = std::string(_("Radius approximated"));
193 }198 }
194 if(use_distance){199 if (_use_distance) {
195 distance_or_radius = std::string(_("Knot distance"));200 distance_or_radius = std::string(_("Knot distance"));
196 }201 }
197 if (knotpoint.x() > 0) {202 if (satellite.is_time) {
198 double intpart;203 position = _amount * 100;
199 position = modf(knotpoint[Geom::X], &intpart) * 100;
200 _flexible = true;204 _flexible = true;
201 _index = intpart;
202 _fillet_chamfer_position_label.set_label(_("Position (%):"));205 _fillet_chamfer_position_label.set_label(_("Position (%):"));
203 } else {206 } else {
204 _flexible = false;207 _flexible = false;
205 std::string posConcat = Glib::ustring::compose (_("%1:"), distance_or_radius);208 std::string posConcat = Glib::ustring::compose (_("%1:"), distance_or_radius);
206 _fillet_chamfer_position_label.set_label(_(posConcat.c_str()));209 _fillet_chamfer_position_label.set_label(_(posConcat.c_str()));
207 position = knotpoint[Geom::X] * -1;210 position = _amount;
208 }211 }
209 _fillet_chamfer_position_numeric.set_value(position);212 _fillet_chamfer_position_numeric.set_value(position);
210 if (knotpoint.y() == 1) {213 _fillet_chamfer_chamfer_subdivisions.set_value(satellite.steps);
214 if (satellite.satellite_type == FILLET) {
211 _fillet_chamfer_type_fillet.set_active(true);215 _fillet_chamfer_type_fillet.set_active(true);
212 } else if (knotpoint.y() == 2) {216 } else if (satellite.satellite_type == INVERSE_FILLET) {
213 _fillet_chamfer_type_inverse_fillet.set_active(true);217 _fillet_chamfer_type_inverse_fillet.set_active(true);
214 } else if (knotpoint.y() >= 3000 && knotpoint.y() < 4000) {218 } else if (satellite.satellite_type == CHAMFER) {
215 _fillet_chamfer_chamfer_subdivisions.set_value(knotpoint.y() - 3000);
216 _fillet_chamfer_type_chamfer.set_active(true);219 _fillet_chamfer_type_chamfer.set_active(true);
217 } else if (knotpoint.y() >= 4000 && knotpoint.y() < 5000) {220 } else if (satellite.satellite_type == INVERSE_CHAMFER) {
218 _fillet_chamfer_chamfer_subdivisions.set_value(knotpoint.y() - 4000);
219 _fillet_chamfer_type_inverse_chamfer.set_active(true);221 _fillet_chamfer_type_inverse_chamfer.set_active(true);
220 }222 }
223 _satellite = satellite;
221}224}
222225
223void FilletChamferPropertiesDialog::_set_pt(226void FilletChamferPropertiesDialog::_setPt(
224 const Inkscape::LivePathEffect::227 const Inkscape::LivePathEffect::
225 FilletChamferPointArrayParamKnotHolderEntity *pt)228 FilletChamferKnotHolderEntity *pt)
226{229{
227 _knotpoint = const_cast<230 _knotpoint = const_cast<
228 Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *>(231 Inkscape::LivePathEffect::FilletChamferKnotHolderEntity *>(
229 pt);232 pt);
230}233}
231234
232void FilletChamferPropertiesDialog::_set_use_distance(bool use_knot_distance)235
233{236void FilletChamferPropertiesDialog::_setAmount(double amount)
234 use_distance = use_knot_distance;237{
235}238 _amount = amount;
236239}
237void FilletChamferPropertiesDialog::_set_aprox(bool aprox_radius)240
238{241
239 aprox = aprox_radius;242
240}243void FilletChamferPropertiesDialog::_setUseDistance(bool use_knot_distance)
241244{
242void FilletChamferPropertiesDialog::_set_desktop(SPDesktop *desktop)245 _use_distance = use_knot_distance;
246}
247
248void FilletChamferPropertiesDialog::_setAprox(bool _aprox_radius)
249{
250 _aprox = _aprox_radius;
251}
252
253void FilletChamferPropertiesDialog::_setDesktop(SPDesktop *desktop)
243{254{
244 if (desktop) {255 if (desktop) {
245 Inkscape::GC::anchor(desktop);256 Inkscape::GC::anchor(desktop);
246257
=== modified file 'src/ui/dialog/lpe-fillet-chamfer-properties.h'
--- src/ui/dialog/lpe-fillet-chamfer-properties.h 2017-03-12 13:37:33 +0000
+++ src/ui/dialog/lpe-fillet-chamfer-properties.h 2017-05-06 17:46:29 +0000
@@ -10,7 +10,7 @@
1010
11#include <2geom/point.h>11#include <2geom/point.h>
12#include <gtkmm.h>12#include <gtkmm.h>
13#include "live_effects/parameter/filletchamferpointarray.h"13#include "live_effects/parameter/satellitesarray.h"
1414
15class SPDesktop;15class SPDesktop;
1616
@@ -23,20 +23,22 @@
23 FilletChamferPropertiesDialog();23 FilletChamferPropertiesDialog();
24 virtual ~FilletChamferPropertiesDialog();24 virtual ~FilletChamferPropertiesDialog();
2525
26 Glib::ustring getName() const {26 Glib::ustring getName() const
27 {
27 return "LayerPropertiesDialog";28 return "LayerPropertiesDialog";
28 }29 }
2930
30 static void showDialog(SPDesktop *desktop, Geom::Point knotpoint,31 static void showDialog(SPDesktop *desktop, double _amount,
31 const Inkscape::LivePathEffect::32 const Inkscape::LivePathEffect::
32 FilletChamferPointArrayParamKnotHolderEntity *pt,33 FilletChamferKnotHolderEntity *pt,
33 bool use_distance,34 bool _use_distance,
34 bool aprox_radius);35 bool _aprox_radius,
36 Satellite _satellite);
3537
36protected:38protected:
3739
38 SPDesktop *_desktop;40 SPDesktop *_desktop;
39 Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *41 Inkscape::LivePathEffect::FilletChamferKnotHolderEntity *
40 _knotpoint;42 _knotpoint;
4143
42 Gtk::Label _fillet_chamfer_position_label;44 Gtk::Label _fillet_chamfer_position_label;
@@ -51,36 +53,40 @@
5153
52 Gtk::Grid _layout_table;54 Gtk::Grid _layout_table;
53 bool _position_visible;55 bool _position_visible;
54 double _index;
5556
56 Gtk::Button _close_button;57 Gtk::Button _close_button;
57 Gtk::Button _apply_button;58 Gtk::Button _apply_button;
5859
59 sigc::connection _destroy_connection;60 sigc::connection _destroy_connection;
6061
61 static FilletChamferPropertiesDialog &_instance() {62 static FilletChamferPropertiesDialog &_instance()
63 {
62 static FilletChamferPropertiesDialog instance;64 static FilletChamferPropertiesDialog instance;
63 return instance;65 return instance;
64 }66 }
6567
66 void _set_desktop(SPDesktop *desktop);68 void _setDesktop(SPDesktop *desktop);
67 void _set_pt(const Inkscape::LivePathEffect::69 void _setPt(const Inkscape::LivePathEffect::
68 FilletChamferPointArrayParamKnotHolderEntity *pt);70 FilletChamferKnotHolderEntity *pt);
69 void _set_use_distance(bool use_knot_distance);71 void _setUseDistance(bool use_knot_distance);
70 void _set_aprox(bool aprox_radius);72 void _setAprox(bool aprox_radius);
73 void _setAmount(double amount);
74 void _setSatellite(Satellite satellite);
75 void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row);
76
77 bool _handleKeyEvent(GdkEventKey *event);
78 void _handleButtonEvent(GdkEventButton *event);
79
71 void _apply();80 void _apply();
72 void _close();81 void _close();
73 bool _flexible;82 bool _flexible;
74 bool use_distance;83 Satellite _satellite;
75 bool aprox;84 bool _use_distance;
76 void _set_knot_point(Geom::Point knotpoint);85 double _amount;
77 void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row);86 bool _aprox;
78
79 bool _handleKeyEvent(GdkEventKey *event);
80 void _handleButtonEvent(GdkEventButton *event);
8187
82 friend class Inkscape::LivePathEffect::88 friend class Inkscape::LivePathEffect::
83 FilletChamferPointArrayParamKnotHolderEntity;89 FilletChamferKnotHolderEntity;
8490
85private:91private:
86 FilletChamferPropertiesDialog(92 FilletChamferPropertiesDialog(
8793
=== modified file 'src/ui/tool/path-manipulator.cpp'
--- src/ui/tool/path-manipulator.cpp 2016-12-06 21:22:02 +0000
+++ src/ui/tool/path-manipulator.cpp 2017-05-06 17:46:29 +0000
@@ -12,7 +12,6 @@
1212
13#include "live_effects/lpe-powerstroke.h"13#include "live_effects/lpe-powerstroke.h"
14#include "live_effects/lpe-bspline.h"14#include "live_effects/lpe-bspline.h"
15#include "live_effects/lpe-fillet-chamfer.h"
16#include <2geom/bezier-utils.h>15#include <2geom/bezier-utils.h>
17#include <2geom/path-sink.h>16#include <2geom/path-sink.h>
18#include "ui/tool/path-manipulator.h"17#include "ui/tool/path-manipulator.h"
@@ -1364,13 +1363,6 @@
1364 lpe_pwr->adjustForNewPath(pathv);1363 lpe_pwr->adjustForNewPath(pathv);
1365 }1364 }
1366 }1365 }
1367 this_effect = _path->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER);
1368 if(this_effect){
1369 LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(this_effect->getLPEObj()->get_lpe());
1370 if (lpe_fll) {
1371 lpe_fll->adjustForNewPath(pathv);
1372 }
1373 }
1374 }1366 }
1375 }1367 }
13761368