static void
sp_gradient_context_add_stops_between_selected_stops (SPGradientContext *rc)
{
    SPDocument *doc = NULL;
    GrDrag *drag = rc->_grdrag;

    GSList *these_stops = NULL;
    GSList *next_stops = NULL;

    std::vector<Geom::Point> coords = sp_gradient_context_get_stop_intervals (drag, &these_stops, &next_stops);

    if (g_slist_length(these_stops) == 0 && drag->numSelected() == 1) {
        // if a single stop is selected, add between that stop and the next one
        GrDragger *dragger = (GrDragger *) drag->selected->data;
        for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { 
            GrDraggable *d = (GrDraggable *) j->data;
            SPGradient *gradient = sp_item_gradient (d->item, d->fill_or_stroke);
            SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (gradient, false);
            SPStop *this_stop = sp_get_stop_i (vector, d->point_i);
            SPStop *next_stop = sp_next_stop (this_stop);
            if (this_stop && next_stop) {
                these_stops = g_slist_prepend (these_stops, this_stop);
                next_stops = g_slist_prepend (next_stops, next_stop);
            }
        }
    }

    // now actually create the new stops
    GSList *i = these_stops;
    GSList *j = next_stops;
    for (; i != NULL && j != NULL; i = i->next, j = j->next) {
        SPStop *this_stop = (SPStop *) i->data;
        SPStop *next_stop = (SPStop *) j->data;
        gfloat offset = 0.5*(this_stop->offset + next_stop->offset);
        SPObject *parent = SP_OBJECT_PARENT(this_stop);
        if (SP_IS_GRADIENT (parent)) {
            doc = SP_OBJECT_DOCUMENT (parent);
            sp_vector_add_stop (SP_GRADIENT (parent), this_stop, next_stop, offset);
            sp_gradient_ensure_vector (SP_GRADIENT (parent));
        }
    }

    if (g_slist_length(these_stops) > 0 && doc) {
        sp_document_done (doc, SP_VERB_CONTEXT_GRADIENT, _("Add gradient stop"));
        drag->updateDraggers();
        // so that it does not automatically update draggers in idle loop, as this would deselect
        drag->local_change = true;
        // select all the old selected and new created draggers
        drag->selectByCoords(coords);
    }

    g_slist_free (these_stops);
    g_slist_free (next_stops);
}
static void
sp_gradient_simplify(SPGradientContext *rc, double tolerance)
{
    SPDocument *doc = NULL;
    GrDrag *drag = rc->_grdrag;

    GSList *these_stops = NULL;
    GSList *next_stops = NULL;

    std::vector<Geom::Point> coords = sp_gradient_context_get_stop_intervals (drag, &these_stops, &next_stops);

    GSList *todel = NULL;

    GSList *i = these_stops;
    GSList *j = next_stops;
    for (; i != NULL && j != NULL; i = i->next, j = j->next) {
        SPStop *stop0 = (SPStop *) i->data;
        SPStop *stop1 = (SPStop *) j->data;

        gint i1 = g_slist_index(these_stops, stop1);
        if (i1 != -1) {
            GSList *next_next = g_slist_nth (next_stops, i1);
            if (next_next) {
                SPStop *stop2 = (SPStop *) next_next->data;

                if (g_slist_find(todel, stop0) || g_slist_find(todel, stop2))
                    continue;

                guint32 const c0 = sp_stop_get_rgba32(stop0);
                guint32 const c2 = sp_stop_get_rgba32(stop2);
                guint32 const c1r = sp_stop_get_rgba32(stop1);
                guint32 c1 = average_color (c0, c2, 
                       (stop1->offset - stop0->offset) / (stop2->offset - stop0->offset));

                double diff = 
                    sqr(SP_RGBA32_R_F(c1) - SP_RGBA32_R_F(c1r)) +
                    sqr(SP_RGBA32_G_F(c1) - SP_RGBA32_G_F(c1r)) +
                    sqr(SP_RGBA32_B_F(c1) - SP_RGBA32_B_F(c1r)) +
                    sqr(SP_RGBA32_A_F(c1) - SP_RGBA32_A_F(c1r));

                if (diff < tolerance)
                    todel = g_slist_prepend (todel, stop1);
            }
        }
    }

    for (i = todel; i != NULL; i = i->next) {
        SPStop *stop = (SPStop*) i->data;
        doc = SP_OBJECT_DOCUMENT (stop);
        Inkscape::XML::Node * parent = SP_OBJECT_REPR(stop)->parent();
        parent->removeChild(SP_OBJECT_REPR(stop));
    }

    if (g_slist_length(todel) > 0) {
        sp_document_done (doc, SP_VERB_CONTEXT_GRADIENT, _("Simplify gradient"));
        drag->local_change = true;
        drag->updateDraggers();
        drag->selectByCoords(coords);
    }

    g_slist_free (todel);
    g_slist_free (these_stops);
    g_slist_free (next_stops);
}
Beispiel #3
0
/**
Wrapper for various mesh operations that require a list of selected corner nodes.
 */
