Code

use touchpath selection when rubberbanding with Alt; do move-selected with Alt only...
[inkscape.git] / src / trace / trace.cpp
index d40fb89d7e67567b2e112c53ec1824e85c78d67f..925e4e195de41aa2068d7f20fc56645ab0197563 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/**
  * A generic interface for plugging different
  *  autotracers into Inkscape.
  *
@@ -19,6 +19,7 @@
 #include <desktop-handles.h>
 #include <document.h>
 #include <message-stack.h>
+#include <gtkmm.h>
 #include <glibmm/i18n.h>
 #include <selection.h>
 #include <xml/repr.h>
@@ -45,7 +46,6 @@ namespace Trace
 
 
 
-
 /**
  * Get the selected image.  Also check for any SPItems over it, in
  * case the user wants SIOX pre-processing.
@@ -57,7 +57,7 @@ Tracer::getSelectedSPImage()
     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
     if (!desktop)
         {
-        g_warning("Trace: No active desktop\n");
+        g_warning("Trace: No active desktop");
         return NULL;
         }
 
@@ -155,23 +155,82 @@ Tracer::getSelectedSPImage()
 
 
 typedef org::siox::SioxImage SioxImage;
+typedef org::siox::SioxObserver SioxObserver;
 typedef org::siox::Siox Siox;
 
-GdkPixbuf *
-Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
+
+class TraceSioxObserver : public SioxObserver
+{
+public:
+
+    /**
+     *
+     */
+    TraceSioxObserver (void *contextArg) :
+                     SioxObserver(contextArg)
+        {}
+
+    /**
+     *
+     */
+    virtual ~TraceSioxObserver ()
+        { }
+
+    /**
+     *  Informs the observer how much has been completed.
+     *  Return false if the processing should be aborted.
+     */
+    virtual bool progress(float percentCompleted)
+        {
+        //Tracer *tracer = (Tracer *)context;
+        //## Allow the GUI to update
+        Gtk::Main::iteration(false); //at least once, non-blocking
+        while( Gtk::Main::events_pending() )
+            Gtk::Main::iteration();
+        return true;
+        }
+
+    /**
+     *  Send an error string to the Observer.  Processing will
+     *  be halted.
+     */
+    virtual void error(const std::string &msg)
+        {
+        //Tracer *tracer = (Tracer *)context;
+        }
+
+
+};
+
+
+
+
+
+/**
+ * Process a GdkPixbuf, according to which areas have been
+ * obscured in the GUI.
+ */
+Glib::RefPtr<Gdk::Pixbuf>
+Tracer::sioxProcessImage(SPImage *img,
+             Glib::RefPtr<Gdk::Pixbuf>origPixbuf)
 {
     if (!sioxEnabled)
         return origPixbuf;
 
+    if (origPixbuf == lastOrigPixbuf)
+        return lastSioxPixbuf;
+
+    //g_message("siox: start");
+
     //Convert from gdk, so a format we know.  By design, the pixel
     //format in PackedPixelMap is identical to what is needed by SIOX
-    SioxImage simage(origPixbuf);
+    SioxImage simage(origPixbuf->gobj());
 
     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
     if (!desktop)
         {
-        g_warning("Trace: No active desktop\n");
-        return NULL;
+        g_warning(_("Trace: No active desktop"));
+        return Glib::RefPtr<Gdk::Pixbuf>(NULL);
         }
 
     Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
@@ -182,7 +241,7 @@ Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
         char *msg = _("Select an <b>image</b> to trace");
         msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
         //g_warning(msg);
-        return NULL;
+        return Glib::RefPtr<Gdk::Pixbuf>(NULL);
         }
 
     NRArenaItem *aImg = sp_item_get_arenaitem(img, desktop->dkey);
@@ -203,20 +262,18 @@ Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
     for (iter = sioxShapes.begin() ; iter!=sioxShapes.end() ; iter++)
         {
         SPItem *item = *iter;
-        //### Create ArenaItems and set transform
         NRArenaItem *aItem = sp_item_get_arenaitem(item, desktop->dkey);
-
-        //nr_arena_item_set_transform(aItem, item->transform);
-        //g_message("%d %d %d %d\n", aItem->bbox.x0, aItem->bbox.y0,
-        //                           aItem->bbox.x1, aItem->bbox.y1);
         arenaItems.push_back(aItem);
         }
