diff options
| author | Jabiertxof <jtx@jtx> | 2017-05-06 18:07:14 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx> | 2017-05-06 18:07:14 +0000 |
| commit | cb39bc5cd6fbecf0f045d58f30dd4288c590a46a (patch) | |
| tree | 9fbb940c15170a68e284dd8ca4a09f84eb8c311d /src | |
| parent | LPE widget refactor. Improvement to not update on same value (diff) | |
| parent | Pre merge fixing (diff) | |
| download | inkscape-cb39bc5cd6fbecf0f045d58f30dd4288c590a46a.tar.gz inkscape-cb39bc5cd6fbecf0f045d58f30dd4288c590a46a.zip | |
Merge pathVectorSatellites
(bzr r15666)
Diffstat (limited to 'src')
| -rw-r--r-- | src/helper/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/helper/geom-pathvectorsatellites.cpp | 244 | ||||
| -rw-r--r-- | src/helper/geom-pathvectorsatellites.h | 58 | ||||
| -rw-r--r-- | src/helper/geom-satellite.cpp | 245 | ||||
| -rw-r--r-- | src/helper/geom-satellite.h | 110 | ||||
| -rw-r--r-- | src/knotholder.h | 5 | ||||
| -rw-r--r-- | src/live_effects/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/live_effects/effect.cpp | 2 | ||||
| -rw-r--r-- | src/live_effects/lpe-fillet-chamfer.cpp | 915 | ||||
| -rw-r--r-- | src/live_effects/lpe-fillet-chamfer.h | 64 | ||||
| -rw-r--r-- | src/live_effects/parameter/array.cpp | 44 | ||||
| -rw-r--r-- | src/live_effects/parameter/array.h | 39 | ||||
| -rw-r--r-- | src/live_effects/parameter/filletchamferpointarray.cpp | 873 | ||||
| -rw-r--r-- | src/live_effects/parameter/filletchamferpointarray.h | 123 | ||||
| -rw-r--r-- | src/live_effects/parameter/satellitesarray.cpp | 583 | ||||
| -rw-r--r-- | src/live_effects/parameter/satellitesarray.h | 114 | ||||
| -rw-r--r-- | src/ui/dialog/lpe-fillet-chamfer-properties.cpp | 101 | ||||
| -rw-r--r-- | src/ui/dialog/lpe-fillet-chamfer-properties.h | 48 | ||||
| -rw-r--r-- | src/ui/tool/path-manipulator.cpp | 8 |
19 files changed, 1973 insertions, 1611 deletions
diff --git a/src/helper/CMakeLists.txt b/src/helper/CMakeLists.txt index ff4760c24..92709e4e9 100644 --- a/src/helper/CMakeLists.txt +++ b/src/helper/CMakeLists.txt @@ -14,6 +14,8 @@ set(helper_SRC geom.cpp geom-nodetype.cpp geom-pathstroke.cpp + geom-pathvectorsatellites.cpp + geom-satellite.cpp gnome-utils.cpp pixbuf-ops.cpp png-write.cpp @@ -32,6 +34,8 @@ set(helper_SRC geom-curves.h geom-nodetype.h geom-pathstroke.h + geom-pathvectorsatellites.h + geom-satellite.h geom.h gnome-utils.h mathfns.h diff --git a/src/helper/geom-pathvectorsatellites.cpp b/src/helper/geom-pathvectorsatellites.cpp new file mode 100644 index 000000000..e995c0a9b --- /dev/null +++ b/src/helper/geom-pathvectorsatellites.cpp @@ -0,0 +1,244 @@ +/** + * \file + * \brief PathVectorSatellites a class to manage satellites -per node extra data- in a pathvector + */ /* + * Authors: + * Jabiertxof + * Nathan Hurst + * Johan Engelen + * Josh Andler + * suv + * Mc- + * Liam P. White + * Krzysztof Kosiński + * This code is in public domain + */ + +#include <helper/geom-pathvectorsatellites.h> +#include "util/units.h" + +Geom::PathVector PathVectorSatellites::getPathVector() const +{ + return _pathvector; +} + +void PathVectorSatellites::setPathVector(Geom::PathVector pathv) +{ + _pathvector = pathv; +} + +Satellites PathVectorSatellites::getSatellites() +{ + return _satellites; +} + +void PathVectorSatellites::setSatellites(Satellites satellites) +{ + _satellites = satellites; +} + +size_t PathVectorSatellites::getTotalSatellites() +{ + size_t counter = 0; + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + counter++; + } + } + return counter; +} + +std::pair<size_t, size_t> PathVectorSatellites::getIndexData(size_t index) +{ + size_t counter = 0; + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if (index == counter) { + return std::make_pair(i,j); + } + counter++; + } + } + return std::make_pair(0,0); +} + +void PathVectorSatellites::setSelected(std::vector<size_t> selected) +{ + size_t counter = 0; + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if (find (selected.begin(), selected.end(), counter) != selected.end()) { + _satellites[i][j].setSelected(true); + } else { + _satellites[i][j].setSelected(false); + } + counter++; + } + } +} + +void PathVectorSatellites::updateSteps(size_t steps, bool apply_no_radius, bool apply_with_radius, bool only_selected) +{ + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if ((!apply_no_radius && _satellites[i][j].amount == 0) || + (!apply_with_radius && _satellites[i][j].amount != 0)) + { + continue; + } + if (only_selected) { + if (_satellites[i][j].selected) { + _satellites[i][j].steps = steps; + } + } else { + _satellites[i][j].steps = steps; + } + } + } +} + +void PathVectorSatellites::updateAmount(double radius, bool apply_no_radius, bool apply_with_radius, bool only_selected, + bool use_knot_distance, bool flexible) +{ + double power = 0; + if (!flexible) { + power = radius; + } else { + power = radius / 100; + } + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + boost::optional<size_t> previous_index = boost::none; + if (j == 0 && _pathvector[i].closed()) { + previous_index = _pathvector[i].size() - 1; + } else if (!_pathvector[i].closed() || j != 0) { + previous_index = j - 1; + } + if (!_pathvector[i].closed() && j == 0) { + _satellites[i][j].amount = 0; + continue; + } + if (_pathvector[i].size() == j) { + continue; + } + if ((!apply_no_radius && _satellites[i][j].amount == 0) || + (!apply_with_radius && _satellites[i][j].amount != 0)) + { + continue; + } + + Geom::Point satellite_point = _pathvector[i].pointAt(j); + if (_satellites[i][j].selected || !only_selected) { + if (!use_knot_distance && !flexible) { + if (previous_index) { + _satellites[i][j].amount = _satellites[i][j].radToLen(power, _pathvector[i][*previous_index], _pathvector[i][j]); + if (power && !_satellites[i][j].amount) { + g_warning("Seems a too high radius value"); + } + } else { + _satellites[i][j].amount = 0.0; + } + } else { + _satellites[i][j].amount = power; + } + } + } + } +} + +void PathVectorSatellites::convertUnit(Glib::ustring in, Glib::ustring to, bool apply_no_radius, bool apply_with_radius) +{ + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if (!_pathvector[i].closed() && j == 0) { + _satellites[i][j].amount = 0; + continue; + } + if (_pathvector[i].size() == j) { + continue; + } + if ((!apply_no_radius && _satellites[i][j].amount == 0) || + (!apply_with_radius && _satellites[i][j].amount != 0)) + { + continue; + } + _satellites[i][j].amount = Inkscape::Util::Quantity::convert(_satellites[i][j].amount, in.c_str(), to.c_str()); + } + } +} + +void PathVectorSatellites::updateSatelliteType(SatelliteType satellitetype, bool apply_no_radius, bool apply_with_radius, + bool only_selected) +{ + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if ((!apply_no_radius && _satellites[i][j].amount == 0) || + (!apply_with_radius && _satellites[i][j].amount != 0)) + { + continue; + } + if (_pathvector[i].size() == j) { + if (!only_selected) { + _satellites[i][j].satellite_type = satellitetype; + } + continue; + } + if (only_selected) { + Geom::Point satellite_point = _pathvector[i].pointAt(j); + if (_satellites[i][j].selected) { + _satellites[i][j].satellite_type = satellitetype; + } + } else { + _satellites[i][j].satellite_type = satellitetype; + } + } + } +} + +void PathVectorSatellites::recalculateForNewPathVector(Geom::PathVector const pathv, Satellite const S) +{ + Satellites satellites; + bool found = false; + //TODO evaluate fix on nodes at same position + size_t number_nodes = pathv.nodes().size(); + size_t previous_number_nodes = _pathvector.nodes().size(); + for (size_t i = 0; i < pathv.size(); i++) { + std::vector<Satellite> path_satellites; + for (size_t j = 0; j < pathv[i].size_closed(); j++) { + found = false; + for (size_t k = 0; k < _pathvector.size(); k++) { + for (size_t l = 0; l < _pathvector[k].size_closed(); l++) { + if (Geom::are_near(_pathvector[k][l].initialPoint(), pathv[i][j].initialPoint())) + { + path_satellites.push_back(_satellites[k][l]); + found = true; + break; + } + } + if (found) { + break; + } + } + + if (!found && previous_number_nodes < number_nodes) { + path_satellites.push_back(S); + } + } + satellites.push_back(path_satellites); + } + setPathVector(pathv); + setSatellites(satellites); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: +// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 +// : diff --git a/src/helper/geom-pathvectorsatellites.h b/src/helper/geom-pathvectorsatellites.h new file mode 100644 index 000000000..d86e6cb25 --- /dev/null +++ b/src/helper/geom-pathvectorsatellites.h @@ -0,0 +1,58 @@ +/** + * \file + * \brief PathVectorSatellites a class to manage satellites -per node extra data- in a pathvector + */ /* + * Authors: + * Jabiertxof + * Nathan Hurst + * Johan Engelen + * Josh Andler + * suv + * Mc- + * Liam P. White + * Krzysztof Kosiński + * This code is in public domain + */ + +#ifndef SEEN_PATHVECTORSATELLITES_H +#define SEEN_PATHVECTORSATELLITES_H + +#include <helper/geom-satellite.h> +#include <2geom/path.h> +#include <2geom/pathvector.h> + +typedef std::vector<std::vector<Satellite> > Satellites; +///@brief PathVectorSatellites a class to manage satellites in a pathvector +class PathVectorSatellites { +public: + Geom::PathVector getPathVector() const; + void setPathVector(Geom::PathVector pathv); + Satellites getSatellites(); + void setSatellites(Satellites satellites); + size_t getTotalSatellites(); + void setSelected(std::vector<size_t> selected); + void updateSteps(size_t steps, bool apply_no_radius, bool apply_with_radius, bool only_selected); + void updateAmount(double radius, bool apply_no_radius, bool apply_with_radius, bool only_selected, + bool use_knot_distance, bool flexible); + void convertUnit(Glib::ustring in, Glib::ustring to, bool apply_no_radius, bool apply_with_radius); + void updateSatelliteType(SatelliteType satellitetype, bool apply_no_radius, bool apply_with_radius, bool only_selected); + std::pair<size_t, size_t> getIndexData(size_t index); + void recalculateForNewPathVector(Geom::PathVector const pathv, Satellite const S); +private: + Geom::PathVector _pathvector; + Satellites _satellites; +}; + +#endif //SEEN_PATHVECTORSATELLITES_H +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: +// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 +// : diff --git a/src/helper/geom-satellite.cpp b/src/helper/geom-satellite.cpp new file mode 100644 index 000000000..8a92273d0 --- /dev/null +++ b/src/helper/geom-satellite.cpp @@ -0,0 +1,245 @@ +/** + * \file + * \brief Satellite a per node holder of data. + */ /* + * Authors: + * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es> + * + * This code is in public domain + */ + +#include <helper/geom-satellite.h> +#include <2geom/curve.h> +#include <2geom/nearest-time.h> +#include <2geom/path-intersection.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/ray.h> +#include <boost/optional.hpp> +//log cache +#ifdef _WIN32 +#include <Windows.h> +#else +#include <sys/time.h> +#include <ctime> +#endif + +///@brief Satellite a per node holder of data. +Satellite::Satellite() {} + + +Satellite::Satellite(SatelliteType satellite_type) + : satellite_type(satellite_type), + is_time(false), + selected(false), + has_mirror(false), + hidden(true), + amount(0.0), + angle(0.0), + steps(0) +{} + +Satellite::~Satellite() {} + +///Calculate the time in curve_in with a size of A +//TODO: find a better place to it +double timeAtArcLength(double const A, Geom::Curve const &curve_in) +{ + if ( A == 0 || curve_in.isDegenerate()) { + return 0; + } + + Geom::D2<Geom::SBasis> d2_in = curve_in.toSBasis(); + double t = 0; + double length_part = curve_in.length(); + if (A >= length_part || curve_in.isLineSegment()) { + if (length_part != 0) { + t = A / length_part; + } + } else if (!curve_in.isLineSegment()) { + std::vector<double> t_roots = roots(Geom::arcLengthSb(d2_in) - A); + if (!t_roots.empty()) { + t = t_roots[0]; + } + } + return t; +} + +///Calculate the size in curve_in with a point at A +//TODO: find a better place to it +double arcLengthAt(double const A, Geom::Curve const &curve_in) +{ + if ( A == 0 || curve_in.isDegenerate()) { + return 0; + } + + double s = 0; + double length_part = curve_in.length(); + if (A > length_part || curve_in.isLineSegment()) { + s = (A * length_part); + } else if (!curve_in.isLineSegment()) { + Geom::Curve *curve = curve_in.portion(0.0, A); + s = curve->length(); + delete curve; + } + return s; +} + +///Convert a arc radius of a fillet/chamfer to his satellite length -point position where fillet/chamfer knot be on original curve +double Satellite::radToLen( + double const A, Geom::Curve const &curve_in, + Geom::Curve const &curve_out) const +{ + double len = 0; + Geom::D2<Geom::SBasis> d2_in = curve_in.toSBasis(); + Geom::D2<Geom::SBasis> d2_out = curve_out.toSBasis(); + Geom::Piecewise<Geom::D2<Geom::SBasis> > offset_curve0 = + Geom::Piecewise<Geom::D2<Geom::SBasis> >(d2_in) + + rot90(unitVector(derivative(d2_in))) * (A); + Geom::Piecewise<Geom::D2<Geom::SBasis> > offset_curve1 = + Geom::Piecewise<Geom::D2<Geom::SBasis> >(d2_out) + + rot90(unitVector(derivative(d2_out))) * (A); + Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0]; + Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0]; + Geom::Crossings cs = Geom::crossings(p0, p1); + if (cs.size() > 0) { + Geom::Point cp = p0(cs[0].ta); + double p0pt = nearest_time(cp, curve_out); + len = arcLengthAt(p0pt, curve_out); + } else { + if (A > 0) { + len = radToLen(A * -1, curve_in, curve_out); + } + } + return len; +} + +///Convert a satelite length -point position where fillet/chamfer knot be on original curve- to a arc radius of fillet/chamfer +double Satellite::lenToRad( + double const A, Geom::Curve const &curve_in, + Geom::Curve const &curve_out, + Satellite const previousSatellite) const +{ + double time_in = (previousSatellite).time(A, true, curve_in); + double time_out = timeAtArcLength(A, curve_out); + Geom::Point start_arc_point = curve_in.pointAt(time_in); + Geom::Point end_arc_point = curve_out.pointAt(time_out); + Geom::Curve *knot_curve1 = curve_in.portion(0, time_in); + Geom::Curve *knot_curve2 = curve_out.portion(time_out, 1); + Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve1); + Geom::Ray ray1(start_arc_point, curve_in.pointAt(1)); + if (cubic1) { + ray1.setPoints((*cubic1)[2], start_arc_point); + } + Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve2); + Geom::Ray ray2(curve_out.pointAt(0), end_arc_point); + if (cubic2) { + ray2.setPoints(end_arc_point, (*cubic2)[1]); + } + bool ccw_toggle = cross(curve_in.pointAt(1) - start_arc_point, + end_arc_point - start_arc_point) < 0; + double distance_arc = + Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point)); + double angle = angle_between(ray1, ray2, ccw_toggle); + double divisor = std::sin(angle / 2.0); + if (divisor > 0) { + return distance_arc / divisor; + } + return 0; +} + +///Get the time position of the satellite in curve_in +double Satellite::time(Geom::Curve const &curve_in, bool inverse) const +{ + double t = amount; + if (!is_time) { + t = time(t, inverse, curve_in); + } else if (inverse) { + t = 1-t; + } + if (t > 1) { + t = 1; + } + return t; +} + +///Get the time from a length A in other curve, a bolean inverse gived to reverse time +double Satellite::time(double A, bool inverse, + Geom::Curve const &curve_in) const +{ + if (A == 0 && inverse) { + return 1; + } + if (A == 0 && !inverse) { + return 0; + } + if (!inverse) { + return timeAtArcLength(A, curve_in); + } + double length_part = curve_in.length(); + A = length_part - A; + return timeAtArcLength(A, curve_in); +} + +///Get the length of the satellite in curve_in +double Satellite::arcDistance(Geom::Curve const &curve_in) const +{ + double s = amount; + if (is_time) { + s = arcLengthAt(s, curve_in); + } + return s; +} + +///Get the point position of the satellite +Geom::Point Satellite::getPosition(Geom::Curve const &curve_in, bool inverse) const +{ + double t = time(curve_in, inverse); + return curve_in.pointAt(t); +} + +///Set the position of the satellite from a gived point P +void Satellite::setPosition(Geom::Point const p, Geom::Curve const &curve_in, bool inverse) +{ + Geom::Curve * curve = const_cast<Geom::Curve *>(&curve_in); + if (inverse) { + curve = curve->reverse(); + } + double A = Geom::nearest_time(p, *curve); + if (!is_time) { + A = arcLengthAt(A, *curve); + } + amount = A; +} + + +///Map a satellite type with gchar +void Satellite::setSatelliteType(gchar const *A) +{ + std::map<std::string, SatelliteType> gchar_map_to_satellite_type = + boost::assign::map_list_of("F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE); + std::map<std::string, SatelliteType>::iterator it = gchar_map_to_satellite_type.find(std::string(A)); + if (it != gchar_map_to_satellite_type.end()) { + satellite_type = it->second; + } +} + +///Map a gchar with satelliteType +gchar const *Satellite::getSatelliteTypeGchar() const +{ + std::map<SatelliteType, gchar const *> satellite_type_to_gchar_map = + boost::assign::map_list_of(FILLET, "F")(INVERSE_FILLET, "IF")(CHAMFER, "C")(INVERSE_CHAMFER, "IC")(INVALID_SATELLITE, "KO"); + return satellite_type_to_gchar_map.at(satellite_type); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: +// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 +// : diff --git a/src/helper/geom-satellite.h b/src/helper/geom-satellite.h new file mode 100644 index 000000000..a4d63d66e --- /dev/null +++ b/src/helper/geom-satellite.h @@ -0,0 +1,110 @@ +/** + * \file + * \brief Satellite a per node holder of data. + */ /* + * Authors: + * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es> + * + * This code is in public domain + */ + +#ifndef SEEN_SATELLITE_H +#define SEEN_SATELLITE_H + +#include <map> +#include <boost/assign.hpp> +#include <2geom/sbasis-geometric.h> +#include "util/enums.h" + + +enum SatelliteType { + FILLET = 0, //Fillet + INVERSE_FILLET, //Inverse Fillet + CHAMFER, //Chamfer + INVERSE_CHAMFER, //Inverse Chamfer + INVALID_SATELLITE // Invalid Satellite +}; +/** + * @brief Satellite a per node holder of data. + */ + +class Satellite { +public: + + Satellite(); + Satellite(SatelliteType satellite_type); + + virtual ~Satellite(); + void setIsTime(bool set_is_time) + { + is_time = set_is_time; + } + void setSelected(bool set_selected) + { + selected = set_selected; + } + void setHasMirror(bool set_has_mirror) + { + has_mirror = set_has_mirror; + } + void setHidden(bool set_hidden) + { + hidden = set_hidden; + } + void setAmount(bool set_amount) + { + amount = set_amount; + } + void setAngle(bool set_angle) + { + angle = set_angle; + } + void setSteps(bool set_steps) + { + steps = set_steps; + } + double lenToRad(double const A, Geom::Curve const &curve_in, + Geom::Curve const &curve_out, + Satellite const previousSatellite) const; + double radToLen(double const A, Geom::Curve const &curve_in, + Geom::Curve const &curve_out) const; + + double time(Geom::Curve const &curve_in, bool inverse = false) const; + double time(double A, bool inverse, Geom::Curve const &curve_in) const; + double arcDistance(Geom::Curve const &curve_in) const; + + void setPosition(Geom::Point const p, Geom::Curve const &curve_in, bool inverse = false); + Geom::Point getPosition(Geom::Curve const &curve_in, bool inverse = false) const; + + void setSatelliteType(gchar const *A); + gchar const *getSatelliteTypeGchar() const; + SatelliteType satellite_type; + //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 + //"is_time" tell is if is a time or lenght value + bool is_time; + bool selected; + bool has_mirror; + bool hidden; + //in "amount" we store the time or distance used in the satellite + double amount; + double angle; + size_t steps; +}; + +double timeAtArcLength(double const A, Geom::Curve const &curve_in); +double arcLengthAt(double const A, Geom::Curve const &curve_in); + +#endif // SEEN_SATELLITE_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: +// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 +// : diff --git a/src/knotholder.h b/src/knotholder.h index f1bacebe5..c8136da3f 100644 --- a/src/knotholder.h +++ b/src/knotholder.h @@ -30,7 +30,8 @@ class Node; } namespace LivePathEffect { class PowerStrokePointArrayParamKnotHolderEntity; -class FilletPointArrayParamKnotHolderEntity; +class SatellitesArrayParam; +class FilletChamferKnotHolderEntity; } } @@ -63,7 +64,7 @@ public: friend class Inkscape::UI::ShapeEditor; // FIXME why? friend class Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity; // why? - friend class Inkscape::LivePathEffect::FilletPointArrayParamKnotHolderEntity; // why? + friend class Inkscape::LivePathEffect::FilletChamferKnotHolderEntity; // why? protected: diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 5ffccc7c0..f67c43db0 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -59,7 +59,6 @@ set(live_effects_SRC parameter/array.cpp parameter/bool.cpp - parameter/filletchamferpointarray.cpp parameter/item-reference.cpp parameter/item.cpp parameter/originalitem.cpp @@ -70,6 +69,7 @@ set(live_effects_SRC parameter/path.cpp parameter/point.cpp parameter/powerstrokepointarray.cpp + parameter/satellitesarray.cpp parameter/random.cpp parameter/text.cpp parameter/fontbutton.cpp @@ -144,7 +144,6 @@ set(live_effects_SRC parameter/array.h parameter/bool.h parameter/enum.h - parameter/filletchamferpointarray.h parameter/item.h parameter/item-reference.h parameter/originalitem.h @@ -155,6 +154,7 @@ set(live_effects_SRC parameter/path.h parameter/point.h parameter/powerstrokepointarray.h + parameter/satellitesarray.h parameter/random.h parameter/text.h parameter/fontbutton.h diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 0984a5681..467a65c7c 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -101,7 +101,6 @@ const Util::EnumData<EffectType> LPETypeData[] = { {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, {TEXT_LABEL, N_("Text label"), "text_label"}, - {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"}, #endif /* 0.46 */ {BEND_PATH, N_("Bend"), "bend_path"}, @@ -142,6 +141,7 @@ const Util::EnumData<EffectType> LPETypeData[] = { {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, /* 9.93 */ {MEASURE_LINE, N_("Measure Line"), "measure_line"}, + {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"}, }; const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 1e2df7dc8..e968a7822 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -4,86 +4,131 @@ * * Copyright (C) 2014 Author(s) * - * Special thanks to Johan Engelen for the base of the effect -powerstroke- - * Also to ScislaC for point me to the idea - * Also su_v for his construvtive feedback and time - * Also to Mc- (IRC nick) for his important contribution to find real time - * values based on - * and finaly to Liam P. White for his big help on coding, that save me a lot of hours * * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "live_effects/lpe-fillet-chamfer.h" - -#include <2geom/sbasis-to-bezier.h> -#include <2geom/elliptical-arc.h> +#include "live_effects/lpe-fillet-chamfer.h" +#include "helper/geom.h" #include "display/curve.h" -#include "helper/geom-nodetype.h" #include "helper/geom-curves.h" -#include "helper/geom.h" +#include "helper/geom-satellite.h" +#include <2geom/elliptical-arc.h> +#include "knotholder.h" +#include <boost/optional.hpp> -// for programmatically updating knots -#include "ui/tools-switch.h" // TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> -using namespace Geom; namespace Inkscape { namespace LivePathEffect { -static const Util::EnumData<FilletMethod> FilletMethodData[FM_END] = { - { FM_AUTO, N_("Auto"), "auto" }, +static const Util::EnumData<Filletmethod> FilletmethodData[] = { + { FM_AUTO, N_("Auto"), "auto" }, { FM_ARC, N_("Force arc"), "arc" }, { FM_BEZIER, N_("Force bezier"), "bezier" } }; -static const Util::EnumDataConverter<FilletMethod> -FMConverter(FilletMethodData, FM_END); - -const double tolerance = 0.001; -const double gapHelper = 0.00001; - -LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : - Effect(lpeobject), - fillet_chamfer_values(_("Fillet point"), _("Fillet point"), "fillet_chamfer_values", &wr, this), - hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, false), - ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), "ignore_radius_0", &wr, this, false), - only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false), - flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false), - use_knot_distance(_("Use knots distance instead radius"), _("Use knots distance instead radius"), "use_knot_distance", &wr, this, false), - method(_("Method:"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO), - radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr, this, 0.), - chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps", &wr, this, 0), - - helper_size(_("Helper size with direction:"), _("Helper size with direction"), "helper_size", &wr, this, 0) +static const Util::EnumDataConverter<Filletmethod> FMConverter(FilletmethodData, FM_END); + +LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + unit(_("Unit"), _("Unit"), "unit", &wr, this, "px"), + satellites_param("Satellites_param", "Satellites_param", + "satellites_param", &wr, this), + method(_("Method:"), _("Methods to calculate the fillet or chamfer"), + "method", FMConverter, &wr, this, FM_AUTO), + radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr, + this, 0.0), + chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps", + &wr, this, 1), + flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), + "flexible", &wr, this, false), + mirror_knots(_("Mirror Knots"), _("Mirror Knots"), "mirror_knots", &wr, + this, true), + only_selected(_("Change only selected nodes"), + _("Change only selected nodes"), "only_selected", &wr, this, + false), + use_knot_distance(_("Use knots distance instead radius"), + _("Use knots distance instead radius"), + "use_knot_distance", &wr, this, false), + hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, + false), + apply_no_radius(_("Apply changes if radius = 0"), _("Apply changes if radius = 0"), "apply_no_radius", &wr, this, true), + apply_with_radius(_("Apply changes if radius > 0"), _("Apply changes if radius > 0"), "apply_with_radius", &wr, this, true), + helper_size(_("Helper path size with direction to node:"), + _("Helper path size with direction to node"), "helper_size", &wr, this, 0), + _pathvector_satellites(NULL), + _degenerate_hide(false) { - registerParameter(&fillet_chamfer_values); + registerParameter(&satellites_param); + registerParameter(&unit); registerParameter(&method); registerParameter(&radius); registerParameter(&chamfer_steps); registerParameter(&helper_size); registerParameter(&flexible); registerParameter(&use_knot_distance); - registerParameter(&ignore_radius_0); + registerParameter(&mirror_knots); + registerParameter(&apply_no_radius); + registerParameter(&apply_with_radius); registerParameter(&only_selected); registerParameter(&hide_knots); - radius.param_set_range(0., infinity()); + radius.param_set_range(0.0, Geom::infinity()); radius.param_set_increments(1, 1); radius.param_set_digits(4); radius.param_overwrite_widget(true); chamfer_steps.param_set_range(1, 999); chamfer_steps.param_set_increments(1, 1); chamfer_steps.param_set_digits(0); - chamfer_steps.param_overwrite_widget(true); - helper_size.param_set_range(0, infinity()); + helper_size.param_set_range(0, 999); helper_size.param_set_increments(5, 5); helper_size.param_set_digits(0); - helper_size.param_overwrite_widget(true); - fillet_chamfer_values.set_chamfer_steps(3); + _provides_knotholder_entities = true; } -LPEFilletChamfer::~LPEFilletChamfer() {} +void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) +{ + SPLPEItem *splpeitem = const_cast<SPLPEItem *>(lpeItem); + SPShape *shape = dynamic_cast<SPShape *>(splpeitem); + if (shape) { + Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(shape->getCurve()->get_pathvector()); + Satellites satellites; + for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) { + if (path_it->empty()) { + continue; + } + std::vector<Satellite> subpath_satellites; + for (Geom::Path::const_iterator curve_it = path_it->begin(); curve_it != path_it->end(); ++curve_it) { + //Maybe we want this satellites... + //if (curve_it->isDegenerate()) { + // continue + //} + Satellite satellite(FILLET); + satellite.setSteps(chamfer_steps); + subpath_satellites.push_back(satellite); + } + //we add the last satellite on open path because _pathvector_satellites is related to nodes, not curves + //so maybe in the future we can need this last satellite in other effects + //dont remove for this effect because _pathvector_satellites class has methods when the path is modiffied + //and we want one method for all uses + if (!path_it->closed()) { + Satellite satellite(FILLET); + satellite.setSteps(chamfer_steps); + subpath_satellites.push_back(satellite); + } + satellites.push_back(subpath_satellites); + } + _pathvector_satellites = new PathVectorSatellites(); + _pathvector_satellites->setPathVector(pathv); + _pathvector_satellites->setSatellites(satellites); + satellites_param.setPathVectorSatellites(_pathvector_satellites); + } else { + g_warning("LPE Fillet/Chamfer can only be applied to shapes (not groups)."); + SPLPEItem *item = const_cast<SPLPEItem *>(lpeItem); + item->removeCurrentPathEffect(false); + } +} Gtk::Widget *LPEFilletChamfer::newWidget() { @@ -94,54 +139,50 @@ Gtk::Widget *LPEFilletChamfer::newWidget() vbox->set_border_width(5); vbox->set_homogeneous(false); vbox->set_spacing(2); - Gtk::HBox *advertaising = Gtk::manage(new Gtk::HBox(true, 0)); - Gtk::Button *advert = Gtk::manage(new Gtk::Button(Glib::ustring(_("IMPORTANT! New version soon...")))); - advertaising->pack_start(*advert, true, true, 2); - vbox->pack_start(*advertaising, true, true, 2); - Gtk::HBox *advertaising2 = Gtk::manage(new Gtk::HBox(true, 0)); - Gtk::Button *advert2 = Gtk::manage(new Gtk::Button(Glib::ustring(_("Not compatible. Convert to path after.")))); - advertaising2->pack_start(*advert2, true, true, 2); - vbox->pack_start(*advertaising2, true, true, 2); std::vector<Parameter *>::iterator it = param_vector.begin(); while (it != param_vector.end()) { if ((*it)->widget_is_visible) { Parameter *param = *it; Gtk::Widget *widg = param->param_newWidget(); if (param->param_key == "radius") { - Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); - widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::updateFillet)); - widg = widgRegistered; + Inkscape::UI::Widget::Scalar *widg_registered = + Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + widg_registered->signal_value_changed().connect( + sigc::mem_fun(*this, &LPEFilletChamfer::updateAmount)); + widg = widg_registered; if (widg) { - Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg); - std::vector<Gtk::Widget *> childList = scalarParameter->get_children(); - Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]); - entryWidg->set_width_chars(6); + Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg); + std::vector<Gtk::Widget *> childList = scalar_parameter->get_children(); + Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]); + entry_widget->set_width_chars(6); } +// } else if (param->param_key == "unit") { +// Inkscape::UI::Widget::RegisteredUnitMenu* widg_registered = +// Gtk::manage(dynamic_cast< Inkscape::UI::Widget::RegisteredUnitMenu *>(widg)); +// widg_registered->setUnit(unit.get_abbreviation()); +// widg_registered->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change unit parameter")); +// widg_registered->getUnitMenu()->signal_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::convertUnit)); +// widg = widg_registered; } else if (param->param_key == "chamfer_steps") { - Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); - widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamferSubdivisions)); - widg = widgRegistered; + Inkscape::UI::Widget::Scalar *widg_registered = + Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + widg_registered->signal_value_changed().connect( + sigc::mem_fun(*this, &LPEFilletChamfer::updateChamferSteps)); + widg = widg_registered; if (widg) { - Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg); - std::vector<Gtk::Widget *> childList = scalarParameter->get_children(); - Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]); - entryWidg->set_width_chars(3); + Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg); + std::vector<Gtk::Widget *> childList = scalar_parameter->get_children(); + Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]); + entry_widget->set_width_chars(3); } - } else if (param->param_key == "flexible") { - Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); - widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleFlexFixed)); } else if (param->param_key == "helper_size") { - Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); - widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots)); - } else if (param->param_key == "hide_knots") { - Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); - widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleHide)); + Inkscape::UI::Widget::Scalar *widg_registered = + Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + widg_registered->signal_value_changed().connect( + sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots)); } else if (param->param_key == "only_selected") { Gtk::manage(widg); - } else if (param->param_key == "ignore_radius_0") { - Gtk::manage(widg); } - Glib::ustring *tip = param->param_getTooltip(); if (widg) { vbox->pack_start(*widg, true, true, 2); @@ -153,504 +194,386 @@ Gtk::Widget *LPEFilletChamfer::newWidget() } } } - ++it; } - Gtk::HBox *filletContainer = Gtk::manage(new Gtk::HBox(true, 0)); - Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet")))); - fillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet)); - filletContainer->pack_start(*fillet, true, true, 2); - Gtk::Button *inverseFillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); - inverseFillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseFillet)); - filletContainer->pack_start(*inverseFillet, true, true, 2); - - Gtk::HBox *chamferContainer = Gtk::manage(new Gtk::HBox(true, 0)); + Gtk::HBox *fillet_container = Gtk::manage(new Gtk::HBox(true, 0)); + Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet")))); + fillet->signal_clicked() + .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),FILLET)); + + fillet_container->pack_start(*fillet, true, true, 2); + Gtk::Button *inverse_fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); + inverse_fillet->signal_clicked() + .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_FILLET)); + fillet_container->pack_start(*inverse_fillet, true, true, 2); + + Gtk::HBox *chamfer_container = Gtk::manage(new Gtk::HBox(true, 0)); Gtk::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer")))); - chamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); + chamfer->signal_clicked() + .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),CHAMFER)); - chamferContainer->pack_start(*chamfer, true, true, 2); - Gtk::Button *inverseChamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer")))); - inverseChamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseChamfer)); - chamferContainer->pack_start(*inverseChamfer, true, true, 2); + chamfer_container->pack_start(*chamfer, true, true, 2); + Gtk::Button *inverse_chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer")))); + inverse_chamfer->signal_clicked() + .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_CHAMFER)); + chamfer_container->pack_start(*inverse_chamfer, true, true, 2); - vbox->pack_start(*filletContainer, true, true, 2); - vbox->pack_start(*chamferContainer, true, true, 2); + vbox->pack_start(*fillet_container, true, true, 2); + vbox->pack_start(*chamfer_container, true, true, 2); return vbox; } -void LPEFilletChamfer::toggleHide() -{ - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - std::vector<Geom::Point> result; - for (std::vector<Point>::const_iterator point_it = filletChamferData.begin(); - point_it != filletChamferData.end(); ++point_it) { - if (hide_knots) { - result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y]) * -1)); - } else { - result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y]))); - } - } - fillet_chamfer_values.param_set_and_write_new_value(result); - refreshKnots(); -} - -void LPEFilletChamfer::toggleFlexFixed() +void LPEFilletChamfer::refreshKnots() { - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - std::vector<Geom::Point> result; - unsigned int i = 0; - for (std::vector<Point>::const_iterator point_it = filletChamferData.begin(); - point_it != filletChamferData.end(); ++point_it) { - if (flexible) { - result.push_back(Point(fillet_chamfer_values.to_time(i, (*point_it)[X]), - (*point_it)[Y])); - } else { - result.push_back(Point(fillet_chamfer_values.to_len(i, (*point_it)[X]), - (*point_it)[Y])); - } - i++; - } - if (flexible) { - radius.param_set_range(0., 100); - radius.param_set_value(0); - } else { - radius.param_set_range(0., infinity()); - radius.param_set_value(0); + if (satellites_param._knoth) { + satellites_param._knoth->update_knots(); } - fillet_chamfer_values.param_set_and_write_new_value(result); } -void LPEFilletChamfer::updateFillet() +void LPEFilletChamfer::updateAmount() { - double power = 0; + setSelected(_pathvector_satellites); + double power = radius; if (!flexible) { - power = radius * -1; - } else { - power = radius; + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Glib::ustring display_unit = nv->display_units->abbr; + power = Inkscape::Util::Quantity::convert(power, unit.get_abbreviation(), display_unit.c_str()); } - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doUpdateFillet(path_from_piecewise(pwd2, tolerance), power); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); -} - -void LPEFilletChamfer::fillet() -{ - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), 1); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to fillet")); + _pathvector_satellites->updateAmount(power, apply_no_radius, apply_with_radius, only_selected, + use_knot_distance, flexible); + satellites_param.setPathVectorSatellites(_pathvector_satellites); } -void LPEFilletChamfer::inverseFillet() -{ - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), 2); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet")); -} - -void LPEFilletChamfer::chamferSubdivisions() -{ - fillet_chamfer_values.set_chamfer_steps(chamfer_steps); - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 5000); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); -} - -void LPEFilletChamfer::chamfer() -{ - fillet_chamfer_values.set_chamfer_steps(chamfer_steps); - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3000); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to chamfer")); -} +//void LPEFilletChamfer::convertUnit() +//{ +// SPDocument * document = SP_ACTIVE_DOCUMENT; +// SPNamedView *nv = sp_document_namedview(document, NULL); +// Glib::ustring display_unit = nv->display_units->abbr; +// _pathvector_satellites->convertUnit(unit.get_abbreviation(), display_unit, apply_no_radius, apply_with_radius); +// satellites_param.setPathVectorSatellites(_pathvector_satellites); +//} -void LPEFilletChamfer::inverseChamfer() +void LPEFilletChamfer::updateChamferSteps() { - fillet_chamfer_values.set_chamfer_steps(chamfer_steps); - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 4000); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet")); + setSelected(_pathvector_satellites); + _pathvector_satellites->updateSteps(chamfer_steps, apply_no_radius, apply_with_radius, only_selected); + satellites_param.setPathVectorSatellites(_pathvector_satellites); } -void LPEFilletChamfer::refreshKnots() +void LPEFilletChamfer::updateSatelliteType(SatelliteType satellitetype) { - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - fillet_chamfer_values.recalculate_knots(pwd2); - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (tools_isactive(desktop, TOOLS_NODES)) { - tools_switch(desktop, TOOLS_SELECT); - tools_switch(desktop, TOOLS_NODES); - } - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Knots and helper paths refreshed")); + setSelected(_pathvector_satellites); + _pathvector_satellites->updateSatelliteType(satellitetype, apply_no_radius, apply_with_radius, only_selected); + satellites_param.setPathVectorSatellites(_pathvector_satellites); } -void LPEFilletChamfer::doUpdateFillet(Geom::PathVector const &original_pathv, double power) -{ - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - std::vector<Geom::Point> result; - Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); - int counter = 0; - for (PathVector::const_iterator path_it = original_pathv_processed.begin(); - path_it != original_pathv_processed.end(); ++path_it) { - if (path_it->empty()) - continue; - - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed() && path_it->back_closed().isDegenerate()) { - const Curve &closingline = path_it->back_closed(); - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - curve_endit = path_it->end_open(); - } - } - double powerend = 0; - while (curve_it1 != curve_endit) { - powerend = power; - if (power < 0 && !use_knot_distance) { - powerend = fillet_chamfer_values.rad_to_len(counter,powerend); - } - if (power > 0) { - powerend = counter + (power / 100); - } - if (ignore_radius_0 && (filletChamferData[counter][X] == 0 || - filletChamferData[counter][X] == counter)) { - powerend = filletChamferData[counter][X]; - } - if (filletChamferData[counter][Y] == 0) { - powerend = filletChamferData[counter][X]; - } - if (only_selected && !isNodePointSelected(curve_it1->initialPoint())) { - powerend = filletChamferData[counter][X]; +void LPEFilletChamfer::setSelected(PathVectorSatellites *_pathvector_satellites){ + Geom::PathVector const pathv = _pathvector_satellites->getPathVector(); + Satellites satellites = _pathvector_satellites->getSatellites(); + for (size_t i = 0; i < satellites.size(); ++i) { + for (size_t j = 0; j < satellites[i].size(); ++j) { + Geom::Curve const &curve_in = pathv[i][j]; + if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){ + satellites[i][j].setSelected(true); + } else { + satellites[i][j].setSelected(false); } - result.push_back(Point(powerend, filletChamferData[counter][Y])); - ++curve_it1; - ++curve_it2; - counter++; } } - fillet_chamfer_values.param_set_and_write_new_value(result); + _pathvector_satellites->setSatellites(satellites); } -void LPEFilletChamfer::doChangeType(Geom::PathVector const &original_pathv, int type) +void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) { - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - std::vector<Geom::Point> result; - Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); - int counter = 0; - for (PathVector::const_iterator path_it = original_pathv_processed.begin(); path_it != original_pathv_processed.end(); ++path_it) { - int pathCounter = 0; - if (path_it->empty()) - continue; - - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed() && path_it->back_closed().isDegenerate()) { - const Curve &closingline = path_it->back_closed(); - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - curve_endit = path_it->end_open(); - } + if (sp_curve) { + //fillet chamfer specific calls + satellites_param.setUseDistance(use_knot_distance); + satellites_param.setCurrentZoom(current_zoom); + //mandatory call + satellites_param.setEffectType(effectType()); + Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(sp_curve->get_pathvector()); + //if are diferent sizes call to recalculate + //TODO: Update the satellite data in paths modified, + Satellites satellites = satellites_param.data(); + if (satellites.empty()) { + doOnApply(lpeItem); + satellites = satellites_param.data(); } - while (curve_it1 != curve_endit) { - bool toggle = true; - if (filletChamferData[counter][Y] == 0 || - (ignore_radius_0 && (filletChamferData[counter][X] == 0 || - filletChamferData[counter][X] == counter)) || - (only_selected && !isNodePointSelected(curve_it1->initialPoint()))) { - toggle = false; + if (_pathvector_satellites) { + size_t number_nodes = pathv.nodes().size(); + size_t previous_number_nodes = _pathvector_satellites->getTotalSatellites(); + if (number_nodes != previous_number_nodes) { + Satellite satellite(FILLET); + satellite.setIsTime(flexible); + satellite.setHasMirror(mirror_knots); + satellite.setHidden(hide_knots); + _pathvector_satellites->recalculateForNewPathVector(pathv, satellite); + satellites = _pathvector_satellites->getSatellites(); } - if (toggle) { - if(type >= 5000){ - if(filletChamferData[counter][Y] >= 3000 && filletChamferData[counter][Y] < 4000){ - type = type - 2000; - } else if (filletChamferData[counter][Y] >= 4000 && filletChamferData[counter][Y] < 5000){ - type = type - 1000; - } - } - result.push_back(Point(filletChamferData[counter][X], type)); - } else { - result.push_back(filletChamferData[counter]); - } - ++curve_it1; - if (curve_it2 != curve_endit) { - ++curve_it2; - } - counter++; - pathCounter++; } - } - fillet_chamfer_values.param_set_and_write_new_value(result); -} - -void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) -{ - if (SP_IS_SHAPE(lpeItem)) { - std::vector<Point> point; - PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeItem)->_curve->get_pathvector()); - Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv); - for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { - if (path_it->empty()) - continue; - - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_closed(); - // the closing line segment is always of type - // Geom::LineSegment. - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - // closingline.isDegenerate() did not work, because it only checks for - // *exact* zero length, which goes wrong for relative coordinates and - // rounding errors... - // the closing line segment has zero-length. So stop before that one! - curve_endit = path_it->end_open(); - } - } - int counter = 0; - while (curve_it1 != curve_endit) { - std::pair<std::size_t, std::size_t> positions = fillet_chamfer_values.get_positions(counter, original_pathv); - Geom::NodeType nodetype; - if (positions.second == 0) { - if (path_it->closed()) { - Piecewise<D2<SBasis> > u; - u.push_cut(0); - u.push(pwd2_in[fillet_chamfer_values.last_index(counter, original_pathv)], 1); - Geom::Curve const * A = path_from_piecewise(u, 0.1)[0][0].duplicate(); - nodetype = get_nodetype(*A, *curve_it1); + if (_degenerate_hide) { + satellites_param.setGlobalKnotHide(true); + } else { + satellites_param.setGlobalKnotHide(false); + } + if (hide_knots) { + satellites_param.setHelperSize(0); + } else { + satellites_param.setHelperSize(helper_size); + } + for (size_t i = 0; i < satellites.size(); ++i) { + for (size_t j = 0; j < satellites[i].size(); ++j) { + Geom::Curve const &curve_in = pathv[i][j]; + if (satellites[i][j].is_time != flexible) { + satellites[i][j].is_time = flexible; + double amount = satellites[i][j].amount; + if (pathv[i].size() == j) { + continue; + } + if (satellites[i][j].is_time) { + double time = timeAtArcLength(amount, curve_in); + satellites[i][j].amount = time; } else { - nodetype = NODE_NONE; + double size = arcLengthAt(amount, curve_in); + satellites[i][j].amount = size; } - } else { - nodetype = get_nodetype((*path_it)[counter - 1], *curve_it1); } - if (nodetype == NODE_CUSP) { - point.push_back(Point(0, 1)); - } else { - point.push_back(Point(0, 0)); + if (satellites[i][j].has_mirror != mirror_knots) { + satellites[i][j].has_mirror = mirror_knots; } - ++curve_it1; - if (curve_it2 != curve_endit) { - ++curve_it2; + satellites[i][j].hidden = hide_knots; + if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){ + satellites[i][j].setSelected(true); } - counter++; } } - fillet_chamfer_values.param_set_and_write_new_value(point); - } else { - g_warning("LPE Fillet can only be applied to shapes (not groups)."); - SPLPEItem * item = const_cast<SPLPEItem*>(lpeItem); - item->removeCurrentPathEffect(false); - } -} - -void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) -{ - if (SP_IS_SHAPE(lpeItem)) { - if(hide_knots){ - fillet_chamfer_values.set_helper_size(0); - } else { - fillet_chamfer_values.set_helper_size(helper_size); - } - fillet_chamfer_values.set_use_distance(use_knot_distance); - SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast<SPPath const *>(lpeItem) - ->get_original_curve() - : SP_SHAPE(lpeItem)->getCurve(); - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - if (!filletChamferData.empty() && getKnotsNumber(c) != (int) - filletChamferData.size()) { - PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); - Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv); - fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in); + if (!_pathvector_satellites) { + _pathvector_satellites = new PathVectorSatellites(); } + _pathvector_satellites->setPathVector(pathv); + _pathvector_satellites->setSatellites(satellites); + satellites_param.setPathVectorSatellites(_pathvector_satellites, false); + refreshKnots(); } else { g_warning("LPE Fillet can only be applied to shapes (not groups)."); } } -int LPEFilletChamfer::getKnotsNumber(SPCurve const *c) +void +LPEFilletChamfer::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) { - int nKnots = c->nodes_in_path(); - PathVector const pv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); - for (Geom::PathVector::const_iterator path_it = pv.begin(); - path_it != pv.end(); ++path_it) { - if (!(*path_it).closed()) { - nKnots--; - } - } - return nKnots; + hp_vec.push_back(_hp); } void -LPEFilletChamfer::adjustForNewPath(Geom::PathVector const &path_in) +LPEFilletChamfer::addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps) { - if (!path_in.empty()) { - fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb()); + setSelected(_pathvector_satellites); + double path_subdivision = 1.0 / steps; + for (size_t i = 1; i < steps; i++) { + Geom::Point chamfer_step = path_chamfer.pointAt(path_subdivision * i); + tmp_path.appendNew<Geom::LineSegment>(chamfer_step); } + tmp_path.appendNew<Geom::LineSegment>(end_arc_point); } Geom::PathVector LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in) { - Geom::PathVector pathvector_out; - Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(pathv_to_linear_and_cubic_beziers(path_in)); - pwd2_in = remove_short_cuts(pwd2_in, .01); - Piecewise<D2<SBasis> > der = derivative(pwd2_in); - Piecewise<D2<SBasis> > n = rot90(unitVector(der)); - fillet_chamfer_values.set_pwd2(pwd2_in, n); - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - unsigned int counter = 0; + const double GAP_HELPER = 0.00001; + Geom::PathVector path_out; + size_t path = 0; const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); - Geom::PathVector path_in_processed = pathv_to_linear_and_cubic_beziers(path_in); - for (PathVector::const_iterator path_it = path_in_processed.begin(); - path_it != path_in_processed.end(); ++path_it) { - if (path_it->empty()) + _degenerate_hide = false; + Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(path_in); + Satellites satellites = _pathvector_satellites->getSatellites(); + for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) { + if (path_it->empty()) { + continue; + } + Geom::Path tmp_path; + if (path_it->size() == 1) { + path++; + tmp_path.start(path_it[0].pointAt(0)); + tmp_path.append(path_it[0]); + path_out.push_back(tmp_path); continue; - Geom::Path path_out; - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_closed(); - // the closing line segment is always of type - // Geom::LineSegment. - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - // closingline.isDegenerate() did not work, because it only checks for - // *exact* zero length, which goes wrong for relative coordinates and - // rounding errors... - // the closing line segment has zero-length. So stop before that one! - curve_endit = path_it->end_open(); - } } - unsigned int counterCurves = 0; - while (curve_it1 != curve_endit) { - Curve *curve_it2Fixed = (*path_it->begin()).duplicate(); - if(!path_it->closed() || curve_it2 != curve_endit){ - curve_it2Fixed = (*curve_it2).duplicate(); + double time0 = 0; + size_t curve = 0; + for (Geom::Path::const_iterator curve_it1 = path_it->begin(); curve_it1 != path_it->end(); ++curve_it1) { + size_t next_index = curve + 1; + if (curve == pathv[path].size() - 1 && pathv[path].closed()) { + next_index = 0; + } + //append last extreme of paths on open paths + if (curve == pathv[path].size() -1 && !pathv[path].closed()) { //the path is open and we are at end of path + if (time0 != 1) { //Previous satellite not at 100% amount + Geom::Curve *last_curve = curve_it1->portion(time0, 1); + last_curve->setInitial(tmp_path.finalPoint()); + tmp_path.append(*last_curve); + } + continue; } - bool last = curve_it2 == curve_endit; - std::vector<double> times = fillet_chamfer_values.get_times(counter, path_in, last); - Curve *knotCurve1 = curve_it1->portion(times[0], times[1]); - if (counterCurves > 0) { - knotCurve1->setInitial(path_out.finalPoint()); + Geom::Curve const &curve_it2 = pathv[path][next_index]; + Satellite satellite = satellites[path][next_index]; + if (Geom::are_near((*curve_it1).initialPoint(), (*curve_it1).finalPoint())) { + _degenerate_hide = true; + g_warning("Knots hidded if consecutive nodes has the same position."); + return path_in; + } + if (!curve) { //curve == 0 + if (!path_it->closed()) { + time0 = 0; + } else { + time0 = satellites[path][0].time(*curve_it1); + } + } + double s = satellite.arcDistance(curve_it2); + double time1 = satellite.time(s, true, (*curve_it1)); + double time2 = satellite.time(curve_it2); + if (time1 <= time0) { + time1 = time0; + } + if (time2 > 1) { + time2 = 1; + } + Geom::Curve *knot_curve_1 = curve_it1->portion(time0, time1); + Geom::Curve *knot_curve_2 = curve_it2.portion(time2, 1); + if (curve > 0) { + knot_curve_1->setInitial(tmp_path.finalPoint()); } else { - path_out.start((*curve_it1).pointAt(times[0])); + tmp_path.start((*curve_it1).pointAt(time0)); + } + + Geom::Point start_arc_point = knot_curve_1->finalPoint(); + Geom::Point end_arc_point = curve_it2.pointAt(time2); + //add a gap helper + if (time2 == 1) { + end_arc_point = curve_it2.pointAt(time2 - GAP_HELPER); } - Curve *knotCurve2 = curve_it2Fixed->portion(times[2], 1); - Point startArcPoint = knotCurve1->finalPoint(); - Point endArcPoint = curve_it2Fixed->pointAt(times[2]); - double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K; - double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K; - Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1); - Ray ray1(startArcPoint, curve_it1->finalPoint()); - if (cubic1) { - ray1.setPoints((*cubic1)[2], startArcPoint); + if (time1 == time0) { + start_arc_point = curve_it1->pointAt(time1 + GAP_HELPER); } - Point handle1 = Point::polar(ray1.angle(),k1) + startArcPoint; - Geom::CubicBezier const *cubic2 = - dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2); - Ray ray2(curve_it1->finalPoint(), endArcPoint); - if (cubic2) { - ray2.setPoints(endArcPoint, (*cubic2)[1]); + + double k1 = distance(start_arc_point, curve_it1->finalPoint()) * K; + double k2 = distance(curve_it2.initialPoint(), end_arc_point) * K; + Geom::CubicBezier const *cubic_1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_1); + Geom::CubicBezier const *cubic_2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_2); + Geom::Ray ray_1(start_arc_point, curve_it1->finalPoint()); + Geom::Ray ray_2(curve_it2.initialPoint(), end_arc_point); + if (cubic_1) { + ray_1.setPoints((*cubic_1)[2], start_arc_point); } - Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2); - bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0; - double angle = angle_between(ray1, ray2, ccwToggle); - double handleAngle = ray1.angle() - angle; - if (ccwToggle) { - handleAngle = ray1.angle() + angle; + if (cubic_2) { + ray_2.setPoints(end_arc_point, (*cubic_2)[1]); } - Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint; - handleAngle = ray2.angle() + angle; - if (ccwToggle) { - handleAngle = ray2.angle() - angle; + bool ccw_toggle = cross(curve_it1->finalPoint() - start_arc_point, end_arc_point - start_arc_point) < 0; + double angle = angle_between(ray_1, ray_2, ccw_toggle); + double handle_angle_1 = ray_1.angle() - angle; + double handle_angle_2 = ray_2.angle() + angle; + if (ccw_toggle) { + handle_angle_1 = ray_1.angle() + angle; + handle_angle_2 = ray_2.angle() - angle; } - Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2); - //straigth lines arc based - Line const x_line(Geom::Point(0,0),Geom::Point(1,0)); - Line const angled_line(startArcPoint,endArcPoint); - double angleArc = Geom::angle_between( x_line,angled_line); - double radius = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint))/sin(angle/2.0); - Coord rx = radius; - Coord ry = rx; - - if (times[1] != 1) { - if (times[1] != gapHelper && times[1] != times[0] + gapHelper) { - path_out.append(*knotCurve1); - } - int type = 0; - if(path_it->closed() && last){ - type = std::abs(filletChamferData[counter - counterCurves][Y]); - } else if (!path_it->closed() && last){ - //0 - } else { - type = std::abs(filletChamferData[counter + 1][Y]); - } - if(are_near(middle_point(startArcPoint,endArcPoint),curve_it1->finalPoint(), 0.0001)){ - path_out.appendNew<Geom::LineSegment>(endArcPoint); - } else if (type >= 3000 && type < 4000) { - unsigned int chamferSubs = type-3000; - Geom::Path path_chamfer; - path_chamfer.start(path_out.finalPoint()); - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - } else { - path_chamfer.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint); - } - double chamfer_stepsTime = 1.0/chamferSubs; - for(unsigned int i = 1; i < chamferSubs; i++){ - Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i); - path_out.appendNew<Geom::LineSegment>(chamferStep); + Geom::Point handle_1 = Geom::Point::polar(ray_1.angle(), k1) + start_arc_point; + Geom::Point handle_2 = end_arc_point - Geom::Point::polar(ray_2.angle(), k2); + Geom::Point inverse_handle_1 = Geom::Point::polar(handle_angle_1, k1) + start_arc_point; + Geom::Point inverse_handle_2 = end_arc_point - Geom::Point::polar(handle_angle_2, k2); + if (time0 == 1) { + handle_1 = start_arc_point; + inverse_handle_1 = start_arc_point; + } + //remove gap helper + if (time2 == 1) { + end_arc_point = curve_it2.pointAt(time2); + } + if (time1 == time0) { + start_arc_point = curve_it1->pointAt(time0); + } + if (time1 != 1) { + if (time1 != time0 || (time1 == 1 && time0 == 1)) { + if (!knot_curve_1->isDegenerate()) { + tmp_path.append(*knot_curve_1); } - path_out.appendNew<Geom::LineSegment>(endArcPoint); - } else if (type >= 4000 && type < 5000) { - unsigned int chamferSubs = type-4000; - Geom::Path path_chamfer; - path_chamfer.start(path_out.finalPoint()); - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - ccwToggle = ccwToggle?0:1; - path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - }else{ - path_chamfer.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint); + } + SatelliteType type = satellite.satellite_type; + size_t steps = satellite.steps; + if (!steps) steps = 1; + Geom::Line const x_line(Geom::Point(0, 0), Geom::Point(1, 0)); + Geom::Line const angled_line(start_arc_point, end_arc_point); + double arc_angle = Geom::angle_between(x_line, angled_line); + double radius = Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point)) / + sin(angle / 2.0); + Geom::Coord rx = radius; + Geom::Coord ry = rx; + bool eliptical = (is_straight_curve(*curve_it1) && + is_straight_curve(curve_it2) && method != FM_BEZIER) || + method == FM_ARC; + switch (type) { + case CHAMFER: + { + Geom::Path path_chamfer; + path_chamfer.start(tmp_path.finalPoint()); + if (eliptical) { + ccw_toggle = ccw_toggle ? 0 : 1; + path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point); + } else { + path_chamfer.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point); + } + addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps); } - double chamfer_stepsTime = 1.0/chamferSubs; - for(unsigned int i = 1; i < chamferSubs; i++){ - Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i); - path_out.appendNew<Geom::LineSegment>(chamferStep); + break; + case INVERSE_CHAMFER: + { + Geom::Path path_chamfer; + path_chamfer.start(tmp_path.finalPoint()); + if (eliptical) { + path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point); + } else { + path_chamfer.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point); + } + addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps); } - path_out.appendNew<Geom::LineSegment>(endArcPoint); - } else if (type == 2) { - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - ccwToggle = ccwToggle?0:1; - path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - }else{ - path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint); + break; + case INVERSE_FILLET: + { + if (eliptical) { + tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point); + } else { + tmp_path.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point); + } } - } else if (type == 1){ - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - } else { - path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint); + break; + default: //fillet + { + if (eliptical) { + ccw_toggle = ccw_toggle ? 0 : 1; + tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point); + } else { + tmp_path.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point); + } } + break; } } else { - path_out.append(*knotCurve1); - } - if (path_it->closed() && last) { - path_out.close(); - } - ++curve_it1; - if (curve_it2 != curve_endit) { - ++curve_it2; + if (!knot_curve_1->isDegenerate()) { + tmp_path.append(*knot_curve_1); + } } - counter++; - counterCurves++; + curve++; + time0 = time2; + } + if (path_it->closed()) { + tmp_path.close(); } - pathvector_out.push_back(path_out); + path++; + path_out.push_back(tmp_path); } - return pathvector_out; + return path_out; } }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 290a37f92..7f5dd7d4c 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -7,25 +7,22 @@ * * Copyright (C) 2014 Author(s) * - * Special thanks to Johan Engelen for the base of the effect -powerstroke- - * Also to ScislaC for point me to the idea - * Also su_v for his construvtive feedback and time - * and finaly to Liam P. White for his big help on coding, that save me a lot of hours + * Jabiertxof:Thanks to all people help me * * Released under GNU GPL, read the file 'COPYING' for more information */ #include "live_effects/parameter/enum.h" -#include "live_effects/parameter/bool.h" -#include "live_effects/parameter/unit.h" - -#include "live_effects/parameter/filletchamferpointarray.h" +#include "live_effects/parameter/satellitesarray.h" #include "live_effects/effect.h" +#include "live_effects/parameter/unit.h" +#include "helper/geom-pathvectorsatellites.h" +#include "helper/geom-satellite.h" namespace Inkscape { namespace LivePathEffect { -enum FilletMethod { +enum Filletmethod { FM_AUTO, FM_ARC, FM_BEZIER, @@ -35,41 +32,38 @@ enum FilletMethod { class LPEFilletChamfer : public Effect { public: LPEFilletChamfer(LivePathEffectObject *lpeobject); - virtual ~LPEFilletChamfer(); - + virtual void doBeforeEffect(SPLPEItem const *lpeItem); virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in); - virtual void doOnApply(SPLPEItem const *lpeItem); - virtual void doBeforeEffect(SPLPEItem const *lpeItem); - virtual void adjustForNewPath(Geom::PathVector const &path_in); - virtual Gtk::Widget* newWidget(); - - int getKnotsNumber(SPCurve const *c); - void toggleHide(); - void toggleFlexFixed(); - void chamfer(); - void chamferSubdivisions(); - void inverseChamfer(); - void fillet(); - void inverseFillet(); - void updateFillet(); - void doUpdateFillet(Geom::PathVector const& original_pathv, double power); - void doChangeType(Geom::PathVector const& original_pathv, int type); + virtual Gtk::Widget *newWidget(); + Geom::Ray getRay(Geom::Point start, Geom::Point end, Geom::Curve *curve, bool reverse); + void addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps); + void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); + void updateSatelliteType(SatelliteType satellitetype); + void setSelected(PathVectorSatellites *_pathvector_satellites); + //void convertUnit(); + void updateChamferSteps(); + void updateAmount(); void refreshKnots(); - FilletChamferPointArrayParam fillet_chamfer_values; + SatellitesArrayParam satellites_param; private: - - BoolParam hide_knots; - BoolParam ignore_radius_0; - BoolParam only_selected; - BoolParam flexible; - BoolParam use_knot_distance; - EnumParam<FilletMethod> method; + UnitParam unit; + EnumParam<Filletmethod> method; ScalarParam radius; ScalarParam chamfer_steps; + BoolParam flexible; + BoolParam mirror_knots; + BoolParam only_selected; + BoolParam use_knot_distance; + BoolParam hide_knots; + BoolParam apply_no_radius; + BoolParam apply_with_radius; ScalarParam helper_size; + bool _degenerate_hide; + PathVectorSatellites *_pathvector_satellites; + Geom::PathVector _hp; LPEFilletChamfer(const LPEFilletChamfer &); LPEFilletChamfer &operator=(const LPEFilletChamfer &); diff --git a/src/live_effects/parameter/array.cpp b/src/live_effects/parameter/array.cpp index 1b8f742da..7470f54cd 100644 --- a/src/live_effects/parameter/array.cpp +++ b/src/live_effects/parameter/array.cpp @@ -5,10 +5,7 @@ */ #include "live_effects/parameter/array.h" - -#include "svg/svg.h" -#include "svg/stringstream.h" - +#include "helper-fns.h" #include <2geom/coord.h> #include <2geom/point.h> @@ -49,6 +46,45 @@ ArrayParam<Geom::Point>::readsvg(const gchar * str) return Geom::Point(Geom::infinity(),Geom::infinity()); } + +template <> +std::vector<Satellite> +ArrayParam<std::vector<Satellite > >::readsvg(const gchar * str) +{ + std::vector<Satellite> subpath_satellites; + if (!str) { + return subpath_satellites; + } + gchar ** strarray = g_strsplit(str, "@", 0); + gchar ** iter = strarray; + while (*iter != NULL) { + gchar ** strsubarray = g_strsplit(*iter, ",", 8); + if (*strsubarray[7]) {//steps always > 0 + Satellite *satellite = new Satellite(); + satellite->setSatelliteType(g_strstrip(strsubarray[0])); + satellite->is_time = strncmp(strsubarray[1],"1",1) == 0; + satellite->selected = strncmp(strsubarray[2],"1",1) == 0; + satellite->has_mirror = strncmp(strsubarray[3],"1",1) == 0; + satellite->hidden = strncmp(strsubarray[4],"1",1) == 0; + double amount,angle; + float stepsTmp; + sp_svg_number_read_d(strsubarray[5], &amount); + sp_svg_number_read_d(strsubarray[6], &angle); + sp_svg_number_read_f(g_strstrip(strsubarray[7]), &stepsTmp); + unsigned int steps = (unsigned int)stepsTmp; + satellite->amount = amount; + satellite->angle = angle; + satellite->steps = steps; + subpath_satellites.push_back(*satellite); + } + g_strfreev (strsubarray); + iter++; + } + g_strfreev (strarray); + return subpath_satellites; +} + + } /* namespace LivePathEffect */ } /* namespace Inkscape */ diff --git a/src/live_effects/parameter/array.h b/src/live_effects/parameter/array.h index fa08e1f91..10a3ea018 100644 --- a/src/live_effects/parameter/array.h +++ b/src/live_effects/parameter/array.h @@ -15,6 +15,7 @@ #include "live_effects/parameter/parameter.h" +#include "helper/geom-satellite.h" #include "svg/svg.h" #include "svg/stringstream.h" @@ -93,7 +94,43 @@ protected: // separate items with pipe symbol str << " | "; } - str << vector[i]; + writesvgData(str,vector[i]); + } + } + + void writesvgData(SVGOStringStream &str, float const &vector_data) const { + str << vector_data; + } + + void writesvgData(SVGOStringStream &str, double const &vector_data) const { + str << vector_data; + } + + void writesvgData(SVGOStringStream &str, Geom::Point const &vector_data) const { + str << vector_data; + } + + void writesvgData(SVGOStringStream &str, std::vector<Satellite> const &vector_data) const { + for (size_t i = 0; i < vector_data.size(); ++i) { + if (i != 0) { + // separate items with @ symbol ¿Any other? + str << " @ "; + } + str << vector_data[i].getSatelliteTypeGchar(); + str << ","; + str << vector_data[i].is_time; + str << ","; + str << vector_data[i].selected; + str << ","; + str << vector_data[i].has_mirror; + str << ","; + str << vector_data[i].hidden; + str << ","; + str << vector_data[i].amount; + str << ","; + str << vector_data[i].angle; + str << ","; + str << vector_data[i].steps; } } diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp deleted file mode 100644 index 7696288b0..000000000 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ /dev/null @@ -1,873 +0,0 @@ -/* - * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> - * Special thanks to Johan Engelen for the base of the effect -powerstroke- - * Also to ScislaC for point me to the idea - * Also su_v for his construvtive feedback and time - * and finaly to Liam P. White for his big help on coding, that save me a lot of - * hours - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <2geom/piecewise.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/sbasis-geometric.h> -#include <2geom/line.h> -#include <2geom/path-intersection.h> - -#include "ui/dialog/lpe-fillet-chamfer-properties.h" -#include "live_effects/parameter/filletchamferpointarray.h" -#include "live_effects/effect.h" -#include "svg/svg.h" -#include "svg/stringstream.h" -#include "knotholder.h" -#include "sp-lpe-item.h" -#include "selection.h" - -// needed for on-canvas editting: -#include "live_effects/lpeobject.h" -#include "helper/geom-nodetype.h" -#include "helper/geom-curves.h" -#include "ui/tools/node-tool.h" - -// TODO due to internal breakage in glibmm headers, -// this has to be included last. -#include <glibmm/i18n.h> - - -using namespace Geom; - -namespace Inkscape { - -namespace LivePathEffect { - -FilletChamferPointArrayParam::FilletChamferPointArrayParam( - const Glib::ustring &label, const Glib::ustring &tip, - const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr, - Effect *effect) - : ArrayParam<Point>(label, tip, key, wr, effect, 0) -{ - knot_shape = SP_KNOT_SHAPE_DIAMOND; - knot_mode = SP_KNOT_MODE_XOR; - knot_color = 0x00ff0000; -} - -FilletChamferPointArrayParam::~FilletChamferPointArrayParam() {} - -Gtk::Widget *FilletChamferPointArrayParam::param_newWidget() -{ - return NULL; - /* - Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = - Gtk::manage( - new Inkscape::UI::Widget::RegisteredTransformedPoint( - param_label, - param_tooltip, - param_key, - *param_wr, - param_effect->getRepr(), - param_effect->getSPDoc() - ) ); - // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Affine transf = desktop->doc2dt(); - pointwdg->setTransform(transf); - pointwdg->setValue( *this ); - pointwdg->clearProgrammatically(); - pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, - _("Change point parameter")); - - Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); - static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true); - static_cast<Gtk::HBox*>(hbox)->show_all_children(); - - return dynamic_cast<Gtk::Widget *> (hbox); - */ -} - -void -FilletChamferPointArrayParam::param_transform_multiply(Affine const &postmul, - bool /*set*/) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - if (prefs->getBool("/options/transform/rectcorners", true) && - _vector[1][X] <= 0) { - std::vector<Geom::Point> result; - for (std::vector<Point>::const_iterator point_it = _vector.begin(); - point_it != _vector.end(); ++point_it) { - Coord A = - (*point_it)[X] * ((postmul.expansionX() + postmul.expansionY()) / 2); - result.push_back(Point(A, (*point_it)[Y])); - } - param_set_and_write_new_value(result); - } - - // param_set_and_write_new_value( (*this) * postmul ); -} - -/** call this method to recalculate the controlpoints such that they stay at the - * same location relative to the new path. Useful after adding/deleting nodes to - * the path.*/ -void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( - Piecewise<D2<SBasis> > const &pwd2_in) -{ - if (!last_pwd2.empty()) { - PathVector const pathv = - path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001); - PathVector last_pathv = - path_from_piecewise(remove_short_cuts(last_pwd2, 0.1), 0.001); - std::vector<Point> result; - unsigned long counter = 0; - unsigned long counterPaths = 0; - unsigned long counterCurves = 0; - long offset = 0; - long offsetPaths = 0; - Geom::NodeType nodetype; - for (PathVector::const_iterator path_it = pathv.begin(); - path_it != pathv.end(); ++path_it) { - if (path_it->empty()) { - counterPaths++; - counter++; - continue; - } - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed() && path_it->back_closed().isDegenerate()) { - const Curve &closingline = path_it->back_closed(); - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - curve_endit = path_it->end_open(); - } - } - counterCurves = 0; - while (curve_it1 != curve_endit) { - //if start a path get node type - if (counterCurves == 0) { - if (path_it->closed()) { - if (path_it->back_closed().isDegenerate()) { - nodetype = get_nodetype(path_it->back_open(), *curve_it1); - } else { - nodetype = get_nodetype(path_it->back_closed(), *curve_it1); - } - } else { - nodetype = NODE_NONE; - } - } else { - //check node type also whith straight lines because get_nodetype - //return non cusp node in a node inserted inside a straight line - //todo: if the path remove some nodes whith the result of a straight - //line but with handles, the node inserted into dont fire the knot - // because is not handle as cusp node by get_nodetype function - bool next_is_line = is_straight_curve(*curve_it1); - bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); - nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1); - if (this_is_line || next_is_line) { - nodetype = NODE_CUSP; - } - } - if (last_pathv.size() > pathv.size() || - (last_pathv.size() > counterPaths && - last_pathv[counterPaths].size() > counter - offset && - !are_near(curve_it1->initialPoint(), - last_pathv[counterPaths][counter - offset].initialPoint(), - 0.1))) { - if ( curve_it2 == curve_endit) { - if (last_pathv[counterPaths].size() != pathv[counterPaths].size()) { - offset = (last_pathv[counterPaths].size() - pathv[counterPaths].size()) * -1; - } else { - offset = 0; - } - offsetPaths += offset; - offset = offsetPaths; - } else if (counterCurves == 0 && last_pathv.size() <= pathv.size() && - counter - offset <= last_pathv[counterPaths].size() && - are_near(curve_it1->initialPoint(), - last_pathv[counterPaths].finalPoint(), 0.1) && - !last_pathv[counterPaths].closed()) { - long e = counter - offset + 1; - std::vector<Point> tmp = _vector; - for (unsigned long i = - last_pathv[counterPaths].size() + counter - offset; - i > counterCurves - offset + 1; i--) { - - if (tmp[i - 1][X] > 0) { - double fractpart, intpart; - fractpart = modf(tmp[i - 1][X], &intpart); - _vector[e] = Point(e + fractpart, tmp[i - 1][Y]); - } else { - _vector[e] = Point(tmp[i - 1][X], tmp[i - 1][Y]); - } - e++; - } - //delete temp vector - std::vector<Point>().swap(tmp); - if (last_pathv.size() > counterPaths) { - last_pathv[counterPaths] = last_pathv[counterPaths].reversed(); - } - } else { - if (last_pathv.size() > counterPaths) { - if (last_pathv[counterPaths].size() < - pathv[counterPaths].size()) { - offset++; - } else if (last_pathv[counterPaths].size() > - pathv[counterPaths].size()) { - offset--; - continue; - } - } else { - offset++; - } - } - double xPos = 0; - if (_vector[1][X] > 0) { - xPos = nearest_time(curve_it1->initialPoint(), pwd2_in); - } - if (nodetype == NODE_CUSP) { - result.push_back(Point(xPos, 1)); - } else { - result.push_back(Point(xPos, 0)); - } - } else { - double xPos = _vector[counter - offset][X]; - if (_vector.size() <= (unsigned)(counter - offset)) { - if (_vector[1][X] > 0) { - xPos = nearest_time(curve_it1->initialPoint(), pwd2_in); - } else { - xPos = 0; - } - } - if (nodetype == NODE_CUSP) { - double vectorY = _vector[counter - offset][Y]; - if (_vector.size() <= (unsigned)(counter - offset) || vectorY == 0) { - vectorY = 1; - } - result.push_back(Point(xPos, vectorY)); - } else { - if (_vector[1][X] < 0) { - xPos = 0; - } - result.push_back(Point(floor(xPos), 0)); - } - } - ++curve_it1; - if (curve_it2 != curve_endit) { - ++curve_it2; - } - counter++; - counterCurves++; - } - counterPaths++; - } - _vector = result; - write_to_SVG(); - } -} - -void FilletChamferPointArrayParam::recalculate_knots( - Piecewise<D2<SBasis> > const &pwd2_in) -{ - bool change = false; - if(_vector.size() == 0){ - return; - } - PathVector pathv = path_from_piecewise(pwd2_in, 0.001); - if (!pathv.empty()) { - std::vector<Point> result; - int counter = 0; - int counterCurves = 0; - Geom::NodeType nodetype; - for (PathVector::const_iterator path_it = pathv.begin(); - path_it != pathv.end(); ++path_it) { - if (path_it->empty()) { - counter++; - continue; - } - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed() && path_it->back_closed().isDegenerate()) { - const Curve &closingline = path_it->back_closed(); - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - curve_endit = path_it->end_open(); - } - } - counterCurves = 0; - while (curve_it1 != curve_endit) { - //if start a path get node type - if (counterCurves == 0) { - if (path_it->closed()) { - if (path_it->back_closed().isDegenerate()) { - nodetype = get_nodetype(path_it->back_open(), *curve_it1); - } else { - nodetype = get_nodetype(path_it->back_closed(), *curve_it1); - } - } else { - nodetype = NODE_NONE; - } - } else { - bool next_is_line = is_straight_curve(*curve_it1); - bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); - nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1); - if (this_is_line || next_is_line) { - nodetype = NODE_CUSP; - } - } - if (nodetype == NODE_CUSP) { - double vectorY = _vector[counter][Y]; - if (vectorY == 0) { - vectorY = 1; - change = true; - } - result.push_back(Point(_vector[counter][X], vectorY)); - } else { - double xPos = floor(_vector[counter][X]); - if (_vector[1][X] < 0) { - xPos = 0; - } - double vectorY = _vector[counter][Y]; - if (vectorY != 0) { - change = true; - } - result.push_back(Point(xPos, 0)); - } - ++curve_it1; - counter++; - if (curve_it2 != curve_endit) { - ++curve_it2; - } - counterCurves++; - } - } - if (change) { - _vector = result; - write_to_SVG(); - } - } -} - -void FilletChamferPointArrayParam::set_pwd2( - Piecewise<D2<SBasis> > const &pwd2_in, - Piecewise<D2<SBasis> > const &pwd2_normal_in) -{ - last_pwd2 = pwd2_in; - last_pwd2_normal = pwd2_normal_in; -} - -void FilletChamferPointArrayParam::set_helper_size(int hs) -{ - helper_size = hs; -} - -void FilletChamferPointArrayParam::set_chamfer_steps(int value_chamfer_steps) -{ - chamfer_steps = value_chamfer_steps; -} - -void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance ) -{ - use_distance = use_knot_distance; -} - -void FilletChamferPointArrayParam::updateCanvasIndicators() -{ - std::vector<Point> ts = data(); - hp.clear(); - unsigned int i = 0; - for (std::vector<Point>::const_iterator point_it = ts.begin(); - point_it != ts.end(); ++point_it) { - double Xvalue = to_time(i, (*point_it)[X]) -i; - if (Xvalue == 0) { - i++; - continue; - } - Geom::Point ptA = last_pwd2[i].valueAt(Xvalue); - Geom::Point derivA = unit_vector(derivative(last_pwd2[i]).valueAt(Xvalue)); - Geom::Rotate rot(Geom::Rotate::from_degrees(-90)); - derivA = derivA * rot; - Geom::Point C = ptA - derivA * helper_size; - Geom::Point D = ptA + derivA * helper_size; - Geom::Ray ray1(C, D); - char const * svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5"; - Geom::PathVector pathv = sp_svg_read_pathv(svgd); - Geom::Affine aff = Geom::Affine(); - aff *= Geom::Scale(helper_size); - aff *= Geom::Rotate(ray1.angle() - rad_from_deg(270)); - aff *= Geom::Translate(last_pwd2[i].valueAt(Xvalue)); - pathv *= aff; - hp.push_back(pathv[0]); - hp.push_back(pathv[1]); - i++; - } -} - -void FilletChamferPointArrayParam::addCanvasIndicators( - SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) -{ - hp_vec.push_back(hp); -} - -double FilletChamferPointArrayParam::rad_to_len(int index, double rad) -{ - double len = 0; - Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1); - std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths); - D2<SBasis> A = last_pwd2[last_index(index, subpaths)]; - if(positions.second != 0){ - A = last_pwd2[index-1]; - }else{ - if(!subpaths[positions.first].closed()){ - return len; - } - } - D2<SBasis> B = last_pwd2[index]; - Piecewise<D2<SBasis> > offset_curve0 = Piecewise<D2<SBasis> >(A)+rot90(unitVector(derivative(A)))*(rad); - Piecewise<D2<SBasis> > offset_curve1 = Piecewise<D2<SBasis> >(B)+rot90(unitVector(derivative(B)))*(rad); - Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0]; - Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0]; - Geom::Crossings cs = Geom::crossings(p0, p1); - if(cs.size() > 0){ - Point cp =p0(cs[0].ta); - double p0pt = nearest_time(cp, B); - len = time_to_len(index,p0pt); - } else { - if(rad < 0){ - len = rad_to_len(index, rad * -1); - } - } - return len; -} - -double FilletChamferPointArrayParam::len_to_rad(int index, double len) -{ - double rad = 0; - double tmp_len = _vector[index][X]; - _vector[index] = Geom::Point(len,_vector[index][Y]); - Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1); - std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths); - Piecewise<D2<SBasis> > u; - u.push_cut(0); - u.push(last_pwd2[last_index(index, subpaths)], 1); - Geom::Curve * A = path_from_piecewise(u, 0.1)[0][0].duplicate(); - Geom::Curve * B = subpaths[positions.first][positions.second].duplicate(); - std::vector<double> times; - if(positions.second != 0){ - A = subpaths[positions.first][positions.second-1].duplicate(); - times = get_times(index-1, subpaths, false); - }else{ - if(!subpaths[positions.first].closed()){ - return rad; - } - times = get_times(last_index(index, subpaths), subpaths, true); - } - _vector[index] = Geom::Point(tmp_len,_vector[index][Y]); - Geom::Point startArcPoint = A->toSBasis().valueAt(times[1]); - Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]); - Curve *knotCurve1 = A->portion(times[0], times[1]); - Curve *knotCurve2 = B->portion(times[2], 1); - Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(knotCurve1); - Ray ray1(startArcPoint, A->finalPoint()); - if (cubic1) { - ray1.setPoints((*cubic1)[2], startArcPoint); - } - Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(knotCurve2); - Ray ray2(B->initialPoint(), endArcPoint); - if (cubic2) { - ray2.setPoints(endArcPoint, (*cubic2)[1]); - } - bool ccwToggle = cross(A->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0; - double distanceArc = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint)); - double angleBetween = angle_between(ray1, ray2, ccwToggle); - rad = distanceArc/sin(angleBetween/2.0); - return rad * -1; -} - -std::vector<double> FilletChamferPointArrayParam::get_times(int index, Geom::PathVector subpaths, bool last) -{ - const double tolerance = 0.001; - const double gapHelper = 0.00001; - std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths); - Curve *curve_it1; - curve_it1 = subpaths[positions.first][positions.second].duplicate(); - Coord it1_length = (*curve_it1).length(tolerance); - double time_it1, time_it2, time_it1_B, intpart; - if (static_cast<int>(_vector.size()) <= index){ - std::vector<double> out; - out.push_back(0); - out.push_back(1); - out.push_back(0); - return out; - } - time_it1 = modf(to_time(index, _vector[index][X]), &intpart); - if (_vector[index][Y] == 0) { - time_it1 = 0; - } - double resultLenght = 0; - if (subpaths[positions.first].closed() && last) { - time_it2 = modf(to_time(index - positions.second , _vector[index - positions.second ][X]), &intpart); - resultLenght = it1_length + to_len(index - positions.second, _vector[index - positions.second ][X]); - } else if (!subpaths[positions.first].closed() && last){ - time_it2 = 0; - resultLenght = 0; - } else { - time_it2 = modf(to_time(index + 1, _vector[index + 1][X]), &intpart); - resultLenght = it1_length + to_len( index + 1, _vector[index + 1][X]); - } - if (resultLenght > 0 && time_it2 != 0) { - time_it1_B = modf(to_time(index, -resultLenght), &intpart); - } else { - if (time_it2 == 0) { - time_it1_B = 1; - } else { - time_it1_B = gapHelper; - } - } - - if ((subpaths[positions.first].closed() && last && _vector[index - positions.second][Y] == 0) || (subpaths[positions.first].size() > positions.second + 1 && _vector[index + 1][Y] == 0)) { - time_it1_B = 1; - time_it2 = 0; - } - if (time_it1_B < time_it1) { - time_it1_B = time_it1 + gapHelper; - } - std::vector<double> out; - out.push_back(time_it1); - out.push_back(time_it1_B); - out.push_back(time_it2); - return out; -} - -std::pair<std::size_t, std::size_t> FilletChamferPointArrayParam::get_positions(int index, Geom::PathVector subpaths) -{ - int counter = -1; - std::size_t first = 0; - std::size_t second = 0; - for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) { - if (path_it->empty()) - continue; - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_closed(); - // the closing line segment is always of type - // Geom::LineSegment. - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - // closingline.isDegenerate() did not work, because it only checks for - // *exact* zero length, which goes wrong for relative coordinates and - // rounding errors... - // the closing line segment has zero-length. So stop before that one! - curve_endit = path_it->end_open(); - } - } - first++; - second = 0; - while (curve_it1 != curve_endit) { - counter++; - second++; - if(counter == index){ - break; - } - ++curve_it1; - } - if(counter == index){ - break; - } - } - first--; - second--; - std::pair<std::size_t, std::size_t> out(first, second); - return out; -} - -int FilletChamferPointArrayParam::last_index(int index, Geom::PathVector subpaths) -{ - int counter = -1; - bool inSubpath = false; - for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) { - if (path_it->empty()) - continue; - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_closed(); - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - curve_endit = path_it->end_open(); - } - } - while (curve_it1 != curve_endit) { - counter++; - if(counter == index){ - inSubpath = true; - } - ++curve_it1; - } - if(inSubpath){ - break; - } - } - if(!inSubpath){ - counter = -1; - } - return counter; -} - - -double FilletChamferPointArrayParam::len_to_time(int index, double len) -{ - double t = 0; - if (last_pwd2.size() > (unsigned) index) { - if (len != 0) { - if (last_pwd2[index][0].degreesOfFreedom() != 2) { - Piecewise<D2<SBasis> > u; - u.push_cut(0); - u.push(last_pwd2[index], 1); - std::vector<double> t_roots = roots(arcLengthSb(u) - std::abs(len)); - if (t_roots.size() > 0) { - t = t_roots[0]; - } - } else { - double lenghtPart = 0; - if (last_pwd2.size() > (unsigned) index) { - lenghtPart = length(last_pwd2[index], EPSILON); - } - if (std::abs(len) < lenghtPart && lenghtPart != 0) { - t = std::abs(len) / lenghtPart; - } - } - } - t = double(index) + t; - } else { - t = double(last_pwd2.size() - 1); - } - - return t; -} - -double FilletChamferPointArrayParam::time_to_len(int index, double time) -{ - double intpart; - double len = 0; - time = modf(time, &intpart); - double lenghtPart = 0; - if (last_pwd2.size() <= (unsigned) index || time == 0) { - return len; - } - if (last_pwd2[index][0].degreesOfFreedom() != 2) { - Piecewise<D2<SBasis> > u; - u.push_cut(0); - u.push(last_pwd2[index], 1); - u = portion(u, 0, time); - return length(u, 0.001) * -1; - } - lenghtPart = length(last_pwd2[index], EPSILON); - return (time * lenghtPart) * -1; -} - -double FilletChamferPointArrayParam::to_time(int index, double A) -{ - if (A > 0) { - return A; - } else { - return len_to_time(index, A); - } -} - -double FilletChamferPointArrayParam::to_len(int index, double A) -{ - if (A > 0) { - return time_to_len(index, A); - } else { - return A; - } -} - -void FilletChamferPointArrayParam::set_oncanvas_looks(SPKnotShapeType shape, - SPKnotModeType mode, - guint32 color) -{ - knot_shape = shape; - knot_mode = mode; - knot_color = color; -} - -FilletChamferPointArrayParamKnotHolderEntity:: -FilletChamferPointArrayParamKnotHolderEntity( - FilletChamferPointArrayParam *p, unsigned int index) - : _pparam(p), _index(index) {} - -void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p, - Point const &/*origin*/, - guint state) -{ - using namespace Geom; - - if (!valid_index(_index)) { - return; - } - Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2(); - double t = nearest_time(p, pwd2[_index]); - Geom::Point const s = snap_knot_position(pwd2[_index].valueAt(t), state); - t = nearest_time(s, pwd2[_index]); - if (t == 1) { - t = 0.9999; - } - t += _index; - - if (_pparam->_vector.at(_index)[X] <= 0) { - _pparam->_vector.at(_index) = - Point(_pparam->time_to_len(_index, t), _pparam->_vector.at(_index)[Y]); - } else { - _pparam->_vector.at(_index) = Point(t, _pparam->_vector.at(_index)[Y]); - } - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); -} - -Point FilletChamferPointArrayParamKnotHolderEntity::knot_get() const -{ - using namespace Geom; - - if (!valid_index(_index)) { - return Point(infinity(), infinity()); - } - - Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2(); - - double time_it = _pparam->to_time(_index, _pparam->_vector.at(_index)[X]); - Point canvas_point = pwd2.valueAt(time_it); - - _pparam->updateCanvasIndicators(); - return canvas_point; - -} - -void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) -{ - if (state & GDK_CONTROL_MASK) { - if (state & GDK_MOD1_MASK) { - _pparam->_vector.at(_index) = Point(_index, _pparam->_vector.at(_index)[Y]); - _pparam->param_set_and_write_new_value(_pparam->_vector); - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); - }else{ - using namespace Geom; - int type = (int)_pparam->_vector.at(_index)[Y]; - if (type >=3000 && type < 4000){ - type = 3; - } - if (type >=4000 && type < 5000){ - type = 4; - } - switch(type){ - case 1: - type = 2; - break; - case 2: - type = _pparam->chamfer_steps + 3000; - break; - case 3: - type = _pparam->chamfer_steps + 4000; - break; - default: - type = 1; - break; - } - _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], (double)type); - _pparam->param_set_and_write_new_value(_pparam->_vector); - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); - const gchar *tip; - if (type >=3000 && type < 4000){ - tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else if (type >=4000 && type < 5000) { - tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else if (type == 2) { - tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else { - tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } - this->knot->tip = g_strdup(tip); - this->knot->show(); - } - } else if (state & GDK_SHIFT_MASK) { - double xModified = _pparam->_vector.at(_index).x(); - if(xModified < 0 && !_pparam->use_distance){ - xModified = _pparam->len_to_rad(_index, _pparam->_vector.at(_index).x()); - } - Geom::PathVector subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1); - std::pair<std::size_t, std::size_t> positions = _pparam->get_positions(_index, subpaths); - D2<SBasis> A = _pparam->last_pwd2[_pparam->last_index(_index, subpaths)]; - if(positions.second != 0){ - A = _pparam->last_pwd2[_index-1]; - } - D2<SBasis> B = _pparam->last_pwd2[_index]; - bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false; - Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y()); - Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( - this->desktop, offset, this, _pparam->use_distance, aprox); - } - -} - -void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset( - Geom::Point offset) -{ - double xModified = offset.x(); - if(xModified < 0 && !_pparam->use_distance){ - xModified = _pparam->rad_to_len(_index, offset.x()); - } - _pparam->_vector.at(_index) = Geom::Point(xModified, offset.y()); - this->parent_holder->knot_ungrabbed_handler(this->knot, 0); -} - -void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { - recalculate_knots(get_pwd2()); - for (unsigned int i = 0; i < _vector.size(); ++i) { - if (_vector[i][Y] <= 0) { - continue; - } - const gchar *tip; - if (_vector[i][Y] >=3000 && _vector[i][Y] < 4000){ - tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else if (_vector[i][Y] >=4000 && _vector[i][Y] < 5000) { - tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else if (_vector[i][Y] == 2) { - tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else { - tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } - FilletChamferPointArrayParamKnotHolderEntity *e = - new FilletChamferPointArrayParamKnotHolderEntity(this, i); - e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip), - knot_shape, knot_mode, knot_color); - knotholder->add(e); - } - updateCanvasIndicators(); -} - -} /* namespace LivePathEffect */ - -} /* namespace Inkscape */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h deleted file mode 100644 index 4e4268703..000000000 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H -#define INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H - -/* - * Inkscape::LivePathEffectParameters - * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> - * Special thanks to Johan Engelen for the base of the effect -powerstroke- - * Also to ScislaC for point me to the idea - * Also su_v for his construvtive feedback and time - * and finaly to Liam P. White for his big help on coding, that save me a lot of - * hours - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <glib.h> -#include <2geom/point.h> - -#include "live_effects/parameter/array.h" - -#include "knot-holder-entity.h" - -namespace Inkscape { - -namespace LivePathEffect { - -class FilletChamferPointArrayParamKnotHolderEntity; - -class FilletChamferPointArrayParam : public ArrayParam<Geom::Point> { -public: - FilletChamferPointArrayParam(const Glib::ustring &label, - const Glib::ustring &tip, - const Glib::ustring &key, - Inkscape::UI::Widget::Registry *wr, - Effect *effect); - virtual ~FilletChamferPointArrayParam(); - - virtual Gtk::Widget *param_newWidget(); - - virtual void param_transform_multiply(Geom::Affine const &postmul, - bool /*set*/); - - void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, - guint32 color); - virtual double to_time(int index, double A); - virtual double to_len(int index, double A); - virtual double rad_to_len(int index, double rad); - virtual double len_to_rad(int index, double len); - virtual double len_to_time(int index, double len); - virtual double time_to_len(int index, double time); - virtual std::pair<std::size_t, std::size_t> get_positions(int index, Geom::PathVector subpaths); - virtual int last_index(int index, Geom::PathVector subpaths); - std::vector<double> get_times(int index, Geom::PathVector subpaths, bool last); - virtual void set_helper_size(int hs); - virtual void set_use_distance(bool use_knot_distance); - virtual void set_chamfer_steps(int value_chamfer_steps); - virtual void addCanvasIndicators(SPLPEItem const *lpeitem, - std::vector<Geom::PathVector> &hp_vec); - virtual void param_update_default(const gchar * default_value){}; - virtual bool providesKnotHolderEntities() const { - return true; - } - virtual void updateCanvasIndicators(); - virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); - - void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in, - Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_normal_in); - Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2() const { - return last_pwd2; - } - Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2_normal() const { - return last_pwd2_normal; - } - - void recalculate_controlpoints_for_new_pwd2( - Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in); - void recalculate_knots( - Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in); - friend class FilletChamferPointArrayParamKnotHolderEntity; - -private: - FilletChamferPointArrayParam(const FilletChamferPointArrayParam &); - FilletChamferPointArrayParam &operator=(const FilletChamferPointArrayParam &); - - SPKnotShapeType knot_shape; - SPKnotModeType knot_mode; - guint32 knot_color; - int helper_size; - int chamfer_steps; - bool use_distance; - Geom::PathVector hp; - - Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2; - Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal; -}; - -class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity { -public: - FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam *p, - unsigned int index); - virtual ~FilletChamferPointArrayParamKnotHolderEntity() {} - - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, - guint state); - virtual Geom::Point knot_get() const; - virtual void knot_click(guint state); - virtual void knot_set_offset(Geom::Point offset); - - /*Checks whether the index falls within the size of the parameter's vector*/ - bool valid_index(unsigned int index) const { - return (_pparam->_vector.size() > index); - } - ; - -private: - FilletChamferPointArrayParam *_pparam; - unsigned int _index; -}; - -} //namespace LivePathEffect - -} //namespace Inkscape - -#endif diff --git a/src/live_effects/parameter/satellitesarray.cpp b/src/live_effects/parameter/satellitesarray.cpp new file mode 100644 index 000000000..7626317a1 --- /dev/null +++ b/src/live_effects/parameter/satellitesarray.cpp @@ -0,0 +1,583 @@ +/* + * Author(s): + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * + * Copyright (C) 2014 Author(s) + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "knotholder.h" +#include "ui/dialog/lpe-fillet-chamfer-properties.h" +#include "live_effects/parameter/satellitesarray.h" +#include "live_effects/effect.h" +#include "sp-lpe-item.h" +#include "inkscape.h" +#include <preferences.h> +// TODO due to internal breakage in glibmm headers, +// this has to be included last. +#include <glibmm/i18n.h> + +namespace Inkscape { + +namespace LivePathEffect { + +SatellitesArrayParam::SatellitesArrayParam(const Glib::ustring &label, + const Glib::ustring &tip, + const Glib::ustring &key, + Inkscape::UI::Widget::Registry *wr, + Effect *effect) + : ArrayParam<std::vector<Satellite> >(label, tip, key, wr, effect, 0), _knoth(NULL) +{ + _knot_shape = SP_KNOT_SHAPE_DIAMOND; + _knot_mode = SP_KNOT_MODE_XOR; + _knot_color = 0xAAFF8800; + _helper_size = 0; + _use_distance = false; + _global_knot_hide = false; + _current_zoom = 0; + _effectType = FILLET_CHAMFER; + _last_pathvector_satellites = NULL; +} + + +void SatellitesArrayParam::set_oncanvas_looks(SPKnotShapeType shape, + SPKnotModeType mode, + guint32 color) +{ + _knot_shape = shape; + _knot_mode = mode; + _knot_color = color; +} + +void SatellitesArrayParam::setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write) +{ + _last_pathvector_satellites = pathVectorSatellites; + if (write) { + param_set_and_write_new_value(_last_pathvector_satellites->getSatellites()); + } else { + param_setValue(_last_pathvector_satellites->getSatellites()); + } +} + +void SatellitesArrayParam::setUseDistance(bool use_knot_distance) +{ + _use_distance = use_knot_distance; +} + +void SatellitesArrayParam::setCurrentZoom(double current_zoom) +{ + _current_zoom = current_zoom; +} + +void SatellitesArrayParam::setGlobalKnotHide(bool global_knot_hide) +{ + _global_knot_hide = global_knot_hide; +} +void SatellitesArrayParam::setEffectType(EffectType et) +{ + _effectType = et; +} + +void SatellitesArrayParam::setHelperSize(int hs) +{ + _helper_size = hs; + updateCanvasIndicators(); +} + +void SatellitesArrayParam::updateCanvasIndicators(bool mirror) +{ + if (!_last_pathvector_satellites) { + return; + } + + if (!_hp.empty()) { + _hp.clear(); + } + Geom::PathVector pathv = _last_pathvector_satellites->getPathVector(); + if (pathv.empty()) { + return; + } + if (mirror == true) { + _hp.clear(); + } + if (_effectType == FILLET_CHAMFER) { + for (size_t i = 0; i < _vector.size(); ++i) { + for (size_t j = 0; j < _vector[i].size(); ++j) { + if (_vector[i][j].hidden || //Ignore if hidden + (!_vector[i][j].has_mirror && mirror == true) || //Ignore if not have mirror and we are in mirror loop + _vector[i][j].amount == 0 || //no helper in 0 value + pathv[i].size() == j || //ignore last satellite in open paths with fillet chamfer effect + (!pathv[i].closed() && j == 0)) //ignore first satellites on open paths + { + continue; + } + Geom::Curve *curve_in = pathv[i][j].duplicate(); + double pos = 0; + bool overflow = false; + double size_out = _vector[i][j].arcDistance(*curve_in); + double lenght_out = curve_in->length(); + gint previous_index = j - 1; //Always are previous index because we skip first satellite on open paths + if (j == 0 && pathv[i].closed()) { + previous_index = pathv[i].size() - 1; + } + if ( previous_index < 0 ) { + return; + } + double lenght_in = pathv.curveAt(previous_index).length(); + if (mirror) { + curve_in = const_cast<Geom::Curve *>(&pathv.curveAt(previous_index)); + pos = _vector[i][j].time(size_out, true, *curve_in); + if (lenght_out < size_out) { + overflow = true; + } + } else { + pos = _vector[i][j].time(*curve_in); + if (lenght_in < size_out) { + overflow = true; + } + } + if (pos <= 0 || pos >= 1) { + continue; + } + Geom::Point point_a = curve_in->pointAt(pos); + Geom::Point deriv_a = unit_vector(derivative(curve_in->toSBasis()).pointAt(pos)); + Geom::Rotate rot(Geom::Rotate::from_degrees(-90)); + deriv_a = deriv_a * rot; + Geom::Point point_c = point_a - deriv_a * _helper_size; + Geom::Point point_d = point_a + deriv_a * _helper_size; + Geom::Ray ray_1(point_c, point_d); + char const *svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + Geom::Affine aff = Geom::Affine(); + aff *= Geom::Scale(_helper_size); + if (mirror) { + aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90)); + } else { + aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270)); + } + aff *= Geom::Translate(curve_in->pointAt(pos)); + pathv *= aff; + _hp.push_back(pathv[0]); + _hp.push_back(pathv[1]); + if (overflow) { + double diameter = _helper_size; + if (_helper_size == 0) { + diameter = 15; + char const *svgd; + 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 " + "0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + aff = Geom::Affine(); + aff *= Geom::Scale(diameter); + aff *= Geom::Translate(point_a - Geom::Point(diameter * 0.35, diameter * 0.35)); + pathv *= aff; + _hp.push_back(pathv[0]); + } else { + char const *svgd; + 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 " + "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 " + "0 -1.32 z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + aff = Geom::Affine(); + aff *= Geom::Scale(_helper_size / 2.0); + if (mirror) { + aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90)); + } else { + aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270)); + } + aff *= Geom::Translate(curve_in->pointAt(pos)); + pathv *= aff; + _hp.push_back(pathv[0]); + } + } + } + } + } + if (!_knot_reset_helper.empty()) { + _hp.insert(_hp.end(), _knot_reset_helper.begin(), _knot_reset_helper.end() ); + } + if (mirror) { + updateCanvasIndicators(false); + } +} +void SatellitesArrayParam::updateCanvasIndicators() +{ + updateCanvasIndicators(true); +} + +void SatellitesArrayParam::addCanvasIndicators( + SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) +{ + hp_vec.push_back(_hp); +} + +void SatellitesArrayParam::param_transform_multiply(Geom::Affine const &postmul, bool /*set*/) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + if (prefs->getBool("/options/transform/rectcorners", true)) { + for (size_t i = 0; i < _vector.size(); ++i) { + for (size_t j = 0; j < _vector[i].size(); ++j) { + if (!_vector[i][j].is_time && _vector[i][j].amount > 0) { + _vector[i][j].amount = _vector[i][j].amount * ((postmul.expansionX() + postmul.expansionY()) / 2); + } + } + } + param_set_and_write_new_value(_vector); + } +} + +void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder, + SPItem *item, + bool mirror) +{ + if (!_last_pathvector_satellites) { + return; + } + Geom::PathVector pathv = _last_pathvector_satellites->getPathVector(); + size_t index = 0; + for (size_t i = 0; i < _vector.size(); ++i) { + for (size_t j = 0; j < _vector[i].size(); ++j) { + if (!_vector[i][j].has_mirror && mirror) { + continue; + } + SatelliteType type = _vector[i][j].satellite_type; + if (mirror && i == 0 && j == 0) { + index = index + _last_pathvector_satellites->getTotalSatellites(); + } + using namespace Geom; + //If is for filletChamfer effect... + if (_effectType == FILLET_CHAMFER) { + const gchar *tip; + if (type == CHAMFER) { + tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> reset"); + } else if (type == INVERSE_CHAMFER) { + tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> reset"); + } else if (type == INVERSE_FILLET) { + tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> reset"); + } else { + tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> reset"); + } + FilletChamferKnotHolderEntity *e = new FilletChamferKnotHolderEntity(this, index); + e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),_knot_shape, _knot_mode, _knot_color); + knotholder->add(e); + } + index++; + } + } + if (mirror) { + addKnotHolderEntities(knotholder, item, false); + } +} + +void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder, + SPItem *item) +{ + _knoth = knotholder; + addKnotHolderEntities(knotholder, item, true); +} + +FilletChamferKnotHolderEntity::FilletChamferKnotHolderEntity( + SatellitesArrayParam *p, size_t index) + : _pparam(p), _index(index) {} + +void FilletChamferKnotHolderEntity::knot_set(Geom::Point const &p, + Geom::Point const &/*origin*/, + guint state) +{ + if (!_pparam->_last_pathvector_satellites) { + return; + } + size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites(); + bool is_mirror = false; + size_t index = _index; + if (_index >= total_satellites) { + index = _index - total_satellites; + is_mirror = true; + } + std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index); + size_t path_index = index_data.first; + size_t curve_index = index_data.second; + + Geom::Point s = snap_knot_position(p, state); + if (!valid_index(path_index, curve_index)) { + return; + } + Satellite satellite = _pparam->_vector[path_index][curve_index]; + Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector(); + if (satellite.hidden || + (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths + pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect + { + return; + } + gint previous_index = curve_index - 1; + if (curve_index == 0 && pathv[path_index].closed()) { + previous_index = pathv[path_index].size() - 1; + } + if ( previous_index < 0 ) { + return; + } + Geom::Curve const &curve_in = pathv[path_index][previous_index]; + double mirror_time = Geom::nearest_time(s, curve_in); + Geom::Point mirror = curve_in.pointAt(mirror_time); + double normal_time = Geom::nearest_time(s, pathv[path_index][curve_index]); + Geom::Point normal = pathv[path_index][curve_index].pointAt(normal_time); + double distance_mirror = Geom::distance(mirror,s); + double distance_normal = Geom::distance(normal,s); + if (Geom::are_near(s, pathv[path_index][curve_index].initialPoint(), 1.5 / _pparam->_current_zoom)) { + satellite.amount = 0; + } else if (distance_mirror < distance_normal) { + double time_start = 0; + Satellites satellites = _pparam->_last_pathvector_satellites->getSatellites(); + time_start = satellites[path_index][previous_index].time(curve_in); + if (time_start > mirror_time) { + mirror_time = time_start; + } + double size = arcLengthAt(mirror_time, curve_in); + double amount = curve_in.length() - size; + if (satellite.is_time) { + amount = timeAtArcLength(amount, pathv[path_index][curve_index]); + } + satellite.amount = amount; + } else { + satellite.setPosition(s, pathv[path_index][curve_index]); + } + _pparam->_knot_reset_helper.clear(); + if (satellite.amount == 0) { + char const *svgd; + 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 " + "m -1.83,1.71 3.78,3.7 M 5.24,8.78 8.98,5.29 10.24,10.28 Z " + "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"; + _pparam->_knot_reset_helper = sp_svg_read_pathv(svgd); + _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()); + } + _pparam->_vector[path_index][curve_index] = satellite; + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); +} + +Geom::Point FilletChamferKnotHolderEntity::knot_get() const +{ + if (!_pparam->_last_pathvector_satellites || _pparam->_global_knot_hide) { + return Geom::Point(Geom::infinity(), Geom::infinity()); + } + Geom::Point tmp_point; + size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites(); + bool is_mirror = false; + size_t index = _index; + if (_index >= total_satellites) { + index = _index - total_satellites; + is_mirror = true; + } + std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index); + size_t path_index = index_data.first; + size_t curve_index = index_data.second; + if (!valid_index(path_index, curve_index)) { + return Geom::Point(Geom::infinity(), Geom::infinity()); + } + Satellite satellite = _pparam->_vector[path_index][curve_index]; + Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector(); + if (satellite.hidden || + (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths + pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect + { + return Geom::Point(Geom::infinity(), Geom::infinity()); + } + this->knot->show(); + if (is_mirror) { + gint previous_index = curve_index - 1; + if (curve_index == 0 && pathv[path_index].closed()) { + previous_index = pathv[path_index].size() - 1; + } + if ( previous_index < 0 ) { + return Geom::Point(Geom::infinity(), Geom::infinity()); + } + Geom::Curve const &curve_in = pathv[path_index][previous_index]; + double s = satellite.arcDistance(pathv[path_index][curve_index]); + double t = satellite.time(s, true, curve_in); + if (t > 1) { + t = 1; + } + if (t < 0) { + t = 0; + } + double time_start = 0; + time_start = _pparam->_last_pathvector_satellites->getSatellites()[path_index][previous_index].time(curve_in); + if (time_start > t) { + t = time_start; + } + tmp_point = (curve_in).pointAt(t); + } else { + tmp_point = satellite.getPosition(pathv[path_index][curve_index]); + } + Geom::Point const canvas_point = tmp_point; + _pparam->updateCanvasIndicators(); + return canvas_point; +} + +void FilletChamferKnotHolderEntity::knot_click(guint state) +{ + if (!_pparam->_last_pathvector_satellites) { + return; + } + size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites(); + bool is_mirror = false; + size_t index = _index; + if (_index >= total_satellites) { + index = _index - total_satellites; + is_mirror = true; + } + std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index); + size_t path_index = index_data.first; + size_t curve_index = index_data.second; + if (!valid_index(path_index, curve_index)) { + return; + } + Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector(); + if ((!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths + pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect + { + return; + } + if (state & GDK_CONTROL_MASK) { + if (state & GDK_MOD1_MASK) { + _pparam->_vector[path_index][curve_index].amount = 0.0; + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + } else { + using namespace Geom; + SatelliteType type = _pparam->_vector[path_index][curve_index].satellite_type; + switch (type) { + case FILLET: + type = INVERSE_FILLET; + break; + case INVERSE_FILLET: + type = CHAMFER; + break; + case CHAMFER: + type = INVERSE_CHAMFER; + break; + default: + type = FILLET; + break; + } + _pparam->_vector[path_index][curve_index].satellite_type = type; + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + const gchar *tip; + if (type == CHAMFER) { + tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> resets"); + } else if (type == INVERSE_CHAMFER) { + tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> resets"); + } else if (type == INVERSE_FILLET) { + tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> resets"); + } else { + tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> resets"); + } + this->knot->tip = g_strdup(tip); + this->knot->show(); + } + } else if (state & GDK_SHIFT_MASK) { + double amount = _pparam->_vector[path_index][curve_index].amount; + gint previous_index = curve_index - 1; + if (curve_index == 0 && pathv[path_index].closed()) { + previous_index = pathv[path_index].size() - 1; + } + if ( previous_index < 0 ) { + return; + } + if (!_pparam->_use_distance && !_pparam->_vector[path_index][curve_index].is_time) { + 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]); + } + bool aprox = false; + Geom::D2<Geom::SBasis> d2_out = pathv[path_index][curve_index].toSBasis(); + Geom::D2<Geom::SBasis> d2_in = pathv[path_index][previous_index].toSBasis(); + aprox = ((d2_in)[0].degreesOfFreedom() != 2 || + d2_out[0].degreesOfFreedom() != 2) && + !_pparam->_use_distance + ? true + : false; + Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( + this->desktop, amount, this, _pparam->_use_distance, + aprox, _pparam->_vector[path_index][curve_index]); + + } +} + +void FilletChamferKnotHolderEntity::knot_set_offset(Satellite satellite) +{ + if (!_pparam->_last_pathvector_satellites) { + return; + } + size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites(); + bool is_mirror = false; + size_t index = _index; + if (_index >= total_satellites) { + index = _index - total_satellites; + is_mirror = true; + } + std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index); + size_t path_index = index_data.first; + size_t curve_index = index_data.second; + if (!valid_index(path_index, curve_index)) { + return; + } + Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector(); + if (satellite.hidden || + (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths + pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect + { + return; + } + double amount = satellite.amount; + double max_amount = amount; + if (!_pparam->_use_distance && !satellite.is_time) { + gint previous_index = curve_index - 1; + if (curve_index == 0 && pathv[path_index].closed()) { + previous_index = pathv[path_index].size() - 1; + } + if ( previous_index < 0 ) { + return; + } + amount = _pparam->_vector[path_index][curve_index].radToLen(amount, pathv[path_index][previous_index], pathv[path_index][curve_index]); + if (max_amount > 0 && amount == 0) { + amount = _pparam->_vector[path_index][curve_index].amount; + } + } + satellite.amount = amount; + _pparam->_vector[path_index][curve_index] = satellite; + this->parent_holder->knot_ungrabbed_handler(this->knot, 0); + SPLPEItem *splpeitem = dynamic_cast<SPLPEItem *>(item); + if (splpeitem) { + sp_lpe_item_update_patheffect(splpeitem, false, false); + } +} + +} /* namespace LivePathEffect */ + +} /* namespace Inkscape */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/parameter/satellitesarray.h b/src/live_effects/parameter/satellitesarray.h new file mode 100644 index 000000000..5ae372ac2 --- /dev/null +++ b/src/live_effects/parameter/satellitesarray.h @@ -0,0 +1,114 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_SATELLITES_ARRAY_H +#define INKSCAPE_LIVEPATHEFFECT_SATELLITES_ARRAY_H + +/* + * Inkscape::LivePathEffectParameters + * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * Special thanks to Johan Engelen for the base of the effect -powerstroke- + * Also to ScislaC for point me to the idea + * Also su_v for his construvtive feedback and time + * To Nathan Hurst for his review and help on refactor + * and finaly to Liam P. White for his big help on coding, that save me a lot of + * hours + * + * + * This parameter act as bridge from pathVectorSatellites class to serialize it as a LPE + * parameter + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/parameter/array.h" +#include "live_effects/effect-enum.h" +#include "helper/geom-pathvectorsatellites.h" +#include "knot-holder-entity.h" +#include <glib.h> + +namespace Inkscape { + +namespace LivePathEffect { + +class FilletChamferKnotHolderEntity; + +class SatellitesArrayParam : public ArrayParam<std::vector<Satellite> > { +public: + SatellitesArrayParam(const Glib::ustring &label, const Glib::ustring &tip, + const Glib::ustring &key, + Inkscape::UI::Widget::Registry *wr, Effect *effect); + + virtual Gtk::Widget *param_newWidget() + { + return NULL; + } + virtual void setHelperSize(int hs); + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item, bool mirror); + virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); + virtual void updateCanvasIndicators(); + virtual void updateCanvasIndicators(bool mirror); + virtual bool providesKnotHolderEntities() const + { + return true; + } + void param_transform_multiply(Geom::Affine const &postmul, bool /*set*/); + void setUseDistance(bool use_knot_distance); + void setCurrentZoom(double current_zoom); + void setGlobalKnotHide(bool global_knot_hide); + void setEffectType(EffectType et); + void setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write = true); + void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + + friend class FilletChamferKnotHolderEntity; + friend class LPEFilletChamfer; + +protected: + KnotHolder *_knoth; + +private: + SatellitesArrayParam(const SatellitesArrayParam &); + SatellitesArrayParam &operator=(const SatellitesArrayParam &); + + SPKnotShapeType _knot_shape; + SPKnotModeType _knot_mode; + guint32 _knot_color; + Geom::PathVector _hp; + Geom::PathVector _knot_reset_helper; + int _helper_size; + bool _use_distance; + bool _global_knot_hide; + double _current_zoom; + EffectType _effectType; + PathVectorSatellites *_last_pathvector_satellites; + +}; + +class FilletChamferKnotHolderEntity : public KnotHolderEntity { +public: + FilletChamferKnotHolderEntity(SatellitesArrayParam *p, size_t index); + virtual ~FilletChamferKnotHolderEntity() + { + _pparam->_knoth = NULL; + } + + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, + guint state); + virtual Geom::Point knot_get() const; + virtual void knot_click(guint state); + void knot_set_offset(Satellite); + /** Checks whether the index falls within the size of the parameter's vector + */ + bool valid_index(size_t index,size_t subindex) const + { + return (_pparam->_vector.size() > index && _pparam->_vector[index].size() > subindex); + }; + +private: + SatellitesArrayParam *_pparam; + size_t _index; +}; + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp index 0baf15e6b..82c6035d4 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp @@ -43,7 +43,6 @@ FilletChamferPropertiesDialog::FilletChamferPropertiesDialog() //todo: get tha max aloable infinity freeze the widget _fillet_chamfer_position_numeric.set_range(0., SCALARPARAM_G_MAXDOUBLE); _fillet_chamfer_position_numeric.set_hexpand(); - _fillet_chamfer_position_label.set_label(_("Radius (pixels):")); _fillet_chamfer_position_label.set_alignment(1.0, 0.5); @@ -54,7 +53,6 @@ FilletChamferPropertiesDialog::FilletChamferPropertiesDialog() //todo: get tha max aloable infinity freeze the widget _fillet_chamfer_chamfer_subdivisions.set_range(0, SCALARPARAM_G_MAXDOUBLE); _fillet_chamfer_chamfer_subdivisions.set_hexpand(); - _fillet_chamfer_chamfer_subdivisions_label.set_label(_("Chamfer subdivisions:")); _fillet_chamfer_chamfer_subdivisions_label.set_alignment(1.0, 0.5); @@ -104,23 +102,26 @@ FilletChamferPropertiesDialog::FilletChamferPropertiesDialog() FilletChamferPropertiesDialog::~FilletChamferPropertiesDialog() { - _set_desktop(NULL); + _setDesktop(NULL); } void FilletChamferPropertiesDialog::showDialog( - SPDesktop *desktop, Geom::Point knotpoint, + SPDesktop *desktop, + double _amount, const Inkscape::LivePathEffect:: - FilletChamferPointArrayParamKnotHolderEntity *pt, - bool use_distance, - bool aprox_radius) + FilletChamferKnotHolderEntity *pt, + bool _use_distance, + bool _aprox_radius, + Satellite _satellite) { FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog(); - dialog->_set_desktop(desktop); - dialog->_set_use_distance(use_distance); - dialog->_set_aprox(aprox_radius); - dialog->_set_knot_point(knotpoint); - dialog->_set_pt(pt); + dialog->_setDesktop(desktop); + dialog->_setUseDistance(_use_distance); + dialog->_setAprox(_aprox_radius); + dialog->_setAmount(_amount); + dialog->_setSatellite(_satellite); + dialog->_setPt(pt); dialog->set_title(_("Modify Fillet-Chamfer")); dialog->_apply_button.set_label(_("_Modify")); @@ -135,34 +136,38 @@ void FilletChamferPropertiesDialog::showDialog( void FilletChamferPropertiesDialog::_apply() { - double d_width; + double d_pos = _fillet_chamfer_position_numeric.get_value(); - if (d_pos) { + if (d_pos >= 0) { if (_fillet_chamfer_type_fillet.get_active() == true) { - d_width = 1; + _satellite.satellite_type = FILLET; } else if (_fillet_chamfer_type_inverse_fillet.get_active() == true) { - d_width = 2; + _satellite.satellite_type = INVERSE_FILLET; } else if (_fillet_chamfer_type_inverse_chamfer.get_active() == true) { - d_width = _fillet_chamfer_chamfer_subdivisions.get_value() + 4000; + _satellite.satellite_type = INVERSE_CHAMFER; } else { - d_width = _fillet_chamfer_chamfer_subdivisions.get_value() + 3000; + _satellite.satellite_type = CHAMFER; } if (_flexible) { if (d_pos > 99.99999 || d_pos < 0) { d_pos = 0; } - d_pos = _index + (d_pos / 100); - } else { - d_pos = d_pos * -1; + d_pos = d_pos / 100; + } + _satellite.amount = d_pos; + size_t steps = (size_t)_fillet_chamfer_chamfer_subdivisions.get_value(); + if (steps < 1) { + steps = 1; } - _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width)); + _satellite.steps = steps; + _knotpoint->knot_set_offset(_satellite); } _close(); } void FilletChamferPropertiesDialog::_close() { - _set_desktop(NULL); + _setDesktop(NULL); destroy_(); Glib::signal_idle().connect( sigc::bind_return( @@ -184,62 +189,68 @@ void FilletChamferPropertiesDialog::_handleButtonEvent(GdkEventButton *event) } } -void FilletChamferPropertiesDialog::_set_knot_point(Geom::Point knotpoint) +void FilletChamferPropertiesDialog::_setSatellite(Satellite satellite) { double position; std::string distance_or_radius = std::string(_("Radius")); - if(aprox){ + if (_aprox) { distance_or_radius = std::string(_("Radius approximated")); } - if(use_distance){ + if (_use_distance) { distance_or_radius = std::string(_("Knot distance")); } - if (knotpoint.x() > 0) { - double intpart; - position = modf(knotpoint[Geom::X], &intpart) * 100; + if (satellite.is_time) { + position = _amount * 100; _flexible = true; - _index = intpart; _fillet_chamfer_position_label.set_label(_("Position (%):")); } else { _flexible = false; std::string posConcat = Glib::ustring::compose (_("%1:"), distance_or_radius); _fillet_chamfer_position_label.set_label(_(posConcat.c_str())); - position = knotpoint[Geom::X] * -1; + position = _amount; } _fillet_chamfer_position_numeric.set_value(position); - if (knotpoint.y() == 1) { + _fillet_chamfer_chamfer_subdivisions.set_value(satellite.steps); + if (satellite.satellite_type == FILLET) { _fillet_chamfer_type_fillet.set_active(true); - } else if (knotpoint.y() == 2) { + } else if (satellite.satellite_type == INVERSE_FILLET) { _fillet_chamfer_type_inverse_fillet.set_active(true); - } else if (knotpoint.y() >= 3000 && knotpoint.y() < 4000) { - _fillet_chamfer_chamfer_subdivisions.set_value(knotpoint.y() - 3000); + } else if (satellite.satellite_type == CHAMFER) { _fillet_chamfer_type_chamfer.set_active(true); - } else if (knotpoint.y() >= 4000 && knotpoint.y() < 5000) { - _fillet_chamfer_chamfer_subdivisions.set_value(knotpoint.y() - 4000); + } else if (satellite.satellite_type == INVERSE_CHAMFER) { _fillet_chamfer_type_inverse_chamfer.set_active(true); } + _satellite = satellite; } -void FilletChamferPropertiesDialog::_set_pt( +void FilletChamferPropertiesDialog::_setPt( const Inkscape::LivePathEffect:: - FilletChamferPointArrayParamKnotHolderEntity *pt) + FilletChamferKnotHolderEntity *pt) { _knotpoint = const_cast< - Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *>( + Inkscape::LivePathEffect::FilletChamferKnotHolderEntity *>( pt); } -void FilletChamferPropertiesDialog::_set_use_distance(bool use_knot_distance) + +void FilletChamferPropertiesDialog::_setAmount(double amount) +{ + _amount = amount; +} + + + +void FilletChamferPropertiesDialog::_setUseDistance(bool use_knot_distance) { - use_distance = use_knot_distance; + _use_distance = use_knot_distance; } -void FilletChamferPropertiesDialog::_set_aprox(bool aprox_radius) +void FilletChamferPropertiesDialog::_setAprox(bool _aprox_radius) { - aprox = aprox_radius; + _aprox = _aprox_radius; } -void FilletChamferPropertiesDialog::_set_desktop(SPDesktop *desktop) +void FilletChamferPropertiesDialog::_setDesktop(SPDesktop *desktop) { if (desktop) { Inkscape::GC::anchor(desktop); diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.h b/src/ui/dialog/lpe-fillet-chamfer-properties.h index c74e3f011..4021d6152 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.h +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.h @@ -10,7 +10,7 @@ #include <2geom/point.h> #include <gtkmm.h> -#include "live_effects/parameter/filletchamferpointarray.h" +#include "live_effects/parameter/satellitesarray.h" class SPDesktop; @@ -23,20 +23,22 @@ public: FilletChamferPropertiesDialog(); virtual ~FilletChamferPropertiesDialog(); - Glib::ustring getName() const { + Glib::ustring getName() const + { return "LayerPropertiesDialog"; } - static void showDialog(SPDesktop *desktop, Geom::Point knotpoint, + static void showDialog(SPDesktop *desktop, double _amount, const Inkscape::LivePathEffect:: - FilletChamferPointArrayParamKnotHolderEntity *pt, - bool use_distance, - bool aprox_radius); + FilletChamferKnotHolderEntity *pt, + bool _use_distance, + bool _aprox_radius, + Satellite _satellite); protected: SPDesktop *_desktop; - Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity * + Inkscape::LivePathEffect::FilletChamferKnotHolderEntity * _knotpoint; Gtk::Label _fillet_chamfer_position_label; @@ -51,36 +53,40 @@ protected: Gtk::Grid _layout_table; bool _position_visible; - double _index; Gtk::Button _close_button; Gtk::Button _apply_button; sigc::connection _destroy_connection; - static FilletChamferPropertiesDialog &_instance() { + static FilletChamferPropertiesDialog &_instance() + { static FilletChamferPropertiesDialog instance; return instance; } - void _set_desktop(SPDesktop *desktop); - void _set_pt(const Inkscape::LivePathEffect:: - FilletChamferPointArrayParamKnotHolderEntity *pt); - void _set_use_distance(bool use_knot_distance); - void _set_aprox(bool aprox_radius); - void _apply(); - void _close(); - bool _flexible; - bool use_distance; - bool aprox; - void _set_knot_point(Geom::Point knotpoint); + void _setDesktop(SPDesktop *desktop); + void _setPt(const Inkscape::LivePathEffect:: + FilletChamferKnotHolderEntity *pt); + void _setUseDistance(bool use_knot_distance); + void _setAprox(bool aprox_radius); + void _setAmount(double amount); + void _setSatellite(Satellite satellite); void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row); bool _handleKeyEvent(GdkEventKey *event); void _handleButtonEvent(GdkEventButton *event); + void _apply(); + void _close(); + bool _flexible; + Satellite _satellite; + bool _use_distance; + double _amount; + bool _aprox; + friend class Inkscape::LivePathEffect:: - FilletChamferPointArrayParamKnotHolderEntity; + FilletChamferKnotHolderEntity; private: FilletChamferPropertiesDialog( diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 5746a8f86..f2899dd01 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -12,7 +12,6 @@ #include "live_effects/lpe-powerstroke.h" #include "live_effects/lpe-bspline.h" -#include "live_effects/lpe-fillet-chamfer.h" #include <2geom/bezier-utils.h> #include <2geom/path-sink.h> #include "ui/tool/path-manipulator.h" @@ -1364,13 +1363,6 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE) lpe_pwr->adjustForNewPath(pathv); } } - this_effect = _path->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER); - if(this_effect){ - LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(this_effect->getLPEObj()->get_lpe()); - if (lpe_fll) { - lpe_fll->adjustForNewPath(pathv); - } - } } } |