static void
sp_mesh_context_corner_operation (SPMeshContext *rc, MeshCornerOperation operation )
{

#ifdef DEBUG_MESH
    std::cout << "sp_mesh_corner_operation: entrance: " << operation << std::endl;
#endif

    SPDocument *doc = NULL;
    GrDrag *drag = rc->_grdrag;

    std::map<SPMeshGradient*, std::vector<guint> > points;
    std::map<SPMeshGradient*, SPItem*> items;
 
    // Get list of selected draggers for each mesh.
    // For all selected draggers
    for (GList *i = drag->selected; i != NULL; i = i->next) {
        GrDragger *dragger = (GrDragger *) i->data;
        // For all draggables of dragger
        for (GSList const* j = dragger->draggables; j != NULL; j = j->next) {
            GrDraggable *d = (GrDraggable *) j->data;

            // Only mesh corners
            if( d->point_type != POINT_MG_CORNER ) continue;

            // Find the gradient
            SPMeshGradient *gradient = SP_MESHGRADIENT( getGradient (d->item, d->fill_or_stroke) );

            // Collect points together for same gradient
            points[gradient].push_back( d->point_i );
            items[gradient] = d->item;
        }
    }

    // Loop over meshes.
    for( std::map<SPMeshGradient*, std::vector<guint> >::const_iterator iter = points.begin(); iter != points.end(); ++iter) {
        SPMeshGradient *mg = SP_MESHGRADIENT( iter->first );
        if( iter->second.size() > 0 ) {
            guint noperation = 0;
            switch (operation) {

                case MG_CORNER_SIDE_TOGGLE:
                    // std::cout << "SIDE_TOGGLE" << std::endl;
                    noperation += mg->array.side_toggle( iter->second );
                    break;

                case MG_CORNER_SIDE_ARC:
                    // std::cout << "SIDE_ARC" << std::endl;
                    noperation += mg->array.side_arc( iter->second );
                    break;

                case MG_CORNER_TENSOR_TOGGLE:
                    // std::cout << "TENSOR_TOGGLE" << std::endl;
                    noperation += mg->array.tensor_toggle( iter->second );
                    break;

                case MG_CORNER_COLOR_SMOOTH:
                    // std::cout << "COLOR_SMOOTH" << std::endl;
                    noperation += mg->array.color_smooth( iter->second );
                    break;

                case MG_CORNER_COLOR_PICK:
                    // std::cout << "COLOR_PICK" << std::endl;
                    noperation += mg->array.color_pick( iter->second, items[iter->first] );
                    break;

                default:
                    std::cout << "sp_mesh_corner_operation: unknown operation" << std::endl;
            }                    

            if( noperation > 0 ) {
                mg->array.write( mg );
                mg->requestModified(SP_OBJECT_MODIFIED_FLAG);
                doc = mg->document;

                switch (operation) {

                    case MG_CORNER_SIDE_TOGGLE:
                        DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Toggled mesh path type."));
                        break;

                    case MG_CORNER_SIDE_ARC:
                        DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Approximated arc for mesh side."));
                        break;

                    case MG_CORNER_TENSOR_TOGGLE:
                        DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Toggled mesh tensors."));
                        break;

                    case MG_CORNER_COLOR_SMOOTH:
                        DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Smoothed mesh corner color."));
                        break;

                    case MG_CORNER_COLOR_PICK:
                        DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Picked mesh corner color."));
                        break;

                    default:
                        std::cout << "sp_mesh_corner_operation: unknown operation" << std::endl;
                }
            }
        }
    }
    drag->updateDraggers();

}