diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2015-02-08 15:40:25 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2015-02-08 15:40:25 +0000 |
| commit | 86891a9e442c81435c6d197cb09b3dc210643bc0 (patch) | |
| tree | 4952411fd6e526907d4241e8965e93c4f185500a /src | |
| parent | refactor of pointwise base (diff) | |
| download | inkscape-86891a9e442c81435c6d197cb09b3dc210643bc0.tar.gz inkscape-86891a9e442c81435c6d197cb09b3dc210643bc0.zip | |
starting whith pointwise
(bzr r13645.1.7)
Diffstat (limited to 'src')
| -rw-r--r-- | src/2geom/Makefile_insert | 3 | ||||
| -rw-r--r-- | src/2geom/pointwise.cpp | 6 | ||||
| -rw-r--r-- | src/2geom/pointwise.h | 16 | ||||
| -rw-r--r-- | src/2geom/satellite-enum.h | 2 | ||||
| -rw-r--r-- | src/2geom/satellite.h | 28 | ||||
| -rw-r--r-- | src/live_effects/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/live_effects/lpe-fillet-chamfer.cpp | 585 | ||||
| -rw-r--r-- | src/live_effects/lpe-fillet-chamfer.h | 41 | ||||
| -rw-r--r-- | src/live_effects/parameter/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/live_effects/parameter/array.cpp | 32 | ||||
| -rw-r--r-- | src/live_effects/parameter/array.h | 9 | ||||
| -rw-r--r-- | src/live_effects/parameter/pointwise.cpp | 104 | ||||
| -rw-r--r-- | src/live_effects/parameter/pointwise.h | 88 |
13 files changed, 295 insertions, 623 deletions
diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index e77f413cb..2f23bc442 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -80,6 +80,8 @@ 2geom/point.cpp \ 2geom/point.h \ 2geom/point-ops.h \ + 2geom/pointwise.cpp \ + 2geom/pointwise.h \ 2geom/poly.cpp \ 2geom/poly.h \ 2geom/quadtree.cpp \ @@ -90,6 +92,7 @@ 2geom/recursive-bezier-intersection.cpp \ 2geom/region.cpp \ 2geom/region.h \ + 2geom/satellite.h \ 2geom/sbasis-2d.cpp \ 2geom/sbasis-2d.h \ 2geom/sbasis.cpp \ diff --git a/src/2geom/pointwise.cpp b/src/2geom/pointwise.cpp index ce3aa86f6..cd7f7914f 100644 --- a/src/2geom/pointwise.cpp +++ b/src/2geom/pointwise.cpp @@ -1,6 +1,8 @@ /* - * pointwise.cpp - Pointwise function class - * + * pointwise.cpp + * Authors: + * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es> + * Copyright 2015 authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public diff --git a/src/2geom/pointwise.h b/src/2geom/pointwise.h index 33289f4f0..c0974f54c 100644 --- a/src/2geom/pointwise.h +++ b/src/2geom/pointwise.h @@ -3,10 +3,20 @@ * \brief Pointwise *//* * Authors: + * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es> + * Copyright 2015 authors * - * Copyright 2014 authors - * - * + * Pointwise maintains a set of "Satellite" positions along a curve/pathvector. + * The positions are specified as arc length distances along the curve or by + * time in the curve. Splicing operations automatically update the satellite + * positions to preserve the intent. + * The data is serialised to SVG using a specialiced pointwise LPE parameter to + * handle it in th future can be a inkscape based property to paths + * //all operations are O(1) per satellite, with the exception of .., .., and .., which + * //need to use binary search to find the locations. + * Anywhere a Piecewise is used, a Pointwise can be substituted, allowing + * existing algorithms to correctly update satellite positions. + * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation diff --git a/src/2geom/satellite-enum.h b/src/2geom/satellite-enum.h index 3872cf718..a71306bc9 100644 --- a/src/2geom/satellite-enum.h +++ b/src/2geom/satellite-enum.h @@ -20,7 +20,7 @@ enum SatelliteType { INVERSE_CHAMFER, INVALID_SATELLITE // This must be last (I made it such that it is not needed anymore I think..., Don't trust on it being last. - johan) }; - +std::map<gchar const *value, SatelliteType> SatelliteTypeMap = boost::map_list_of("FILLET", FILLET)("INVERSE_FILLET", INVERSE_FILLET)("CHAMFER",CHAMFER)("INVERSE_CHAMFER",INVERSE_CHAMFER)("INVALID_SATELLITE",INVALID_SATELLITE); extern const Util::EnumData<SatelliteType> SATELLITETypeData[]; /// defined in satelite.cpp extern const Util::EnumDataConverter<SateliteType> SATELLITETypeConverter; /// defined in sattelite.cpp diff --git a/src/2geom/satellite.h b/src/2geom/satellite.h index 8e570db4c..a18b08f27 100644 --- a/src/2geom/satellite.h +++ b/src/2geom/satellite.h @@ -3,8 +3,8 @@ * \brief Satellite *//* * Authors: - * - * Copyright 2014 authors + * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es> + * Copyright 2015 authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -129,16 +129,30 @@ class Satellite return _time; } - double toTime(double A,D2<SBasis> curve) const + double time(D2<SBasis> curve) const { //todo make the process return _time; } - double toSize(double A,D2<SBasis> curve) const - { - //todo make the process - return _size; + void setPosition(Geom::Point p, D2<SBasis> curve){ + _time = Geom::nearestPoint(p, curve); + if(!_isTime){ + if (curve.degreesOfFreedom() != 2) { + Piecewise<D2<SBasis> > u; + u.push_cut(0); + u.push(curve, 1); + u = portion(u, 0, _time); + _size = length(u, 0.001) * -1; + } else { + lenghtPart = length(last_pwd2[index], EPSILON); + _size = (time * lenghtPart) * -1; + } + } + } + + Geom::Point getPosition(D2<SBasis> curve){ + return curve.pointAt(_time); } bool isDegenerate() const diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index c8a02c810..e171e99e3 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -63,6 +63,7 @@ set(live_effects_SRC parameter/path-reference.cpp parameter/point.cpp parameter/powerstrokepointarray.cpp + parameter/pointwise.cpp parameter/random.cpp parameter/text.cpp paramter/transformedpoint.cpp @@ -139,6 +140,7 @@ set(live_effects_SRC parameter/originalpatharray.h parameter/point.h parameter/powerstrokepointarray.h + parameter/pointwise.h parameter/random.h parameter/text.h parameter/togglebutton.h diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index d2bdf2d8d..f4eb4f46e 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -13,23 +13,8 @@ * * 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/svg-elliptical-arc.h> -#include <2geom/line.h> -#include "desktop.h" -#include "display/curve.h" -#include "helper/geom-nodetype.h" -#include "helper/geom-curves.h" -#include "helper/geom.h" - -#include "live_effects/parameter/filletchamferpointarray.h" - -// for programmatically updating knots -#include "ui/tools-switch.h" -#include <util/units.h> +#include "live_effects/parameter/pointwise.h" // TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> @@ -38,348 +23,23 @@ using namespace Geom; namespace Inkscape { namespace LivePathEffect { -static const Util::EnumData<FilletMethod> FilletMethodData[FM_END] = { - { 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), - unit(_("Unit:"), _("Unit"), "unit", &wr, this), - 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) + pointwise_values(_("Fillet point"), _("Fillet point"), "pointwise_values", &wr, this) { - registerParameter(&fillet_chamfer_values); - registerParameter(&unit); - registerParameter(&method); - registerParameter(&radius); - registerParameter(&chamfer_steps); - registerParameter(&helper_size); - registerParameter(&flexible); - registerParameter(&use_knot_distance); - registerParameter(&ignore_radius_0); - registerParameter(&only_selected); - registerParameter(&hide_knots); - - radius.param_set_range(0., infinity()); - radius.param_set_increments(1, 1); - radius.param_set_digits(4); - chamfer_steps.param_set_range(1, 999); - chamfer_steps.param_set_increments(1, 1); - chamfer_steps.param_set_digits(0); - helper_size.param_set_range(0, infinity()); - helper_size.param_set_increments(5, 5); - helper_size.param_set_digits(0); - fillet_chamfer_values.set_chamfer_steps(3); + registerParameter(&pointwise_values); } LPEFilletChamfer::~LPEFilletChamfer() {} -Gtk::Widget *LPEFilletChamfer::newWidget() -{ - // use manage here, because after deletion of Effect object, others might - // still be pointing to this widget. - Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget())); - - vbox->set_border_width(5); - vbox->set_homogeneous(false); - vbox->set_spacing(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; - 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); - } - } 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; - 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); - } - } 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)); - } 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); - if (tip) { - widg->set_tooltip_text(*tip); - } else { - widg->set_tooltip_text(""); - widg->set_has_tooltip(false); - } - } - } - - ++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::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer")))); - chamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::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); - - vbox->pack_start(*filletContainer, true, true, 2); - vbox->pack_start(*chamferContainer, 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() -{ - 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); - } - fillet_chamfer_values.param_set_and_write_new_value(result); -} - -void LPEFilletChamfer::updateFillet() -{ - double power = 0; - if (!flexible) { - power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), *defaultUnit) * -1; - } else { - power = radius; - } - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doUpdateFillet(path_from_piecewise(pwd2, tolerance), power); -} - -void LPEFilletChamfer::fillet() -{ - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), 1); -} - -void LPEFilletChamfer::inverseFillet() -{ - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), 2); -} - -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); -} - -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); -} - -void LPEFilletChamfer::inverseChamfer() -{ - 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); -} - -void LPEFilletChamfer::refreshKnots() -{ - 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); - } -} - -void LPEFilletChamfer::doUpdateFillet(std::vector<Geom::Path> const& original_pathv, double power) -{ - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - std::vector<Geom::Point> result; - std::vector<Geom::Path> 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]; - } - result.push_back(Point(powerend, filletChamferData[counter][Y])); - ++curve_it1; - ++curve_it2; - counter++; - } - } - fillet_chamfer_values.param_set_and_write_new_value(result); -} - -void LPEFilletChamfer::doChangeType(std::vector<Geom::Path> const& original_pathv, int type) -{ - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - std::vector<Geom::Point> result; - std::vector<Geom::Path> 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(); - } - } - 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 (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); + SPShape * shape = dynamic_cast<SPshape *>(lpeItem); + if (shape) { + std::vector<std::pair<int,GeomSatellite> pointwise; + PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(shape->gerCurve->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; @@ -401,25 +61,16 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) } 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::Saltellite sat(FILLET, true, true, false, false, false, 0, 0.2); + std::pair<std::size_t, std::size_t> positions = pointwise_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); - } else { - nodetype = NODE_NONE; - } + nodetype = NODE_NONE; } 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)); + pointwise.push_back(std::pair<counter,sat>); } ++curve_it1; if (curve_it2 != curve_endit) { @@ -428,222 +79,14 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) counter++; } } - fillet_chamfer_values.param_set_and_write_new_value(point); + pointwise_values.param_set_and_write_new_value(pointwise); } else { - g_warning("LPE Fillet can only be applied to shapes (not groups)."); + g_warning("LPE Fillet/Chamfer 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_document_unit(defaultUnit); - fillet_chamfer_values.set_use_distance(use_knot_distance); - fillet_chamfer_values.set_unit(unit.get_abbreviation()); - 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); - } - } else { - g_warning("LPE Fillet can only be applied to shapes (not groups)."); - } -} - -int LPEFilletChamfer::getKnotsNumber(SPCurve const *c) -{ - int nKnots = c->nodes_in_path(); - PathVector const pv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); - for (std::vector<Geom::Path>::const_iterator path_it = pv.begin(); - path_it != pv.end(); ++path_it) { - if (!(*path_it).closed()) { - nKnots--; - } - } - return nKnots; -} - -void -LPEFilletChamfer::adjustForNewPath(std::vector<Geom::Path> const &path_in) -{ - if (!path_in.empty()) { - fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb()); - } -} - -std::vector<Geom::Path> -LPEFilletChamfer::doEffect_path(std::vector<Geom::Path> const &path_in) -{ - std::vector<Geom::Path> 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 K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); - std::vector<Geom::Path> 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()) - 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(); - } - 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()); - } else { - path_out.start((*curve_it1).pointAt(times[0])); - } - 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); - } - 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]); - } - 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; - } - Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint; - handleAngle = ray2.angle() + angle; - if (ccwToggle) { - handleAngle = ray2.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<SVGEllipticalArc>(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); - } - 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<SVGEllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - }else{ - path_chamfer.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, 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); - } - 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<SVGEllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - }else{ - path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint); - } - } else if (type == 1){ - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - path_out.appendNew<SVGEllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - } else { - path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint); - } - } - } else { - path_out.append(*knotCurve1); - } - if (path_it->closed() && last) { - path_out.close(); - } - ++curve_it1; - if (curve_it2 != curve_endit) { - ++curve_it2; - } - counter++; - counterCurves++; - } - pathvector_out.push_back(path_out); - } - return pathvector_out; -} }; //namespace LivePathEffect }; /* namespace Inkscape */ diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 0d6a1ff17..f4462d154 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -27,58 +27,23 @@ #include "live_effects/parameter/bool.h" #include "live_effects/parameter/unit.h" -#include "live_effects/parameter/filletchamferpointarray.h" +#include "live_effects/parameter/pointwise.h" #include "live_effects/effect.h" namespace Inkscape { namespace LivePathEffect { -enum FilletMethod { - FM_AUTO, - FM_ARC, - FM_BEZIER, - FM_END -}; class LPEFilletChamfer : public Effect { public: LPEFilletChamfer(LivePathEffectObject *lpeobject); virtual ~LPEFilletChamfer(); - virtual std::vector<Geom::Path> doEffect_path(std::vector<Geom::Path> const &path_in); - virtual void doOnApply(SPLPEItem const *lpeItem); - virtual void doBeforeEffect(SPLPEItem const *lpeItem); - virtual void adjustForNewPath(std::vector<Geom::Path> 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(std::vector<Geom::Path> const& original_pathv, double power); - void doChangeType(std::vector<Geom::Path> const& original_pathv, int type); - void refreshKnots(); - - FilletChamferPointArrayParam fillet_chamfer_values; -private: + PointwiseArrayParam pointwise_values; - BoolParam hide_knots; - BoolParam ignore_radius_0; - BoolParam only_selected; - BoolParam flexible; - BoolParam use_knot_distance; - UnitParam unit; - EnumParam<FilletMethod> method; - ScalarParam radius; - ScalarParam chamfer_steps; - ScalarParam helper_size; +private: LPEFilletChamfer(const LPEFilletChamfer &); LPEFilletChamfer &operator=(const LPEFilletChamfer &); diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert index f990f41c7..d78b1e22f 100644 --- a/src/live_effects/parameter/Makefile_insert +++ b/src/live_effects/parameter/Makefile_insert @@ -26,6 +26,8 @@ ink_common_sources += \ live_effects/parameter/powerstrokepointarray.h \ live_effects/parameter/filletchamferpointarray.cpp \ live_effects/parameter/filletchamferpointarray.h \ + live_effects/parameter/pointwise.cpp \ + live_effects/parameter/pointwise.h \ live_effects/parameter/text.cpp \ live_effects/parameter/text.h \ live_effects/parameter/transformedpoint.cpp \ diff --git a/src/live_effects/parameter/array.cpp b/src/live_effects/parameter/array.cpp index 1b8f742da..bd2bf1870 100644 --- a/src/live_effects/parameter/array.cpp +++ b/src/live_effects/parameter/array.cpp @@ -48,6 +48,38 @@ ArrayParam<Geom::Point>::readsvg(const gchar * str) } return Geom::Point(Geom::infinity(),Geom::infinity()); } +void +sp_svg_satellite_read_d(gchar const *str, satellite *sat){ + gchar ** strarray = g_strsplit(str, "*", 0); + if(strarray.size() != 6){ + g_strfreev (strarray); + return NULL; + } + sat->setSatelliteType(SatelliteTypeMap[strarray[0]]); + sat->setActive(helperfns_read_bool(strarray[1], true)); + sat->sethasMirror(helperfns_read_bool(strarray[2], false)); + sat->setHidden(helperfns_read_bool(strarray[3], false)); + sat->setHidden(helperfns_read_bool(strarray[3], false)); + sat->setTime(sp_svg_number_read_d(strarray[4], 0.0)); + sat->setSize(sp_svg_number_read_d(strarray[5], 0.0)); + g_strfreev (strarray); +} + +template <> +std::pair<int, satellite> +ArrayParam<Geom::Point>::readsvg(const gchar * str) +{ + gchar ** strarray = g_strsplit(str, ",", 2); + int index; + Geom::satellite sat = NULL; + unsigned int success = sp_svg_number_read_d(strarray[0], &index); + success += sp_svg_satellite_read_d(strarray[1], &sat); + g_strfreev (strarray); + if (success == 2) { + return std::pair<index, sat>; + } + return std::pair<Geom::infinity(),NULL>; +} } /* namespace LivePathEffect */ diff --git a/src/live_effects/parameter/array.h b/src/live_effects/parameter/array.h index a600f0257..b93c7a617 100644 --- a/src/live_effects/parameter/array.h +++ b/src/live_effects/parameter/array.h @@ -93,7 +93,14 @@ protected: // separate items with pipe symbol str << " | "; } - str << vector[i]; + std::pair<int,Geom::satellite> pointwiseElement = dynamic_cast<std::pair<int,Geom::satellite> ><(_vector[i]); + if(pointwiseElement){ + str << vector[i].first; + str << " , "; + str << vector[i].second; + } else { + str << vector[i]; + } } } diff --git a/src/live_effects/parameter/pointwise.cpp b/src/live_effects/parameter/pointwise.cpp new file mode 100644 index 000000000..ec83eb6c7 --- /dev/null +++ b/src/live_effects/parameter/pointwise.cpp @@ -0,0 +1,104 @@ +/* + * 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 "knotholder.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 { + +PointwiseParam::PointwiseParam( + const Glib::ustring &label, const Glib::ustring &tip, + const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr, + Effect *effect) + : ArrayParam<Pointwise>(label, tip, key, wr, effect, 0) +{ + knot_shape = SP_KNOT_SHAPE_DIAMOND; + knot_mode = SP_KNOT_MODE_XOR; + knot_color = 0x00ff0000; +} + +PointwiseParam::~PointwiseParam() {} + +Gtk::Widget *PointwiseParam::param_newWidget() +{ + return NULL; +} + +void PointwiseParam::set_oncanvas_looks(SPKnotShapeType shape, + SPKnotModeType mode, + guint32 color) +{ + knot_shape = shape; + knot_mode = mode; + knot_color = color; +} + +PointwiseParamKnotHolderEntity:: +PointwiseParamKnotHolderEntity( + PointwiseParam *p) + : _pparam(p) {} + +void PointwiseParamKnotHolderEntity::knot_set(Point const &p, + Point const &/*origin*/, + guint state) +{ + Geom::Point const s = snap_knot_position(p, state); + _pparam->_vector.at(_index).second.setPosition(s,_pparam->_pointwise.pwd2[_pparam->_vector.at(_index).first]); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); +} + +Point PointwiseParamKnotHolderEntity::knot_get() const +{ + Geom::Point const canvas_point = _pparam->_vector.at(_index).second.getPosition(_pparam->_pointwise.pwd2[_pparam->_vector.at(_index).first]); + _pparam->updateCanvasIndicators(); + return canvas_point; +} + + +void PointwiseParam::addKnotHolderEntities(KnotHolder *knotholder, + SPDesktop *desktop, + SPItem *item) +{ + for (unsigned int i = 0; i < _pointwise.satellites.size(); ++i) { + const gchar *tip; + tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> reset"); + PointwiseParamKnotHolderEntity *e = + new PointwiseParamKnotHolderEntity(this, i); + e->create(desktop, 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/pointwise.h b/src/live_effects/parameter/pointwise.h new file mode 100644 index 000000000..59f1b4ff4 --- /dev/null +++ b/src/live_effects/parameter/pointwise.h @@ -0,0 +1,88 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_POINTWISE_H +#define INKSCAPE_LIVEPATHEFFECT_POINTWISE_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 pointwise class to serialize it as a LPE + * parameter + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <glib.h> +#include "knot-holder-entity.h" + +namespace Inkscape { + +namespace LivePathEffect { + +class PointwiseParamKnotHolderEntity; + +class PointwiseParam : public ArrayParam<Geom::Pointwise> { +public: + PointwiseParam(const Glib::ustring &label, + const Glib::ustring &tip, + const Glib::ustring &key, + Inkscape::UI::Widget::Registry *wr, + Effect *effect); + virtual ~PointwiseParam(); + + virtual Gtk::Widget * param_newWidget() { + return NULL; + } + + void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, + guint32 color); + virtual bool providesKnotHolderEntities() const { + return true; + } + friend class PointwiseParamKnotHolderEntity; + +protected: + + StorageType readsvg(const gchar * str); + +private: + PointwiseParam(const PointwiseParam &); + PointwiseParam &operator=(const PointwiseParam &); + + SPKnotShapeType knot_shape; + SPKnotModeType knot_mode; + guint32 knot_color; +}; + +class PointwiseParamKnotHolderEntity : public KnotHolderEntity { +public: + PointwiseParamKnotHolderEntity(PointwiseParam *p, + unsigned int index); + virtual ~PointwiseParamKnotHolderEntity() {} + + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, + guint state); + virtual Geom::Point knot_get() const; + + /*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: + PointwiseParam *_pparam; + unsigned int _index; +}; + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif |
