Code

Implement segment weld to make segment join similar to node join
authorKrzysztof Kosiński <tweenk.pl@gmail.com>
Thu, 14 Jan 2010 08:42:20 +0000 (09:42 +0100)
committerKrzysztof Kosiński <tweenk.pl@gmail.com>
Thu, 14 Jan 2010 08:42:20 +0000 (09:42 +0100)
src/ui/tool/multi-path-manipulator.cpp
src/ui/tool/multi-path-manipulator.h
src/ui/tool/path-manipulator.cpp
src/widgets/toolbox.cpp

index 2cc9bc97b5cf26b45cf6abab886d20c6e26e5529..3ae7e4d2495264cb8c3f4a32fc870d4d4c7faa6b 100644 (file)
@@ -304,15 +304,10 @@ void MultiPathManipulator::deleteNodes(bool keep_shape)
 }
 
 /** Join selected endpoints to create segments. */
-void MultiPathManipulator::joinSegment()
+void MultiPathManipulator::joinSegments()
 {
     IterPairList joins;
     find_join_iterators(_selection, joins);
-    if (joins.empty()) {
-        _desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE,
-            _("There must be at least 2 endnodes in selection"));
-        return;
-    }
 
     for (IterPairList::iterator i = joins.begin(); i != joins.end(); ++i) {
         bool same_path = prepare_join(*i);
@@ -328,6 +323,9 @@ void MultiPathManipulator::joinSegment()
         }
     }
 
+    if (joins.empty()) {
+        invokeForAll(&PathManipulator::weldSegments);
+    }
     _doneWithCleanup("Join segments");
 }
 
@@ -421,7 +419,7 @@ bool MultiPathManipulator::event(GdkEvent *event)
                 return true;
             }
             if (held_only_alt(event->key)) {
-                joinSegment();
+                joinSegments();
                 return true;
             }
             break;
index 46ad3a8d22f054b81863c9a90f9347c70340714d..151e153ecc9036931cfb2f0ecaf71e8807100bd4 100644 (file)
@@ -55,7 +55,7 @@ public:
     void joinNodes();
     void breakNodes();
     void deleteNodes(bool keep_shape = true);
-    void joinSegment();
+    void joinSegments();
     void deleteSegments();
     void alignNodes(Geom::Dim2 d);
     void distributeNodes(Geom::Dim2 d);
index cfa3846f86495a5b37aa2206db5e369817bbde9b..9889eb787cd3a96c33d467885ea3cc4f9db95578 100644 (file)
@@ -317,19 +317,21 @@ void PathManipulator::weldNodes(NodeList::iterator preserve_pos)
         }
 
         // Start from unselected node in closed paths, so that we don't start in the middle
-        // of a contiguous selection
+        // of a selection
         NodeList::iterator sel_beg = sp->begin(), sel_end;
         if (sp->closed()) {
             while (sel_beg->selected()) ++sel_beg;
         }
 
-        // Main loop
+        // Work loop
         while (num_selected > 0) {
             // Find selected node
             while (sel_beg && !sel_beg->selected()) sel_beg = sel_beg.next();
             if (!sel_beg) throw std::logic_error("Join nodes: end of open path reached, "
                 "but there are still nodes to process!");
 
+            // note: this is initialized to zero, because the loop below counts sel_beg as well
+            // the loop conditions are simpler that way
             unsigned num_points = 0;
             bool use_pos = false;
             Geom::Point back_pos, front_pos;
@@ -373,7 +375,57 @@ void PathManipulator::weldNodes(NodeList::iterator preserve_pos)
 /** Remove nodes in the middle of selected segments. */
 void PathManipulator::weldSegments()
 {
-    // TODO
+    if (!_num_selected) return;
+    _dragpoint->setVisible(false);
+
+    for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
+        SubpathPtr sp = *i;
+        unsigned num_selected = 0, num_unselected = 0;
+        for (NodeList::iterator j = sp->begin(); j != sp->end(); ++j) {
+            if (j->selected()) ++num_selected;
+            else ++num_unselected;
+        }
+        if (num_selected < 3) continue;
+        if (num_unselected == 0 && sp->closed()) {
+            // if all nodes in a closed subpath are selected, the operation doesn't make much sense
+            continue;
+        }
+
+        // Start from unselected node in closed paths, so that we don't start in the middle
+        // of a selection
+        NodeList::iterator sel_beg = sp->begin(), sel_end;
+        if (sp->closed()) {
+            while (sel_beg->selected()) ++sel_beg;
+        }
+
+        // Work loop
+        while (num_selected > 0) {
+            // Find selected node
+            while (sel_beg && !sel_beg->selected()) sel_beg = sel_beg.next();
+            if (!sel_beg) throw std::logic_error("Join nodes: end of open path reached, "
+                "but there are still nodes to process!");
+
+            // note: this is initialized to zero, because the loop below counts sel_beg as well
+            // the loop conditions are simpler that way
+            unsigned num_points = 0;
+
+            // find the end of selected segment
+            for (sel_end = sel_beg; sel_end && sel_end->selected(); sel_end = sel_end.next()) {
+                ++num_points;
+            }
+            if (num_points > 2) {
+                // remove nodes in the middle
+                sel_beg = sel_beg.next();
+                while (sel_beg != sel_end.prev()) {
+                    NodeList::iterator next = sel_beg.next();
+                    sp->erase(sel_beg);
+                    sel_beg = next;
+                }
+                sel_beg = sel_end;
+            }
+            num_selected -= num_points;
+        }
+    }
 }
 
 /** Break the subpath at selected nodes. It also works for single node closed paths. */
index bb13bfdad01ec93f8f705154df59d28792f02f41..e3d309c47ffaf22f368ae43a3c541c1866cadf0e 100644 (file)
@@ -1061,7 +1061,7 @@ void
 sp_node_path_edit_join_segment(void)
 {
     InkNodeTool *nt = get_node_tool();
-    if (nt) nt->_multipath->joinSegment();
+    if (nt) nt->_multipath->joinSegments();
 }
 
 void