Logo Search packages:      
Sourcecode: inkscape version File versions  Download package

void sp_node_delete_preserve ( GList *  nodes_to_delete  ) 

Delete one or more selected nodes and preserve the shape of the path as much as possible.

Definition at line 2479 of file nodepath.cpp.

References Geom::bezier_fit_cubic(), Geom::bezier_pt(), Inkscape::NodePath::SubPath::closed, Inkscape::NodePath::Path::desktop, Inkscape::NodePath::SubPath::last, Inkscape::NodePath::Node::n, Inkscape::NodePath::SubPath::nodepath, Inkscape::NodePath::Node::p, Inkscape::NodePath::Node::pos, sp_nodepath_convert_node_type(), sp_nodepath_get_node_count(), sp_nodepath_node_destroy(), sp_nodepath_update_handles(), sp_nodepath_update_repr(), sp_nodepath_update_statusbar(), Inkscape::NodePath::Node::subpath, Inkscape::NodePath::Path::subpaths, and Inkscape::NodePath::Node::type.

Referenced by node_clicked().

{
    GSList *nodepaths = NULL;

    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<Geom::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 == sp->last) {
                    just_delete = true;
                    break;
                }

                //sample points on the contiguous selected segment
                Geom::Point *bez;
                bez = new Geom::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;
                    Geom::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
            Geom::Point *adata;
            adata = new Geom::Point [data.size()];
            copy(data.begin(), data.end(), adata);

            Geom::Point *bez;
            bez = new Geom::Point [4];
            //would decreasing error create a better fitting approximation?
            gdouble error = 1.0;
            gint ret;
            ret = Geom::bezier_fit_cubic (bez, adata, data.size(), error);

            //if these nodes are smooth or symmetrical, the endpoints will be thrown out of sync.
            //make sure these nodes are changed to cusp nodes so that, once the endpoints are moved,
            //the resulting nodes behave as expected.
            if (sample_cursor->type != Inkscape::NodePath::NODE_CUSP)
                sp_nodepath_convert_node_type(sample_cursor, Inkscape::NodePath::NODE_CUSP);
            if (sample_end->type != Inkscape::NodePath::NODE_CUSP)
                sp_nodepath_convert_node_type(sample_end, Inkscape::NodePath::NODE_CUSP);

            //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);
        }

        sp_nodepath_update_handles(nodepath);

        if (!g_slist_find(nodepaths, nodepath))
            nodepaths = g_slist_prepend (nodepaths, nodepath);
    }

    for (GSList *i = nodepaths; i; i = i->next) {
        // FIXME: when/if we teach node tool to have more than one nodepath, deleting nodes from
        // different nodepaths will give us one undo event per nodepath
        Inkscape::NodePath::Path *nodepath = (Inkscape::NodePath::Path *) i->data;

        // if the entire nodepath is removed, delete the selected object.
        if (nodepath->subpaths == NULL ||
            //FIXME: a closed path CAN legally have one node, it's only an open one which must be
            //at least 2
            sp_nodepath_get_node_count(nodepath) < 2) {
            SPDocument *document = sp_desktop_document (nodepath->desktop);
            //FIXME: The following line will be wrong when we have mltiple nodepaths: we only want to
            //delete this nodepath's object, not the entire selection! (though at this time, this
            //does not matter)
            sp_selection_delete(nodepath->desktop);
            sp_document_done (document, SP_VERB_CONTEXT_NODE,
                              _("Delete nodes"));
        } else {
            sp_nodepath_update_repr(nodepath, _("Delete nodes preserving shape"));
            sp_nodepath_update_statusbar(nodepath);
        }
    }

    g_slist_free (nodepaths);
}


Generated by  Doxygen 1.6.0   Back to index