summaryrefslogtreecommitdiffstats
path: root/src/live_effects/lpe-show_handles.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/live_effects/lpe-show_handles.cpp')
-rw-r--r--src/live_effects/lpe-show_handles.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/live_effects/lpe-show_handles.cpp b/src/live_effects/lpe-show_handles.cpp
new file mode 100644
index 0000000..c40f075
--- /dev/null
+++ b/src/live_effects/lpe-show_handles.cpp
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Authors:
+ * Jabier Arraiza Cenoz
+ *
+ * Copyright (C) Jabier Arraiza Cenoz 2014 <jabier.arraiza@marker.es>
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <gtkmm.h>
+#include "live_effects/lpe-show_handles.h"
+#include <2geom/sbasis-to-bezier.h>
+#include <2geom/svg-path-parser.h>
+#include "helper/geom.h"
+#include "desktop-style.h"
+#include "display/curve.h"
+#include "svg/svg.h"
+
+#include "object/sp-shape.h"
+#include "style.h"
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+LPEShowHandles::LPEShowHandles(LivePathEffectObject *lpeobject)
+ : Effect(lpeobject),
+ nodes(_("Show nodes"), _("Show nodes"), "nodes", &wr, this, true),
+ handles(_("Show handles"), _("Show handles"), "handles", &wr, this, true),
+ original_path(_("Show path"), _("Show path"), "original_path", &wr, this, true),
+ show_center_node(_("Show center of node"), _("Show center of node"), "show_center_node", &wr, this, false),
+ original_d(_("Show original"), _("Show original"), "original_d", &wr, this, false),
+ scale_nodes_and_handles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scale_nodes_and_handles", &wr, this, 10)
+{
+ registerParameter(&nodes);
+ registerParameter(&handles);
+ registerParameter(&original_path);
+ registerParameter(&show_center_node);
+ registerParameter(&original_d);
+ registerParameter(&scale_nodes_and_handles);
+ scale_nodes_and_handles.param_set_range(0, 500.);
+ scale_nodes_and_handles.param_set_increments(1, 1);
+ scale_nodes_and_handles.param_set_digits(2);
+ stroke_width = 1.0;
+}
+
+bool LPEShowHandles::alerts_off = false;
+
+/**
+ * Sets default styles to element
+ * this permanently remove.some styles of the element
+ */
+
+void LPEShowHandles::doOnApply(SPLPEItem const* lpeitem)
+{
+ if(!alerts_off) {
+ char *msg = _("The \"show handles\" path effect will remove any custom style on the object you are applying it to. If this is not what you want, click Cancel.");
+ Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
+ gint response = dialog.run();
+ alerts_off = true;
+ if(response == GTK_RESPONSE_CANCEL) {
+ SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem);
+ item->removeCurrentPathEffect(false);
+ return;
+ }
+ }
+ SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem);
+ SPCSSAttr *css = sp_repr_css_attr_new ();
+ sp_repr_css_set_property (css, "stroke", "black");
+ sp_repr_css_set_property (css, "stroke-width", "1");
+ sp_repr_css_set_property (css, "stroke-linecap", "butt");
+ sp_repr_css_set_property(css, "fill", "none");
+
+ sp_desktop_apply_css_recursive(item, css, true);
+ sp_repr_css_attr_unref (css);
+}
+
+void LPEShowHandles::doBeforeEffect (SPLPEItem const* lpeitem)
+{
+ SPItem const* item = SP_ITEM(lpeitem);
+ stroke_width = item->style->stroke_width.computed;
+}
+
+Geom::PathVector LPEShowHandles::doEffect_path (Geom::PathVector const & path_in)
+{
+ Geom::PathVector path_out;
+ Geom::PathVector original_pathv = pathv_to_linear_and_cubic_beziers(path_in);
+ if(original_path) {
+ for (const auto & i : path_in) {
+ path_out.push_back(i);
+ }
+ }
+ if(!outline_path.empty()) {
+ outline_path.clear();
+ }
+ if (original_d) {
+ SPCurve * shape_curve = current_shape->getCurveForEdit();
+ if (shape_curve) {
+ Geom::PathVector original_curve = shape_curve->get_pathvector();
+ if(original_path) {
+ for (const auto & i : original_curve) {
+ path_out.push_back(i);
+ }
+ }
+ original_pathv.insert(original_pathv.end(), original_curve.begin(), original_curve.end());
+ }
+ generateHelperPath(original_pathv);
+ shape_curve->unref();
+ } else {
+ generateHelperPath(original_pathv);
+ }
+ for (const auto & i : outline_path) {
+ path_out.push_back(i);
+ }
+
+ return path_out;
+}
+
+void
+LPEShowHandles::generateHelperPath(Geom::PathVector result)
+{
+ if(!handles && !nodes) {
+ return;
+ }
+
+ Geom::CubicBezier const *cubic = nullptr;
+ for (auto & path_it : result) {
+ //Si está vacío...
+ if (path_it.empty()) {
+ continue;
+ }
+ //Itreadores
+ Geom::Path::iterator curve_it1 = path_it.begin(); // incoming curve
+ Geom::Path::iterator curve_it2 = ++(path_it.begin()); // outgoing curve
+ Geom::Path::iterator curve_endit = path_it.end_default(); // this determines when the loop has to stop
+
+ if (path_it.closed()) {
+ // if the path is closed, maybe we have to stop a bit earlier because the
+ // closing line segment has zerolength.
+ Geom::Curve const &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();
+ }
+ }
+ if(nodes) {
+ Geom::NodeType nodetype = Geom::NODE_CUSP;
+ if(path_it.closed()) {
+ nodetype = Geom::get_nodetype(path_it.finalCurve(), *curve_it1);
+ }
+ drawNode(curve_it1->initialPoint(), nodetype);
+ }
+ while (curve_it1 != curve_endit) {
+ cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
+ if (cubic) {
+ if(handles) {
+ if(!are_near((*cubic)[0],(*cubic)[1])) {
+ drawHandle((*cubic)[1]);
+ drawHandleLine((*cubic)[0],(*cubic)[1]);
+ }
+ if(!are_near((*cubic)[3],(*cubic)[2])) {
+ drawHandle((*cubic)[2]);
+ drawHandleLine((*cubic)[3],(*cubic)[2]);
+ }
+ }
+ }
+ if(nodes && (curve_it2 != curve_endit || !path_it.closed())) {
+ Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
+ drawNode(curve_it1->finalPoint(), nodetype);
+ }
+ ++curve_it1;
+ if(curve_it2 != curve_endit) {
+ ++curve_it2;
+ }
+ }
+ }
+}
+
+void
+LPEShowHandles::drawNode(Geom::Point p, Geom::NodeType nodetype)
+{
+ if(stroke_width * scale_nodes_and_handles > 0.0) {
+ Geom::Rotate rotate = Geom::Rotate(0);
+ if ( nodetype == Geom::NODE_CUSP) {
+ rotate = Geom::Rotate::from_degrees(45);
+ }
+ double diameter = stroke_width * scale_nodes_and_handles;
+ char const * svgd;
+ if (show_center_node) {
+ svgd = "M 0.05,0 A 0.05,0.05 0 0 1 0,0.05 0.05,0.05 0 0 1 -0.05,0 0.05,0.05 0 0 1 0,-0.05 0.05,0.05 0 0 1 0.05,0 Z M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z";
+ } else {
+ svgd = "M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z";
+ }
+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
+ pathv *= rotate * Geom::Scale(diameter) * Geom::Translate(p);
+ outline_path.push_back(pathv[0]);
+ if (show_center_node) {
+ outline_path.push_back(pathv[1]);
+ }
+ }
+}
+
+void
+LPEShowHandles::drawHandle(Geom::Point p)
+{
+ if(stroke_width * scale_nodes_and_handles > 0.0) {
+ double diameter = stroke_width * scale_nodes_and_handles;
+ 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);
+ pathv *= Geom::Scale (diameter) * Geom::Translate(p - Geom::Point(diameter * 0.35,diameter * 0.35));
+ outline_path.push_back(pathv[0]);
+ }
+}
+
+
+void
+LPEShowHandles::drawHandleLine(Geom::Point p,Geom::Point p2)
+{
+ Geom::Path path;
+ double diameter = stroke_width * scale_nodes_and_handles;
+ if(diameter > 0.0 && Geom::distance(p,p2) > (diameter * 0.35)) {
+ Geom::Ray ray2(p, p2);
+ p2 = p2 - Geom::Point::polar(ray2.angle(),(diameter * 0.35));
+ }
+ path.start( p );
+ path.appendNew<Geom::LineSegment>( p2 );
+ outline_path.push_back(path);
+}
+
+}; //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 :