diff --git a/CMakeScripts/InstallMSYS2.cmake b/CMakeScripts/InstallMSYS2.cmake
index aac4fd6482333927978206c4df018a895a99aa00..c8c580fe4ecdd35e7c0985aa914a891d6f15b653 100644
--- a/CMakeScripts/InstallMSYS2.cmake
+++ b/CMakeScripts/InstallMSYS2.cmake
@@ -166,7 +166,20 @@ if(WIN32)
install(DIRECTORY ${MINGW_PATH}/share/glib-2.0/schemas
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/glib-2.0)
+ # fontconfig
install(DIRECTORY ${MINGW_PATH}/etc/fonts
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/etc
+ FILES_MATCHING PATTERN "fonts.conf" EXCLUDE)
+ # adjust fonts.conf to store font cache in AppData
+ set(cachedir_default "\\t^/var/cache/fontconfig^") # the '^' are needed to escape angle brackets on Windows command shell
+ set(cachedir_appdata "\\t^LOCAL_APPDATA_FONTCONFIG_CACHE^")
+ add_custom_command(
+ OUTPUT ${CMAKE_BINARY_DIR}/etc/fonts/fonts.conf
+ COMMAND sed 's!${cachedir_default}!${cachedir_appdata}\\n${cachedir_default}!' ${MINGW_PATH}/etc/fonts/fonts.conf > ${CMAKE_BINARY_DIR}/etc/fonts/fonts.conf
+ MAIN_DEPENDENCY ${MINGW_PATH}/etc/fonts/fonts.conf
+ )
+ add_custom_target(fonts_conf ALL DEPENDS ${CMAKE_BINARY_DIR}/etc/fonts/fonts.conf)
+ install(DIRECTORY ${CMAKE_BINARY_DIR}/etc/fonts
DESTINATION ${CMAKE_INSTALL_PREFIX}/etc)
# GTK 3.0
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b998cf29462a1afd63f2dc44af1e22281044161f..fce7e385e3837d5995497f74fe39ef02fef82883 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -153,7 +153,7 @@ src/live_effects/lpe-transform_2pts.cpp
src/live_effects/lpe-vonkoch.cpp
src/live_effects/parameter/bool.cpp
src/live_effects/parameter/enum.h
-src/live_effects/parameter/filletchamferpointarray.cpp
+src/live_effects/parameter/satellitearray.cpp
src/live_effects/parameter/fontbutton.cpp
src/live_effects/parameter/originalpath.cpp
src/live_effects/parameter/originalpatharray.cpp
diff --git a/src/helper/CMakeLists.txt b/src/helper/CMakeLists.txt
index ff4760c24715088c9ffdb4c049928669e8331d88..92709e4e94426327ee03bb479a208ec8bb181a9c 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 0000000000000000000000000000000000000000..e995c0a9b47291507ea5f8e27ef0c6182ffe905f
--- /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
+#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 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 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 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 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 0000000000000000000000000000000000000000..d86e6cb25bcfc36df5d934686d2b43d08c7531ff
--- /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
+#include <2geom/path.h>
+#include <2geom/pathvector.h>
+
+typedef std::vector > 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 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 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 0000000000000000000000000000000000000000..8a92273d0d4acd0560861a6837e1fa27e03cca93
--- /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
+ *
+ * This code is in public domain
+ */
+
+#include
+#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
+//log cache
+#ifdef _WIN32
+#include
+#else
+#include
+#include
+#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 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 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 d2_in = curve_in.toSBasis();
+ Geom::D2 d2_out = curve_out.toSBasis();
+ Geom::Piecewise > offset_curve0 =
+ Geom::Piecewise >(d2_in) +
+ rot90(unitVector(derivative(d2_in))) * (A);
+ Geom::Piecewise > offset_curve1 =
+ Geom::Piecewise >(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(&*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(&*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(&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 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::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 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 0000000000000000000000000000000000000000..a4d63d66e6bb7849439596dd2384a5fcc19f6990
--- /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
+ *
+ * This code is in public domain
+ */
+
+#ifndef SEEN_SATELLITE_H
+#define SEEN_SATELLITE_H
+
+#include