+
     //g_message("%d arena items\n", arenaItems.size());
 
-    PackedPixelMap *dumpMap = PackedPixelMapCreate(
-                    simage.getWidth(), simage.getHeight());
+    //PackedPixelMap *dumpMap = PackedPixelMapCreate(
+    //                simage.getWidth(), simage.getHeight());
+
+    //g_message("siox: start selection");
 
-    for (int row=0 ; row<simage.getHeight() ; row++)
+    for (int row=0 ; row<iheight ; row++)
         {
         double ypos = ((double)aImg->bbox.y0) + ihscale * (double) row;
         for (int col=0 ; col<simage.getWidth() ; col++)
@@ -227,7 +284,6 @@ Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
             point *= aImg->transform;
             //point *= imgMat;
             //point = desktop->doc2dt(point);
-            std::vector<SPShape *>::iterator iter;
             //g_message("x:%f    y:%f\n", point[0], point[1]);
             bool weHaveAHit = false;
             std::vector<NRArenaItem *>::iterator aIter;
@@ -246,31 +302,34 @@ Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
             if (weHaveAHit)
                 {
                 //g_message("hit!\n");
-                dumpMap->setPixelLong(dumpMap, col, row, 0L);
+                //dumpMap->setPixelLong(dumpMap, col, row, 0L);
                 simage.setConfidence(col, row, 
                         Siox::UNKNOWN_REGION_CONFIDENCE);
                 }
             else
                 {
-                dumpMap->setPixelLong(dumpMap, col, row,
-                        simage.getPixel(col, row));
+                //g_message("miss!\n");
+                //dumpMap->setPixelLong(dumpMap, col, row,
+                //        simage.getPixel(col, row));
                 simage.setConfidence(col, row,
                         Siox::CERTAIN_BACKGROUND_CONFIDENCE);
                 }
             }
         }
 
+    //g_message("siox: selection done");
+
     //dumpMap->writePPM(dumpMap, "siox1.ppm");
-    dumpMap->destroy(dumpMap);
+    //dumpMap->destroy(dumpMap);
 
     //## ok we have our pixel buf
-    org::siox::Siox sengine;
-    org::siox::SioxImage result =
-            sengine.extractForeground(simage, 0xffffff);
+    TraceSioxObserver observer(this);
+    Siox sengine(&observer);
+    SioxImage result = sengine.extractForeground(simage, 0xffffff);
     if (!result.isValid())
         {
-        g_warning("Invalid SIOX result");
-        return NULL;
+        g_warning(_("Invalid SIOX result"));
+        return Glib::RefPtr<Gdk::Pixbuf>(NULL);
         }
 
     //result.writePPM("siox2.ppm");
@@ -286,7 +345,11 @@ Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
     nr_object_unref((NRObject *) arena);
     */
 
-    GdkPixbuf *newPixbuf = result.getGdkPixbuf();
+    Glib::RefPtr<Gdk::Pixbuf> newPixbuf = Glib::wrap(result.getGdkPixbuf());
+
+    //g_message("siox: done");
+
+    lastSioxPixbuf = newPixbuf;
 
     return newPixbuf;
 }
@@ -295,24 +358,27 @@ Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
 /**
  *
  */
-GdkPixbuf *
+Glib::RefPtr<Gdk::Pixbuf>
 Tracer::getSelectedImage()
 {
 
+
     SPImage *img = getSelectedSPImage();
     if (!img)
-        return NULL;
+        return Glib::RefPtr<Gdk::Pixbuf>(NULL);
 
-    GdkPixbuf *pixbuf = img->pixbuf;
-    if (!pixbuf)
-        return NULL;
+    if (!img->pixbuf)
+        return Glib::RefPtr<Gdk::Pixbuf>(NULL);
+
+    Glib::RefPtr<Gdk::Pixbuf> pixbuf =
+          Glib::wrap(img->pixbuf, true);
 
     if (sioxEnabled)
         {
-        GdkPixbuf *sioxPixbuf = sioxProcessImage(img, pixbuf);
+        Glib::RefPtr<Gdk::Pixbuf> sioxPixbuf =
+             sioxProcessImage(img, pixbuf);
         if (!sioxPixbuf)
             {
-            g_object_ref(pixbuf);
             return pixbuf;
             }
         else
@@ -322,7 +388,6 @@ Tracer::getSelectedImage()
         }
     else
         {
-        g_object_ref(pixbuf);
         return pixbuf;
         }
 
@@ -385,8 +450,7 @@ void Tracer::traceThread()
         return;
         }
 
