summaryrefslogtreecommitdiffstats
path: root/src/live_effects/parameter
diff options
context:
space:
mode:
authorJabiertxof <jtx@jtx>2017-05-06 18:07:14 +0000
committerJabiertxof <jtx@jtx>2017-05-06 18:07:14 +0000
commitcb39bc5cd6fbecf0f045d58f30dd4288c590a46a (patch)
tree9fbb940c15170a68e284dd8ca4a09f84eb8c311d /src/live_effects/parameter
parentLPE widget refactor. Improvement to not update on same value (diff)
parentPre merge fixing (diff)
downloadinkscape-cb39bc5cd6fbecf0f045d58f30dd4288c590a46a.tar.gz
inkscape-cb39bc5cd6fbecf0f045d58f30dd4288c590a46a.zip
Merge pathVectorSatellites
(bzr r15666)
Diffstat (limited to 'src/live_effects/parameter')
-rw-r--r--src/live_effects/parameter/array.cpp44
-rw-r--r--src/live_effects/parameter/array.h39
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.cpp873
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.h123
-rw-r--r--src/live_effects/parameter/satellitesarray.cpp583
-rw-r--r--src/live_effects/parameter/satellitesarray.h114
6 files changed, 775 insertions, 1001 deletions
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