summaryrefslogtreecommitdiffstats
path: root/src/spray-context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/spray-context.cpp')
-rw-r--r--src/spray-context.cpp1208
1 files changed, 1208 insertions, 0 deletions
diff --git a/src/spray-context.cpp b/src/spray-context.cpp
new file mode 100644
index 000000000..b70e16467
--- /dev/null
+++ b/src/spray-context.cpp
@@ -0,0 +1,1208 @@
+#define __SP_SPRAY_CONTEXT_C__
+
+/*
+ * Spray Tool
+ *
+ * Authors:
+ * Pierre-Antoine MARC
+ * Pierre CACLIN
+ * Aurel-Aimé MARMION
+ * Julien LERAY
+ * Benoît LAVORATA
+ * Vincent MONTAGNE
+ * Pierre BARBRY-BLOT
+ *
+ * Copyright (C) 2009 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <glibmm/i18n.h>
+
+#include <numeric>
+
+#include "svg/svg.h"
+#include "display/canvas-bpath.h"
+
+#include <glib/gmem.h>
+#include "macros.h"
+#include "document.h"
+#include "selection.h"
+#include "desktop.h"
+#include "desktop-events.h"
+#include "desktop-handles.h"
+#include "unistd.h"
+#include "desktop-style.h"
+#include "message-context.h"
+#include "pixmaps/cursor-spray.xpm"
+#include "pixmaps/cursor-spray-move.xpm"
+#include "pixmaps/cursor-thin.xpm"
+#include "pixmaps/cursor-thicken.xpm"
+#include "pixmaps/cursor-attract.xpm"
+#include "pixmaps/cursor-repel.xpm"
+#include "pixmaps/cursor-push.xpm"
+#include "pixmaps/cursor-roughen.xpm"
+#include "pixmaps/cursor-color.xpm"
+#include <boost/optional.hpp>
+#include "libnr/nr-matrix-ops.h"
+#include "libnr/nr-scale-translate-ops.h"
+#include "xml/repr.h"
+#include "context-fns.h"
+#include "sp-item.h"
+#include "inkscape.h"
+#include "color.h"
+#include "svg/svg-color.h"
+#include "splivarot.h"
+#include "sp-item-group.h"
+#include "sp-shape.h"
+#include "sp-path.h"
+#include "path-chemistry.h"
+#include "sp-gradient.h"
+#include "sp-stop.h"
+#include "sp-stop-fns.h"
+#include "sp-gradient-reference.h"
+#include "sp-linear-gradient.h"
+#include "sp-radial-gradient.h"
+#include "gradient-chemistry.h"
+#include "sp-text.h"
+#include "sp-flowtext.h"
+#include "display/canvas-bpath.h"
+#include "display/canvas-arena.h"
+#include "display/curve.h"
+#include "livarot/Shape.h"
+#include <2geom/isnan.h>
+#include <2geom/transforms.h>
+#include "preferences.h"
+#include "style.h"
+#include "box3d.h"
+#include "sp-item-transform.h"
+#include "filter-chemistry.h"
+#include "sp-gaussian-blur-fns.h"
+#include "sp-gaussian-blur.h"
+
+#include "spray-context.h"
+#include "ui/dialog/dialog-manager.h"
+#include "helper/action.h"
+
+#include <iostream>
+using namespace std;
+
+
+#define DDC_RED_RGBA 0xff0000ff
+
+#define DYNA_MIN_WIDTH 1.0e-6
+
+static void sp_spray_context_class_init(SPSprayContextClass *klass);
+static void sp_spray_context_init(SPSprayContext *ddc);
+static void sp_spray_context_dispose(GObject *object);
+
+static void sp_spray_context_setup(SPEventContext *ec);
+static void sp_spray_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val);
+static gint sp_spray_context_root_handler(SPEventContext *ec, GdkEvent *event);
+
+static SPEventContextClass *parent_class = 0;
+
+
+
+// The following code implements NormalDistribution wich is used for the density of the spray
+
+
+/*
+ RAND is a macro which returns a pseudo-random numbers from a uniform
+ distribution on the interval [0 1]
+*/
+#define RAND ((double) rand())/((double) RAND_MAX)
+
+/*
+ TWOPI = 2.0*pi
+*/
+#define TWOPI 2.0*3.141592653589793238462643383279502884197169399375
+
+/*
+ RANDN is a macro which returns a pseudo-random numbers from a normal
+ distribution with mean zero and standard deviation one. This macro uses Box
+ Muller's algorithm
+*/
+#define RANDN sqrt(-2.0*log(RAND))*cos(TWOPI*RAND)
+
+
+double NormalDistribution(double mu,double sigma)
+{
+/*
+ This function returns a pseudo-random numbers from a normal distribution with
+ mean equal at mu and standard deviation equal at sigma > 0
+*/
+
+ return (mu+sigma*RANDN);
+
+}
+
+//Fin de la création de NormalDistribution
+
+GtkType sp_spray_context_get_type(void)
+{
+ static GType type = 0;
+ if (!type) {
+ GTypeInfo info = {
+ sizeof(SPSprayContextClass),
+ NULL, NULL,
+ (GClassInitFunc) sp_spray_context_class_init,
+ NULL, NULL,
+ sizeof(SPSprayContext),
+ 4,
+ (GInstanceInitFunc) sp_spray_context_init,
+ NULL, /* value_table */
+ };
+ type = g_type_register_static(SP_TYPE_EVENT_CONTEXT, "SPSprayContext", &info, (GTypeFlags)0);
+ }
+ return type;
+}
+
+static void sp_spray_context_class_init(SPSprayContextClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ SPEventContextClass *event_context_class = (SPEventContextClass *) klass;
+
+ parent_class = (SPEventContextClass*)g_type_class_peek_parent(klass);
+
+ object_class->dispose = sp_spray_context_dispose;
+
+ event_context_class->setup = sp_spray_context_setup;
+ event_context_class->set = sp_spray_context_set;
+ event_context_class->root_handler = sp_spray_context_root_handler;
+}
+
+/*Method to rotate items*/
+void sp_spray_rotate_rel(Geom::Point c,SPDesktop */*desktop*/,SPItem *item, Geom::Rotate const &rotation)
+{
+
+ Geom::Point center = c;
+ Geom::Translate const s(c);
+ Geom::Matrix affine = Geom::Matrix(s).inverse() * Geom::Matrix(rotation) * Geom::Matrix(s);
+
+ // Rotate item.
+ sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * (Geom::Matrix)affine);
+ // Use each item's own transform writer, consistent with sp_selection_apply_affine()
+ sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform);
+
+ // Restore the center position (it's changed because the bbox center changed)
+ if (item->isCenterSet()) {
+ item->setCenter(c);
+ item->updateRepr();
+ }
+}
+
+/*Method to scale items*/
+void sp_spray_scale_rel(Geom::Point c, SPDesktop */*desktop*/, SPItem *item, Geom::Scale const &scale)
+{
+ Geom::Translate const s(c);
+
+
+ sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * s.inverse() * scale * s );
+ sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform);
+
+
+}
+
+static void sp_spray_context_init(SPSprayContext *tc)
+{
+ SPEventContext *event_context = SP_EVENT_CONTEXT(tc);
+
+
+
+ event_context->cursor_shape = cursor_spray_xpm;
+ event_context->hot_x = 4;
+ event_context->hot_y = 4;
+
+ /* attributes */
+ tc->dragging = FALSE;
+ tc->distrib = 1;
+ tc->width = 0.2;
+ tc->force = 0.2;
+ tc->ratio = 0;
+ tc->tilt=0;
+ tc->mean = 0.2;
+ tc->rot_min=0;
+ tc->rot_max=0;
+ tc->standard_deviation=0.2;
+ tc->scale=1;
+ tc->scale_min = 1;
+ tc->scale_max=1;
+ tc->pressure = TC_DEFAULT_PRESSURE;
+
+ tc->is_dilating = false;
+ tc->has_dilated = false;
+
+ tc->do_h = true;
+ tc->do_s = true;
+ tc->do_l = true;
+ tc->do_o = false;
+
+ new (&tc->style_set_connection) sigc::connection();
+}
+
+static void sp_spray_context_dispose(GObject *object)
+{
+ SPSprayContext *tc = SP_SPRAY_CONTEXT(object);
+
+ tc->style_set_connection.disconnect();
+ tc->style_set_connection.~connection();
+
+ if (tc->dilate_area) {
+ gtk_object_destroy(GTK_OBJECT(tc->dilate_area));
+ tc->dilate_area = NULL;
+ }
+
+ if (tc->_message_context) {
+ delete tc->_message_context;
+ }
+
+ G_OBJECT_CLASS(parent_class)->dispose(object);
+}
+
+bool is_transform_modes(gint mode)
+{
+ return (mode == SPRAY_MODE_COPY ||
+ mode == SPRAY_MODE_CLONE ||
+ mode == SPRAY_MODE_SINGLE_PATH ||
+ mode == SPRAY_OPTION);
+}
+
+void sp_spray_update_cursor(SPSprayContext *tc, bool /*with_shift*/)
+{
+ SPEventContext *event_context = SP_EVENT_CONTEXT(tc);
+ SPDesktop *desktop = event_context->desktop;
+
+ guint num = 0;
+ gchar *sel_message = NULL;
+ if (!desktop->selection->isEmpty()) {
+ num = g_slist_length((GSList *) desktop->selection->itemList());
+ sel_message = g_strdup_printf(ngettext("<b>%i</b> object selected","<b>%i</b> objects selected",num), num);
+ } else {
+ sel_message = g_strdup_printf(_("<b>Nothing</b> selected"));
+ }
+
+
+ switch (tc->mode) {
+ case SPRAY_MODE_COPY:
+ tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray <b>copies</b> of the initial selection"), sel_message);
+ break;
+ case SPRAY_MODE_CLONE:
+ tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray <b>clones</b> of the initial selection"), sel_message);
+ break;
+ case SPRAY_MODE_SINGLE_PATH:
+ tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray in a <b>single path</b> of the initial selection"), sel_message);
+ break;
+ case SPRAY_OPTION:
+ tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Modify <b>spray</b> options"), sel_message);
+ break;
+ }
+ sp_event_context_update_cursor(event_context);
+ g_free(sel_message);
+}
+
+static void sp_spray_context_setup(SPEventContext *ec)
+{
+ SPSprayContext *tc = SP_SPRAY_CONTEXT(ec);
+
+ if (((SPEventContextClass *) parent_class)->setup)
+ ((SPEventContextClass *) parent_class)->setup(ec);
+
+ {
+ /* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */
+ SPCurve *c = new SPCurve();
+ const double C1 = 0.552;
+ c->moveto(-1,0);
+ c->curveto(-1, C1, -C1, 1, 0, 1 );
+ c->curveto(C1, 1, 1, C1, 1, 0 );
+ c->curveto(1, -C1, C1, -1, 0, -1 );
+ c->curveto(-C1, -1, -1, -C1, -1, 0 );
+ c->closepath();
+ tc->dilate_area = sp_canvas_bpath_new(sp_desktop_controls(ec->desktop), c);
+ c->unref();
+ sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(tc->dilate_area), 0x00000000,(SPWindRule)0);
+ sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(tc->dilate_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
+ sp_canvas_item_hide(tc->dilate_area);
+ }
+
+ tc->is_drawing = false;
+
+ tc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
+
+ sp_event_context_read(ec, "distrib");
+ sp_event_context_read(ec, "width");
+ sp_event_context_read(ec, "ratio");
+ sp_event_context_read(ec, "tilt");
+ sp_event_context_read(ec, "rot_min");
+ sp_event_context_read(ec, "rot_max");
+ sp_event_context_read(ec, "scale_min");
+ sp_event_context_read(ec, "scale_max");
+ sp_event_context_read(ec, "mode");
+ sp_event_context_read(ec, "population");
+ sp_event_context_read(ec, "force");
+ sp_event_context_read(ec, "mean");
+ sp_event_context_read(ec, "standard_deviation");
+ sp_event_context_read(ec, "usepressure");
+ sp_event_context_read(ec, "Rotation min");
+ sp_event_context_read(ec, "Rotation max");
+ sp_event_context_read(ec, "Scale");
+ sp_event_context_read(ec, "doh");
+ sp_event_context_read(ec, "dol");
+ sp_event_context_read(ec, "dos");
+ sp_event_context_read(ec, "doo");
+
+ ;
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if (prefs->getBool("/tools/spray/selcue")) {
+ ec->enableSelectionCue();
+ }
+
+ if (prefs->getBool("/tools/spray/gradientdrag")) {
+ ec->enableGrDrag();
+ }
+}
+
+static void sp_spray_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val)
+{
+ SPSprayContext *tc = SP_SPRAY_CONTEXT(ec);
+ Glib::ustring path = val->getEntryName();
+
+ if (path == "width") {
+ tc->width = 0.01 * CLAMP(val->getInt(10), 1, 100);
+ } else if (path == "mode") {
+ tc->mode = val->getInt();
+ sp_spray_update_cursor(tc, false);
+ } else if (path == "distribution") {
+ tc->distrib = val->getInt(1);
+ } else if (path == "population") {
+ tc->population = 0.01 * CLAMP(val->getInt(10), 1, 100);
+ } else if (path == "tilt") {
+ tc->tilt = CLAMP(val->getDouble(0.1), 0, 1000.0);
+ } else if (path == "ratio") {
+ tc->ratio = CLAMP(val->getDouble(), 0.0, 0.9);
+ } else if (path == "force") {
+ tc->force = CLAMP(val->getDouble(1.0), 0, 1.0);
+ } else if (path == "rot_min") {
+ tc->rot_min = CLAMP(val->getDouble(0), 0, 10.0);
+ } else if (path == "rot_max") {
+ tc->rot_max = CLAMP(val->getDouble(0), 0, 10.0);
+ } else if (path == "scale_min") {
+ tc->scale_min = CLAMP(val->getDouble(1.0), 0, 10.0);
+ } else if (path == "scale_max") {
+ tc->scale_max = CLAMP(val->getDouble(1.0), 0, 10.0);
+ } else if (path == "mean") {
+ tc->mean = 0.01 * CLAMP(val->getInt(10), 1, 100);
+ } else if (path == "standard_deviation") {
+ tc->standard_deviation = 0.01 * CLAMP(val->getInt(10), 1, 100);
+ } else if (path == "usepressure") {
+ tc->usepressure = val->getBool();
+ } else if (path == "doh") {
+ tc->do_h = val->getBool();
+ } else if (path == "dos") {
+ tc->do_s = val->getBool();
+ } else if (path == "dol") {
+ tc->do_l = val->getBool();
+ } else if (path == "doo") {
+ tc->do_o = val->getBool();
+ }
+}
+
+static void sp_spray_extinput(SPSprayContext *tc, GdkEvent *event)
+{
+ if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &tc->pressure))
+ tc->pressure = CLAMP (tc->pressure, TC_MIN_PRESSURE, TC_MAX_PRESSURE);
+ else
+ tc->pressure = TC_DEFAULT_PRESSURE;
+}
+
+double get_dilate_radius(SPSprayContext *tc)
+{
+
+ return 250 * tc->width/SP_EVENT_CONTEXT(tc)->desktop->current_zoom();
+
+
+}
+
+double get_path_force(SPSprayContext *tc)
+{
+ double force = 8 * (tc->usepressure? tc->pressure : TC_DEFAULT_PRESSURE)
+ /sqrt(SP_EVENT_CONTEXT(tc)->desktop->current_zoom());
+ if (force > 3) {
+ force += 4 * (force - 3);
+ }
+ return force * tc->force;
+}
+
+double get_path_mean(SPSprayContext *tc)
+{
+ return tc->mean;
+}
+
+double get_path_standard_deviation(SPSprayContext *tc)
+{
+ return tc->standard_deviation;
+}
+
+double get_move_force(SPSprayContext *tc)
+{
+ double force = (tc->usepressure? tc->pressure : TC_DEFAULT_PRESSURE);
+ return force * tc->force;
+}
+
+double get_move_mean(SPSprayContext *tc)
+{
+ return tc->mean;
+}
+
+double get_move_standard_deviation(SPSprayContext *tc)
+{
+ return tc->standard_deviation;
+}
+
+/* Method to handle the distribution of the items */
+
+
+void random_position( double &r, double &p, double &a, double &s, int choix)
+{
+ if (choix == 0) // Mode 1 : uniform repartition
+ {
+ r = (1-pow(g_random_double_range(0, 1),2));
+ p = g_random_double_range(0, M_PI*2);
+ }
+ if (choix == 1) //Mode 0 : gaussian repartition
+ {
+ double r_temp =-1;
+while(!((r_temp>=0)&&(r_temp<=1)))
+{
+ r_temp = NormalDistribution(a,s/4);
+}
+// generates a number following a normal distribution
+ p = g_random_double_range(0, M_PI*2);
+ r=r_temp;
+ /* if (r_temp<=0) r=0;
+ else
+ {
+ if (r_temp>1) r=1;
+ else r = r_temp;
+ }*/
+ }
+}
+
+
+
+
+
+bool sp_spray_dilate_recursive(SPDesktop *desktop,
+ Inkscape::Selection *selection,
+ SPItem *item,
+ Geom::Point p,
+ Geom::Point /*vector*/,
+ gint mode,
+ double radius,
+ double /*force*/,
+ double population,
+ double &scale,
+ double scale_min,
+ double scale_max,
+ bool /*reverse*/,
+ double mean,
+ double standard_deviation,
+ double ratio,
+ double tilt,
+ double rot_min,
+ double rot_max,
+ gint _distrib )
+{
+
+
+
+ bool did = false;
+
+ if (SP_IS_BOX3D(item) /*&& !is_transform_modes(mode)*/) {
+ // convert 3D boxes to ordinary groups before spraying their shapes
+ item = SP_ITEM(box3d_convert_to_group(SP_BOX3D(item)));
+ selection->add(item);
+ }
+
+/*if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
+ GSList *items = g_slist_prepend (NULL, item);
+ GSList *selected = NULL;
+ GSList *to_select = NULL;
+ SPDocument *doc = SP_OBJECT_DOCUMENT(item);
+ sp_item_list_to_curves (items, &selected, &to_select);
+ g_slist_free (items);
+ SPObject* newObj = doc->getObjectByRepr((Inkscape::XML::Node *) to_select->data);
+ g_slist_free (to_select);
+ item = (SPItem *) newObj;
+ // selection->add(item);
+ }
+*/
+ /*if (SP_IS_GROUP(item) && !SP_IS_BOX3D(item)) {
+ for (SPObject *child = sp_object_first_child(SP_OBJECT(item)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
+ if (SP_IS_ITEM(child)) {
+ if (sp_spray_dilate_recursive (desktop,selection, SP_ITEM(child), p, vector, mode, radius, force, population, scale, scale_min, scale_max, reverse, mean, standard_deviation,ratio,tilt, rot_min, rot_max,_distrib))
+ did = true;
+ }
+ }
+
+ } else {*/
+ if (mode == SPRAY_MODE_COPY) {
+
+ Geom::OptRect a = item->getBounds(sp_item_i2doc_affine(item));
+ if (a) {
+ double dr; double dp;
+ random_position(dr,dp,mean,standard_deviation,_distrib);
+ dr=dr*radius;
+ double _fid = g_random_double_range(0,1);
+ SPItem *item_copied;
+ double angle = g_random_double_range(rot_min, rot_max);
+ double _scale = g_random_double_range(scale_min, scale_max);
+ if(_fid<=population)
+ {
+ // duplicate
+ SPDocument *doc = SP_OBJECT_DOCUMENT(item);
+ Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
+ Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item);
+ Inkscape::XML::Node *parent = old_repr->parent();
+ Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
+ parent->appendChild(copy);
+
+ SPObject *new_obj = doc->getObjectByRepr(copy);
+ item_copied = (SPItem *) new_obj; //convertion object->item
+ Geom::Point center=item->getCenter();
+ sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale));
+ sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale));
+
+ sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
+ Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());//Move the cursor p
+ sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
+
+
+
+
+
+ did = true;
+ }
+ }
+
+ } else if (mode == SPRAY_MODE_SINGLE_PATH) {
+
+
+ SPItem *Pere; //Objet initial
+ SPItem *item_copied;//Objet projeté
+ SPItem *Union;//Union précédente
+ SPItem *fils;//Copie du père
+
+ // GSList *items = g_slist_copy((GSList *) selection->itemList()); //Récupère la liste des objects sélectionnés
+//Pere = (SPItem *) items->data;//Le premier objet est le père du spray
+
+ int i=1;
+ for (GSList *items = g_slist_copy((GSList *) selection->itemList());
+ items != NULL;
+ items = items->next) {
+
+ SPItem *item1 = (SPItem *) items->data;
+ if (i==1) {
+ Pere=item1;
+ }
+ if (i==2) {
+ Union=item1;
+ }
+ i++;
+ }
+ SPDocument *doc = SP_OBJECT_DOCUMENT(Pere);
+ Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
+ Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(Pere);
+ //SPObject *old_obj = doc->getObjectByRepr(old_repr);
+ Inkscape::XML::Node *parent = old_repr->parent();
+
+ Geom::OptRect a = Pere->getBounds(sp_item_i2doc_affine(Pere));
+ if (a) {
+ double dr; double dp; //initialisation des variables
+ random_position(dr,dp,mean,standard_deviation,_distrib);
+ dr=dr*radius;
+ double _fid = g_random_double_range(0,1);
+ double angle = (g_random_double_range(rot_min, rot_max));
+ double _scale = g_random_double_range(scale_min, scale_max);
+ if (i==2) {
+ Inkscape::XML::Node *copy1 = old_repr->duplicate(xml_doc);
+ parent->appendChild(copy1);
+ SPObject *new_obj1 = doc->getObjectByRepr(copy1);
+ fils = (SPItem *) new_obj1; //conversion object->item
+ Union=fils;
+ Inkscape::GC::release(copy1);
+ }
+
+ if (_fid<=population) { //Rules the population of objects sprayed
+ // duplicates the father
+ Inkscape::XML::Node *copy2 = old_repr->duplicate(xml_doc);
+ parent->appendChild(copy2);
+ SPObject *new_obj2 = doc->getObjectByRepr(copy2);
+ item_copied = (SPItem *) new_obj2;
+
+ Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());//Move around the cursor
+
+ Geom::Point center=Pere->getCenter();
+ sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale));
+ sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale));
+ sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
+ sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
+
+//UNION et surduplication
+ selection->clear();
+ selection->add(item_copied);
+ selection->add(Union);
+ sp_selected_path_union(selection->desktop());
+ selection->add(Pere);
+ Inkscape::GC::release(copy2);
+ did = true;
+ }
+
+ }
+ } else if (mode == SPRAY_MODE_CLONE) {
+
+ Geom::OptRect a = item->getBounds(sp_item_i2doc_affine(item));
+ if (a) {
+ double dr; double dp;
+ random_position(dr,dp,mean,standard_deviation,_distrib);
+ dr=dr*radius;
+ double _fid = g_random_double_range(0,1);
+ double angle = (g_random_double_range(rot_min, rot_max));
+ double _scale = g_random_double_range(scale_min, scale_max);
+
+ if(_fid<=population)
+ {
+ SPItem *item_copied;
+ SPDocument *doc = SP_OBJECT_DOCUMENT(item);
+ Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
+ Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item);
+ Inkscape::XML::Node *parent = old_repr->parent();
+
+ //Creation of the clone
+ Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
+ parent->appendChild(clone); //Ajout du clone à la liste d'enfants du père (selection initiale
+ clone->setAttribute("xlink:href", g_strdup_printf("#%s", old_repr->attribute("id")), false); //Génère le lien entre les attributs du père et du fils
+
+ SPObject *clone_object = doc->getObjectByRepr(clone);
+ item_copied = (SPItem *) clone_object;//conversion object->item
+ Geom::Point center=item->getCenter();
+ sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale));
+ sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale));
+ sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
+ Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
+ sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
+
+ Inkscape::GC::release(clone);
+
+ did = true;
+ } }}
+ return did;
+
+}
+
+
+bool sp_spray_color_recursive(guint /*mode*/,
+ SPItem */*item*/,
+ SPItem */*item_at_point*/,
+ guint32 /*fill_goal*/,
+ bool /*do_fill*/,
+ guint32 /*stroke_goal*/,
+ bool /*do_stroke*/,
+ float /*opacity_goal*/,
+ bool /*do_opacity*/,
+ bool /*do_blur*/,
+ bool /*reverse*/,
+ Geom::Point /*p*/,
+ double /*radius*/,
+ double /*force*/,
+ bool /*do_h*/,
+ bool /*do_s*/,
+ bool /*do_l*/,
+ bool /*do_o*/)
+{
+ bool did = false;
+
+ return did;
+}
+
+
+bool sp_spray_dilate(SPSprayContext *tc, Geom::Point /*event_p*/, Geom::Point p, Geom::Point vector, bool reverse)
+{
+ Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(tc)->desktop);
+ SPDesktop *desktop = SP_EVENT_CONTEXT(tc)->desktop;
+
+
+ if (selection->isEmpty()) {
+ return false;
+ }
+
+ bool did = false;
+ double radius = get_dilate_radius(tc);
+
+
+
+ bool do_fill = false, do_stroke = false, do_opacity = false;
+ guint32 fill_goal = sp_desktop_get_color_tool(desktop, "/tools/spray", true, &do_fill);
+ guint32 stroke_goal = sp_desktop_get_color_tool(desktop, "/tools/spray", false, &do_stroke);
+ double opacity_goal = sp_desktop_get_master_opacity_tool(desktop, "/tools/spray", &do_opacity);
+ if (reverse) {
+#if 0
+ // HSL inversion
+ float hsv[3];
+ float rgb[3];
+ sp_color_rgb_to_hsv_floatv (hsv,
+ SP_RGBA32_R_F(fill_goal),
+ SP_RGBA32_G_F(fill_goal),
+ SP_RGBA32_B_F(fill_goal));
+ sp_color_hsv_to_rgb_floatv (rgb, hsv[0]<.5? hsv[0]+.5 : hsv[0]-.5, 1 - hsv[1], 1 - hsv[2]);
+ fill_goal = SP_RGBA32_F_COMPOSE(rgb[0], rgb[1], rgb[2], 1);
+ sp_color_rgb_to_hsv_floatv (hsv,
+ SP_RGBA32_R_F(stroke_goal),
+ SP_RGBA32_G_F(stroke_goal),
+ SP_RGBA32_B_F(stroke_goal));
+ sp_color_hsv_to_rgb_floatv (rgb, hsv[0]<.5? hsv[0]+.5 : hsv[0]-.5, 1 - hsv[1], 1 - hsv[2]);
+ stroke_goal = SP_RGBA32_F_COMPOSE(rgb[0], rgb[1], rgb[2], 1);
+#else
+ // RGB inversion
+ fill_goal = SP_RGBA32_U_COMPOSE(
+ (255 - SP_RGBA32_R_U(fill_goal)),
+ (255 - SP_RGBA32_G_U(fill_goal)),
+ (255 - SP_RGBA32_B_U(fill_goal)),
+ (255 - SP_RGBA32_A_U(fill_goal)));
+ stroke_goal = SP_RGBA32_U_COMPOSE(
+ (255 - SP_RGBA32_R_U(stroke_goal)),
+ (255 - SP_RGBA32_G_U(stroke_goal)),
+ (255 - SP_RGBA32_B_U(stroke_goal)),
+ (255 - SP_RGBA32_A_U(stroke_goal)));
+#endif
+ opacity_goal = 1 - opacity_goal;
+ }
+
+ double path_force = get_path_force(tc);
+ if (radius == 0 || path_force == 0) {
+ return false;
+ }
+ double path_mean = get_path_mean(tc);
+ if (radius == 0 || path_mean == 0) {
+ return false;
+ }
+ double path_standard_deviation = get_path_standard_deviation(tc);
+ if (radius == 0 || path_standard_deviation == 0) {
+ return false;
+ }
+ double move_force = get_move_force(tc);
+ double move_mean = get_move_mean(tc);
+ double move_standard_deviation = get_move_standard_deviation(tc);
+
+
+ for (GSList *items = g_slist_copy((GSList *) selection->itemList());
+ items != NULL;
+ items = items->next) {
+
+ SPItem *item = (SPItem *) items->data;
+
+ /*if (is_color_modes (tc->mode)) {
+ if (do_fill || do_stroke || do_opacity) {
+ if (sp_spray_color_recursive (tc->mode, item, item_at_point,
+ fill_goal, do_fill,
+ stroke_goal, do_stroke,
+ opacity_goal, do_opacity,
+ tc->mode == SPRAY_MODE_BLUR, reverse,
+ p, radius, color_force, tc->do_h, tc->do_s, tc->do_l, tc->do_o))
+ did = true;
+ }
+ }else*/ if (is_transform_modes(tc->mode)) {
+ if (sp_spray_dilate_recursive (desktop,selection, item, p, vector, tc->mode, radius, move_force, tc->population,tc->scale, tc->scale_min, tc->scale_max, reverse, move_mean, move_standard_deviation,tc->ratio,tc->tilt, tc->rot_min, tc->rot_max, tc->distrib))
+ did = true;
+ } else {
+ if (sp_spray_dilate_recursive (desktop,selection, item, p, vector, tc->mode, radius, path_force, tc->population,tc->scale, tc->scale_min, tc->scale_max, reverse, path_mean, path_standard_deviation,tc->ratio,tc->tilt, tc->rot_min, tc->rot_max, tc->distrib))
+ did = true;
+ }
+ }
+
+ return did;
+}
+
+void sp_spray_update_area(SPSprayContext *tc)
+{
+ double radius = get_dilate_radius(tc);
+ Geom::Matrix const sm ( Geom::Scale(radius/(1-tc->ratio), radius/(1+tc->ratio)) );
+ sp_canvas_item_affine_absolute(tc->dilate_area, (sm* Geom::Rotate(tc->tilt))* Geom::Translate(SP_EVENT_CONTEXT(tc)->desktop->point()));
+ sp_canvas_item_show(tc->dilate_area);
+}
+
+void sp_spray_switch_mode(SPSprayContext *tc, gint mode, bool with_shift)
+{
+ SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("spray_tool_mode", mode); //sélectionne le bouton numéro "mode"
+ // need to set explicitly, because the prefs may not have changed by the previous
+ tc->mode = mode;
+ sp_spray_update_cursor (tc, with_shift);
+}
+
+void sp_spray_switch_mode_temporarily(SPSprayContext *tc, gint mode, bool with_shift)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ // Juggling about so that prefs have the old value but tc->mode and the button show new mode:
+ gint now_mode = prefs->getInt("/tools/spray/mode", 0);
+ SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("spray_tool_mode", mode);
+ // button has changed prefs, restore
+ prefs->setInt("/tools/spray/mode", now_mode);
+ // changing prefs changed tc->mode, restore back :)
+ tc->mode = mode;
+ sp_spray_update_cursor (tc, with_shift);
+}
+
+gint sp_spray_context_root_handler(SPEventContext *event_context,
+ GdkEvent *event)
+{
+ SPSprayContext *tc = SP_SPRAY_CONTEXT(event_context);
+ SPDesktop *desktop = event_context->desktop;
+
+ gint ret = FALSE;
+
+ switch (event->type) {
+ case GDK_ENTER_NOTIFY:
+ sp_canvas_item_show(tc->dilate_area);
+ break;
+ case GDK_LEAVE_NOTIFY:
+ sp_canvas_item_hide(tc->dilate_area);
+ break;
+ case GDK_BUTTON_PRESS:
+ if (event->button.button == 1 && !event_context->space_panning) {
+
+ if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) {
+ return TRUE;
+ }
+
+ Geom::Point const motion_w(event->button.x,
+ event->button.y);
+ Geom::Point const motion_dt(desktop->w2d(motion_w));
+ tc->last_push = desktop->dt2doc(motion_dt);
+
+ sp_spray_extinput(tc, event);
+
+ sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3);
+ tc->is_drawing = true;
+ tc->is_dilating = true;
+ tc->has_dilated = false;
+
+
+
+ if(tc->is_dilating && event->button.button == 1 && !event_context->space_panning)
+
+ sp_spray_dilate (tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT);
+
+
+
+ tc->has_dilated=true;
+
+ ret = TRUE;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ {
+ Geom::Point const motion_w(event->motion.x,
+ event->motion.y);
+ Geom::Point motion_dt(desktop->w2d(motion_w));
+ Geom::Point motion_doc(desktop->dt2doc(motion_dt));
+ sp_spray_extinput(tc, event);
+
+ // draw the dilating cursor
+ double radius = get_dilate_radius(tc);
+ Geom::Matrix const sm (Geom::Scale(radius/(1-tc->ratio), radius/(1+tc->ratio)) );
+ sp_canvas_item_affine_absolute(tc->dilate_area, (sm*Geom::Rotate(tc->tilt))*Geom::Translate(desktop->w2d(motion_w)));
+ sp_canvas_item_show(tc->dilate_area);
+
+ guint num = 0;
+ if (!desktop->selection->isEmpty()) {
+ num = g_slist_length((GSList *) desktop->selection->itemList());
+ }
+ if (num == 0) {
+ tc->_message_context->flash(Inkscape::ERROR_MESSAGE, _("<b>Nothing selected!</b> Select objects to spray."));
+ }
+
+ // dilating:
+ if (tc->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK )) {
+ sp_spray_dilate (tc, motion_w, motion_doc, motion_doc - tc->last_push, event->button.state & GDK_SHIFT_MASK? true : false);
+ //tc->last_push = motion_doc;
+ tc->has_dilated = true;
+
+ // it's slow, so prevent clogging up with events
+ gobble_motion_events(GDK_BUTTON1_MASK);
+ return TRUE;
+ }
+
+ }
+ break;
+/*Spray with the scroll*/
+ case GDK_SCROLL:
+ {
+ if (event->scroll.state & GDK_BUTTON1_MASK)
+ {
+ double temp ;
+ temp=tc->population;
+ tc->population=1.0;
+ desktop->setToolboxAdjustmentValue ("population", tc->population * 100);
+ Geom::Point const scroll_w(event->button.x,event->button.y);
+ Geom::Point const scroll_dt = desktop->point();;
+ Geom::Point motion_doc(desktop->dt2doc(scroll_dt));
+ switch (event->scroll.direction)
+ {
+ case GDK_SCROLL_UP:
+ {
+ if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false)
+ {
+ return TRUE;
+ }
+ tc->last_push = desktop->dt2doc(scroll_dt);
+ sp_spray_extinput(tc, event);
+ sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3);
+ tc->is_drawing = true;
+ tc->is_dilating = true;
+ tc->has_dilated = false;
+ if(tc->is_dilating && !event_context->space_panning)
+
+ sp_spray_dilate (tc, scroll_w, desktop->dt2doc(scroll_dt), Geom::Point(0,0),false);
+
+
+
+ tc->has_dilated=true;
+ tc->population=temp;
+
+ desktop->setToolboxAdjustmentValue ("population", tc->population * 100);
+
+ ret = TRUE;
+ }
+ break;
+ case GDK_SCROLL_DOWN:
+ {
+ if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false)
+ {
+ return TRUE;
+ }
+ tc->last_push = desktop->dt2doc(scroll_dt);
+ sp_spray_extinput(tc, event);
+ sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3);
+ tc->is_drawing = true;
+ tc->is_dilating = true;
+ tc->has_dilated = false;
+ if(tc->is_dilating && !event_context->space_panning)
+ sp_spray_dilate (tc, scroll_w, desktop->dt2doc(scroll_dt), Geom::Point(0,0), false);
+
+ tc->has_dilated=true;
+
+ ret = TRUE;
+
+
+ }
+ break;
+case GDK_SCROLL_RIGHT:
+ {} break;
+case GDK_SCROLL_LEFT:
+ {} break;
+ }
+ }
+
+
+ break;
+
+ }
+ case GDK_BUTTON_RELEASE:
+ {
+ Geom::Point const motion_w(event->button.x, event->button.y);
+ Geom::Point const motion_dt(desktop->w2d(motion_w));
+
+ sp_canvas_end_forced_full_redraws(desktop->canvas);
+ tc->is_drawing = false;
+
+ if (tc->is_dilating && event->button.button == 1 && !event_context->space_panning) {
+ if (!tc->has_dilated) {
+ // if we did not rub, do a light tap
+ tc->pressure = 0.03;
+ sp_spray_dilate (tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT);
+ }
+ tc->is_dilating = false;
+ tc->has_dilated = false;
+ switch (tc->mode) {
+ case SPRAY_MODE_COPY:
+ sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop),
+ SP_VERB_CONTEXT_SPRAY, _("Spray with copies"));
+ break;
+ case SPRAY_MODE_CLONE:
+ sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop),
+ SP_VERB_CONTEXT_SPRAY, _("Spray with clones"));
+ break;
+ case SPRAY_MODE_SINGLE_PATH:
+ sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop),
+ SP_VERB_CONTEXT_SPRAY, _("Spray in single path"));
+ break;
+ }
+ }
+ break;
+ }
+
+ case GDK_KEY_PRESS:
+ switch (get_group0_keyval (&event->key)) {
+case GDK_j: if (MOD__SHIFT_ONLY) {
+ sp_spray_switch_mode(tc, SPRAY_MODE_COPY, MOD__SHIFT);
+ ret = TRUE;
+ }
+case GDK_J: if (MOD__SHIFT_ONLY) {
+ sp_spray_switch_mode(tc, SPRAY_MODE_COPY, MOD__SHIFT);
+ ret = TRUE;
+ }
+
+break;
+ case GDK_m:
+ case GDK_M:
+ case GDK_0:
+
+ break;
+ case GDK_i:
+ case GDK_I:
+ case GDK_k: if (MOD__SHIFT_ONLY) {
+ sp_spray_switch_mode(tc, SPRAY_MODE_SINGLE_PATH, MOD__SHIFT);
+ ret = TRUE;
+ }
+ case GDK_K:if (MOD__SHIFT_ONLY) {
+ sp_spray_switch_mode(tc, SPRAY_MODE_SINGLE_PATH, MOD__SHIFT);
+ ret = TRUE;
+ }
+break;
+
+ case GDK_l: if (MOD__SHIFT_ONLY) {
+ sp_spray_switch_mode(tc, SPRAY_MODE_CLONE, MOD__SHIFT);
+ ret = TRUE;
+ }
+
+ case GDK_L:
+ if (MOD__SHIFT_ONLY) {
+ sp_spray_switch_mode(tc, SPRAY_MODE_CLONE, MOD__SHIFT);
+ ret = TRUE;
+ }
+ break;
+ case GDK_Up:
+ case GDK_KP_Up:
+ if (!MOD__CTRL_ONLY) {
+ tc->scale += 0.05;
+
+ //desktop->setToolboxAdjustmentValue ("spray-force", tc->force * 100);
+ ret = TRUE;
+ }
+ break;
+ case GDK_Down:
+ case GDK_KP_Down:
+ if (!MOD__CTRL_ONLY) {
+
+ tc->scale -= 0.05;
+ if (tc->scale < 0.0)
+ tc->scale = 0.0;
+ //desktop->setToolboxAdjustmentValue ("spray-force", tc->force * 100);
+
+ ret = TRUE;
+
+ }
+ break;
+ case GDK_Right:
+ case GDK_KP_Right:
+ if (!MOD__CTRL_ONLY) {
+ tc->width += 0.01;
+ if (tc->width > 1.0)
+ tc->width = 1.0;
+ desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100); // the same spinbutton is for alt+x
+ sp_spray_update_area(tc);
+ ret = TRUE;
+ }
+ break;
+ case GDK_Left:
+ case GDK_KP_Left:
+ if (!MOD__CTRL_ONLY) {
+ tc->width -= 0.01;
+ if (tc->width < 0.01)
+ tc->width = 0.01;
+ desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100);
+ sp_spray_update_area(tc);
+ ret = TRUE;
+ }
+ break;
+ case GDK_Home:
+ case GDK_KP_Home:
+ tc->width = 0.01;
+ desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100);
+ sp_spray_update_area(tc);
+ ret = TRUE;
+ break;
+ case GDK_End:
+ case GDK_KP_End:
+ tc->width = 1.0;
+ desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100);
+ sp_spray_update_area(tc);
+ ret = TRUE;
+ break;
+ case GDK_x:
+ case GDK_X:
+ if (MOD__ALT_ONLY) {
+ desktop->setToolboxFocusTo ("altx-spray");
+ ret = TRUE;
+ }
+ break;
+
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ sp_spray_update_cursor(tc, true);
+ break;
+/*Set the scale to 1*/
+ case GDK_Control_L:
+ tc->scale=1;
+ default:
+ break;
+ }
+ break;
+
+ case GDK_KEY_RELEASE: {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ switch (get_group0_keyval(&event->key)) {
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ sp_spray_update_cursor(tc, false);
+ break;
+ case GDK_Control_L:
+ case GDK_Control_R:
+ sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT);
+ tc->_message_context->clear();
+ break;
+ default:
+ sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT);
+ break;
+ }
+ }
+
+ default:
+ break;
+ }
+
+ if (!ret) {
+ if (((SPEventContextClass *) parent_class)->root_handler) {
+ ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ 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:encoding=utf-8:textwidth=99 :
+