-    GdkPixbuf *pixbuf = img->pixbuf;
-    g_object_ref(pixbuf);
+    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(img->pixbuf, true);
 
     pixbuf = sioxProcessImage(img, pixbuf);
 
@@ -399,12 +463,16 @@ void Tracer::traceThread()
         return;
         }
 
-    int nrPaths;
-    TracingEngineResult *results = engine->trace(pixbuf, &nrPaths);
-    //printf("nrPaths:%d\n", nrPaths);
+    msgStack->flash(Inkscape::NORMAL_MESSAGE, _("Trace: Starting trace..."));
+    desktop->updateCanvasNow();
+    
+    std::vector<TracingEngineResult> results =
+                engine->trace(pixbuf);
+    //printf("nrPaths:%d\n", results.size());
+    int nrPaths = results.size();
 
     //### Check if we should stop
-    if (!keepGoing || !results || nrPaths<1)
+    if (!keepGoing || nrPaths<1)
         {
         engine = NULL;
         return;
@@ -433,8 +501,8 @@ void Tracer::traceThread()
 
     NR::Matrix trans(NR::translate(x, y));
 
-    double iwidth  = (double)gdk_pixbuf_get_width(pixbuf);
-    double iheight = (double)gdk_pixbuf_get_height(pixbuf);
+    double iwidth  = (double)pixbuf->get_width();
+    double iheight = (double)pixbuf->get_height();
 
     double iwscale = width  / iwidth;
     double ihscale = height / iheight;
@@ -449,25 +517,26 @@ void Tracer::traceThread()
 
     //#OK.  Now let's start making new nodes
 
+    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc());
     Inkscape::XML::Node *groupRepr = NULL;
 
     //# if more than 1, make a <g>roup of <path>s
     if (nrPaths > 1)
         {
-        groupRepr = sp_repr_new("svg:g");
+        groupRepr = xml_doc->createElement("svg:g");
         par->addChild(groupRepr, imgRepr);
         }
 
     long totalNodeCount = 0L;
 
-    for (TracingEngineResult *result=results ;
-                  result ; result=result->next)
+    for (unsigned int i=0 ; i<results.size() ; i++)
         {
-        totalNodeCount += result->getNodeCount();
+        TracingEngineResult result = results[i];
+        totalNodeCount += result.getNodeCount();
 
-        Inkscape::XML::Node *pathRepr = sp_repr_new("svg:path");
-        pathRepr->setAttribute("style", result->getStyle());
-        pathRepr->setAttribute("d",     result->getPathData());
+        Inkscape::XML::Node *pathRepr = xml_doc->createElement("svg:path");
+        pathRepr->setAttribute("style", result.getStyle().c_str());
+        pathRepr->setAttribute("d",     result.getPathData().c_str());
 
         if (nrPaths > 1)
             groupRepr->addChild(pathRepr, NULL);
@@ -489,11 +558,6 @@ void Tracer::traceThread()
         Inkscape::GC::release(pathRepr);
         }
 
-    //release our pixbuf
-    g_object_unref(pixbuf);
-
-    delete results;
-
     // If we have a group, then focus on, then forget it
     if (nrPaths > 1)
         {
@@ -503,7 +567,7 @@ void Tracer::traceThread()
         }
 
     //## inform the document, so we can undo
-    sp_document_done(doc);
+    sp_document_done(doc, SP_VERB_SELECTION_TRACE, _("Trace bitmap"));
 
     engine = NULL;