summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: b2378d6)
raw | patch | inline | side by side (parent: b2378d6)
author | acspike <acspike@users.sourceforge.net> | |
Fri, 14 Apr 2006 21:24:32 +0000 (21:24 +0000) | ||
committer | acspike <acspike@users.sourceforge.net> | |
Fri, 14 Apr 2006 21:24:32 +0000 (21:24 +0000) |
Old deletion behavior is available via Ctrl+Delete
index 8316c86cc213d64d6db99b7df7cc97abd8baf57a..04a38c236b3c4454a38328553052dfd72aa39ecc 100644 (file)
NR::Point const data[], double const u[], unsigned len);
static void reparameterize(NR::Point const d[], unsigned len, double u[], BezierCurve const bezCurve);
static gdouble NewtonRaphsonRootFind(BezierCurve const Q, NR::Point const &P, gdouble u);
-static NR::Point bezier_pt(unsigned degree, NR::Point const V[], gdouble t);
static NR::Point sp_darray_center_tangent(NR::Point const d[], unsigned center, unsigned length);
static NR::Point sp_darray_right_tangent(NR::Point const d[], unsigned const len);
static unsigned copy_without_nans_or_adjacent_duplicates(NR::Point const src[], unsigned src_len, NR::Point dest[]);
* is i * BezierII(i-1, V'), where for all j, V'[j] =
* V[j + 1] - V[j].
*/
-static NR::Point
+NR::Point
bezier_pt(unsigned const degree, NR::Point const V[], gdouble const t)
{
/** Pascal's triangle. */
index f281ab220cf997c707d055000ce2e7d219053c4d..1d6c8678f0de12a7e1847302942ceb3cca7d0497 100644 (file)
#include <glib/gtypes.h>
/* Bezier approximation utils */
+NR::Point bezier_pt(unsigned degree, NR::Point const V[], gdouble t);
gint sp_bezier_fit_cubic(NR::Point bezier[], NR::Point const data[], gint len, gdouble error);
diff --git a/src/node-context.cpp b/src/node-context.cpp
index 1e01b1af9ac59e00602c3087623db0455cd4e89e..2e5fd3e7307d8d6e45833362491b042fad96a426 100644 (file)
--- a/src/node-context.cpp
+++ b/src/node-context.cpp
case GDK_Delete:
case GDK_KP_Delete:
case GDK_BackSpace:
- // with any modifiers
- sp_node_selected_delete();
+ if (MOD__CTRL_ONLY) {
+ sp_node_selected_delete();
+ } else {
+ sp_node_delete_preserve(g_list_copy(nc->nodepath->selected));
+ }
ret = TRUE;
break;
case GDK_C:
diff --git a/src/nodepath.cpp b/src/nodepath.cpp
index b50ee90c7b6a0acae5ae6540a89024627b0eca5d..8aed0420bb461f94f5ccf051ea5f6d456535474b 100644 (file)
--- a/src/nodepath.cpp
+++ b/src/nodepath.cpp
#include "prefs-utils.h"
#include "sp-metrics.h"
#include "sp-path.h"
-#include <libnr/nr-matrix-ops.h>
+#include "libnr/nr-matrix-ops.h"
#include "splivarot.h"
#include "svg/svg.h"
+#include "display/bezier-utils.h"
+#include <vector>
+#include <algorithm>
class NR::Matrix;
sp_nodepath_update_repr(nodepath);
}
+/**
+ * Delete one or more selected nodes and preserve the shape of the path as much as possible.
+ */
+void sp_node_delete_preserve(GList *nodes_to_delete)
+{
+
+ while (nodes_to_delete) {
+ Inkscape::NodePath::Node *node = (Inkscape::NodePath::Node*) g_list_first(nodes_to_delete)->data;
+ Inkscape::NodePath::SubPath *sp = node->subpath;
+ Inkscape::NodePath::Path *nodepath = sp->nodepath;
+ Inkscape::NodePath::Node *sample_cursor = NULL;
+ Inkscape::NodePath::Node *sample_end = NULL;
+ Inkscape::NodePath::Node *delete_cursor = node;
+ bool just_delete = false;
+
+ //find the start of this contiguous selection
+ //move left to the first node that is not selected
+ //or the start of the non-closed path
+ for (Inkscape::NodePath::Node *curr=node->p.other; curr && curr!=node && g_list_find(nodes_to_delete, curr); curr=curr->p.other) {
+ delete_cursor = curr;
+ }
+
+ //just delete at the beginning of an open path
+ if (!delete_cursor->p.other) {
+ sample_cursor = delete_cursor;
+ just_delete = true;
+ } else {
+ sample_cursor = delete_cursor->p.other;
+ }
+
+ //calculate points for each segment
+ int rate = 5;
+ float period = 1.0 / rate;
+ std::vector<NR::Point> data;
+ if (!just_delete) {
+ data.push_back(sample_cursor->pos);
+ for (Inkscape::NodePath::Node *curr=sample_cursor; curr; curr=curr->n.other) {
+ //just delete at the end of an open path
+ if (!sp->closed && curr->n.other == sp->last) {
+ just_delete = true;
+ break;
+ }
+
+ //sample points on the contiguous selected segment
+ NR::Point *bez;
+ bez = new NR::Point [4];
+ bez[0] = curr->pos;
+ bez[1] = curr->n.pos;
+ bez[2] = curr->n.other->p.pos;
+ bez[3] = curr->n.other->pos;
+ for (int i=1; i<rate; i++) {
+ gdouble t = i * period;
+ NR::Point p = bezier_pt(3, bez, t);
+ data.push_back(p);
+ }
+ data.push_back(curr->n.other->pos);
+
+ sample_end = curr->n.other;
+ //break if we've come full circle or hit the end of the selection
+ if (!g_list_find(nodes_to_delete, curr->n.other) || curr->n.other==sample_cursor) {
+ break;
+ }
+ }
+ }
+
+ if (!just_delete) {
+ //calculate the best fitting single segment and adjust the endpoints
+ NR::Point *adata;
+ adata = new NR::Point [data.size()];
+ copy(data.begin(), data.end(), adata);
+
+ NR::Point *bez;
+ bez = new NR::Point [4];
+ //would decreasing error create a better fitting approximation?
+ gdouble error = 1.0;
+ gint ret;
+ ret = sp_bezier_fit_cubic (bez, adata, data.size(), error);
+
+ //adjust endpoints
+ sample_cursor->n.pos = bez[1];
+ sample_end->p.pos = bez[2];
+ }
+
+ //destroy this contiguous selection
+ while (delete_cursor && g_list_find(nodes_to_delete, delete_cursor)) {
+ Inkscape::NodePath::Node *temp = delete_cursor;
+ if (delete_cursor->n.other == delete_cursor) {
+ // delete_cursor->n points to itself, which means this is the last node on a closed subpath
+ delete_cursor = NULL;
+ } else {
+ delete_cursor = delete_cursor->n.other;
+ }
+ nodes_to_delete = g_list_remove(nodes_to_delete, temp);
+ sp_nodepath_node_destroy(temp);
+ }
+
+ //clean up the nodepath (such as for trivial subpaths)
+ sp_nodepath_cleanup(nodepath);
+
+ sp_nodepath_update_handles(nodepath);
+
+ // if the entire nodepath is removed, delete the selected object.
+ if (nodepath->subpaths == NULL ||
+ sp_nodepath_get_node_count(nodepath) < 2) {
+ SPDocument *document = SP_DT_DOCUMENT (nodepath->desktop);
+ sp_nodepath_destroy(nodepath);
+ g_list_free(nodes_to_delete);
+ nodes_to_delete = NULL;
+ //is the next line necessary?
+ sp_selection_delete();
+ sp_document_done (document);
+ return;
+ }
+
+ sp_nodepath_update_repr(nodepath);
+
+ sp_nodepath_update_statusbar(nodepath);
+ }
+}
+
/**
* Delete one or more selected nodes.
*/
sp_nodepath_update_statusbar(nodepath);
} else { //ctrl+alt+click: delete node
- sp_nodepath_node_destroy(n);
- //clean up the nodepath (such as for trivial subpaths)
- sp_nodepath_cleanup(nodepath);
-
- // if the entire nodepath is removed, delete the selected object.
- if (nodepath->subpaths == NULL ||
- sp_nodepath_get_node_count(nodepath) < 2) {
- SPDocument *document = SP_DT_DOCUMENT (nodepath->desktop);
- sp_nodepath_destroy(nodepath);
- sp_selection_delete();
- sp_document_done (document);
-
- } else {
- sp_nodepath_update_handles(nodepath);
- sp_nodepath_update_repr(nodepath);
- sp_nodepath_update_statusbar(nodepath);
- }
+ GList *node_to_delete = NULL;
+ node_to_delete = g_list_append(node_to_delete, n);
+ sp_node_delete_preserve(node_to_delete);
}
} else {
diff --git a/src/nodepath.h b/src/nodepath.h
index a0f33d4b10105a350df486c6f2168050e4bff7db..c9315470fa3f082105491c609422cef9573b7976 100644 (file)
--- a/src/nodepath.h
+++ b/src/nodepath.h
void sp_node_selected_duplicate (void);
void sp_node_selected_join (void);
void sp_node_selected_join_segment (void);
+void sp_node_delete_preserve (GList *nodes_to_delete);
void sp_node_selected_delete (void);
void sp_node_selected_delete_segment (void);
void sp_node_selected_set_type (Inkscape::NodePath::NodeType type);