Updating.
authorFrancois Fleuret <francois@fleuret.org>
Sun, 4 Sep 2016 20:25:53 +0000 (22:25 +0200)
committerFrancois Fleuret <francois@fleuret.org>
Sun, 4 Sep 2016 20:25:53 +0000 (22:25 +0200)
Makefile
main.cc
plotter.cc [new file with mode: 0644]
plotter.h [new file with mode: 0644]
polygon.cc
polygon.h
universe.cc
universe.h

index f4556f8..b5eef5e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -42,8 +42,10 @@ TAGS: *.cc *.h
 main:  main.o misc.o \
        simple_window.o \
        universe.o \
+       plotter.o \
        polygon.o \
        xfig_tracer.o \
+       canvas.o canvas_cairo.o \
        map.o \
        task.o \
        retina.o \
@@ -56,7 +58,7 @@ main:         main.o misc.o \
        $(CXX) $(CXXFLAGS) -shared -Wl,-soname,$@ -o $@ $^
 
 Makefile.depend: *.h *.cc Makefile
-       $(CC) -M *.cc > Makefile.depend
+       $(CC) $(CXXFLAGS) -M *.cc > Makefile.depend
 
 clean:
        \rm -f main *.o *.so Makefile.depend
diff --git a/main.cc b/main.cc
index bbea852..15e97a0 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -20,56 +20,15 @@ using namespace std;
 #include "retina.h"
 #include "manipulator.h"
 #include "intelligence.h"
-#include "xfig_tracer.h"
-
-#ifdef CAIRO_SUPPORT
-#include <cairo.h>
+#include "canvas_cairo.h"
 
-static cairo_status_t write_cairo_to_file(void *closure,
-                                          const unsigned char *data,
-                                          unsigned int length) {
-  fwrite(data, 1, length, (FILE *) closure);
-  return CAIRO_STATUS_SUCCESS;
-}
+#include "xfig_tracer.h"
 
 void generate_png(Universe *universe, scalar_t scale, FILE *file) {
-  const int depth = 4;
-  const int width = int(universe->width() * scale);
-  const int height = int(universe->height() * scale);
-
-  cairo_surface_t *image;
-  cairo_t* context_resource;
-  unsigned char *data;
-
-  data = new unsigned char [width * height * depth];
-
-  image = cairo_image_surface_create_for_data(data,
-                                              CAIRO_FORMAT_RGB24,
-                                              width,
-                                              height,
-                                              width * depth);
-
-  context_resource = cairo_create(image);
-
-  cairo_scale(context_resource, scale, scale);
-
-  cairo_set_source_rgb(context_resource, 1.0, 1.0, 1.0);
-
-  cairo_rectangle(context_resource, 0, 0,
-                  universe->width(), universe->height());
-
-  cairo_fill(context_resource);
-
-  universe->draw(context_resource);
-
-  cairo_surface_write_to_png_stream(image, write_cairo_to_file, file);
-
-  cairo_destroy(context_resource);
-  cairo_surface_destroy(image);
-
-  delete[] data;
+  CanvasCairo canvas(scale, universe->width(), universe->height());
+  universe->draw(&canvas);
+  canvas.write_png(file);
 }
-#endif
 
 // To train
 // ./main --task hit_shape.task 0 --action-mode=random --nb-ticks=5000 --proportion-for-training=0.5 --save-file=dump.mem --no-window
@@ -221,7 +180,7 @@ int main(int argc, char **argv) {
   int window_main_fd = -1;
 
 #ifdef CAIRO_SUPPORT
-  cairo_t *window_main_cairo_cr = 0;
+  // cairo_t *window_main_cairo_cr = 0;
 #endif
 
   MapConcatener sensory_map(2);
@@ -255,7 +214,7 @@ int main(int argc, char **argv) {
     window_main_fd = window_main->file_descriptor();
     window_main->map();
 #ifdef CAIRO_SUPPORT
-    window_main_cairo_cr = window_main->get_cairo_context_resource();
+    // window_main_cairo_cr = window_main->get_cairo_context_resource();
 #endif
     cout << "When the main window has the focus, press `q' to quit and click and drag to move" << endl
          << "objects." << endl;
@@ -348,11 +307,13 @@ int main(int argc, char **argv) {
             window_main->color(1.0, 1.0, 1.0);
             window_main->fill();
 
-#ifdef CAIRO_SUPPORT
-            universe.draw(window_main_cairo_cr);
-#else
+// #ifdef CAIRO_SUPPORT
+            // CanvasCairo cc;
+            // cc._context_resource = window_main_cairo_cr;
+            // universe.draw(&cc);
+// #else
             universe.draw(window_main);
-#endif
+// #endif
 
             task->draw(window_main);
             manipulator.draw_on_universe(window_main);
diff --git a/plotter.cc b/plotter.cc
new file mode 100644 (file)
index 0000000..b546753
--- /dev/null
@@ -0,0 +1,227 @@
+
+// Written and (C) by Francois Fleuret
+// Contact <francois.fleuret@idiap.ch> for comments & bug reports
+
+#include "plotter.h"
+
+Plotter::Plotter(int width, int height, int scaling) {
+  _scaling = scaling;
+  _width = width * _scaling;
+  _height = height * _scaling;
+
+  _tag_map = new Tag *[_width * _height];
+  _tag_stack = new Tag[_width * _height];
+
+  _red_imap = new scalar_t[(_width + 1) * (_height + 1)];
+  _green_imap = new scalar_t[(_width + 1) * (_height + 1)];
+  _blue_imap = new scalar_t[(_width + 1) * (_height + 1)];
+
+  reset();
+}
+
+Plotter::~Plotter() {
+  delete[] _tag_map;
+  delete[] _tag_stack;
+  delete[] _red_imap;
+  delete[] _green_imap;
+  delete[] _blue_imap;
+}
+
+void Plotter::reset() {
+  for(int k = 0; k < _width * _height; k++) {
+    _tag_map[k] = 0;
+  }
+  _tag_stack_top = _tag_stack;
+  _current_polygon = 0;
+}
+
+void Plotter::draw_polygon(Polygon *p) {
+  int nb = p->_nb_vertices;
+
+  int ix[nb], iy[nb];
+
+  for(int n = 0; n < nb; n++) {
+    ix[n] = int(p->_x[n] * scalar_t(_scaling) + 0.5);
+    iy[n] = int(p->_y[n] * scalar_t(_scaling) + 0.5);
+  }
+
+  scalar_t red = p->_red;
+  scalar_t green = p->_green;
+  scalar_t blue = p->_blue;
+
+  int direction;
+
+  if(iy[0] > iy[nb-1]) direction = 1;
+  else if(iy[0] < iy[nb-1]) direction = -1;
+  else direction = 0;
+
+  for(int n = 0; n < nb; n++) {
+    int m = (n+1)%nb;
+
+    if(ix[n] >= 0 && ix[n] < _width && iy[n] >= 0 && iy[n] < _height &&
+       ix[m] >= 0 && ix[m] < _width && iy[m] >= 0 && iy[m] < _height) {
+
+      if(iy[m] > iy[n]) { // RIGHT BORDERS
+
+        if(direction < 0) {
+          push_tag(1 + ix[n], iy[n], red, green, blue);
+        }
+
+        for(int y = iy[n] + 1; y <= iy[m]; y++) {
+          push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
+                   red, green, blue);
+        }
+
+        direction = 1;
+
+      } else if(iy[m] < iy[n]) { // LEFT BORDERS
+
+        if(direction >= 0) {
+          push_tag(ix[n], iy[n], red, green, blue);
+        }
+
+        for(int y = iy[n] - 1; y >= iy[m]; y--) {
+          push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
+                   red, green, blue);
+        }
+
+        direction = -1;
+
+      } else {
+
+        if(direction >= 0) push_tag(ix[n]+1, iy[n], red, green, blue);
+        push_tag(ix[m], iy[m], red, green, blue);
+        direction = 0;
+
+      }
+
+    } else {
+
+      if(iy[m] > iy[n]) { // RIGHT BORDERS
+
+        if(direction < 0) {
+          protected_push_tag(1 + ix[n], iy[n], red, green, blue);
+        }
+
+        for(int y = iy[n] + 1; y <= iy[m]; y++) {
+          protected_push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
+                             red, green, blue);
+        }
+
+        direction = 1;
+
+      } else if(iy[m] < iy[n]) { // LEFT BORDERS
+
+        if(direction >= 0) {
+          protected_push_tag(ix[n], iy[n], red, green, blue);
+        }
+
+        for(int y = iy[n] - 1; y >= iy[m]; y--) {
+          protected_push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
+                             red, green, blue);
+        }
+
+        direction = -1;
+
+      } else {
+
+        if(direction >= 0) {
+          protected_push_tag(ix[n]+1, iy[n], red, green, blue);
+        }
+
+        protected_push_tag(ix[m], iy[m], red, green, blue);
+
+        direction = 0;
+      }
+    }
+  }
+
+  _current_polygon++;
+}
+
+void Plotter::fill() {
+  bool in[_current_polygon];
+  for(int p = 0; p < _current_polygon; p++) in[p] = false;
+
+  scalar_t red[_current_polygon], green[_current_polygon], blue[_current_polygon];
+  Tag **u = _tag_map;
+
+  int lk = 0, k = 0;
+
+  for(int x = 0; x < _width+1; x++) {
+    _red_imap[k] = 0;
+    _green_imap[k] = 0;
+    _blue_imap[k] = 0;
+    k++;
+  }
+
+  int current_index = -1;
+  for(int y = 0; y < _height; y++) {
+    scalar_t sred = 0, sgreen = 0, sblue = 0;
+    _red_imap[k] = 0;
+    _green_imap[k] = 0;
+    _blue_imap[k] = 0;
+    k++; lk++;
+
+    for(int x = 0; x < _width; x++) {
+      for(Tag *t = *u; t; t = t->next) {
+        if(in[t->index]) {
+          in[t->index] = false;
+          if(t->index == current_index) {
+            current_index--;
+            while(current_index >= 0 && !in[current_index]) current_index--;
+          }
+        } else {
+          in[t->index] = true;
+          red[t->index] = t->red;
+          green[t->index] = t->green;
+          blue[t->index] = t->blue;
+          if(t->index > current_index) current_index = t->index;
+        }
+      }
+
+      if(current_index >= 0) {
+        sred += red[current_index];
+        sgreen += green[current_index];
+        sblue += blue[current_index];
+      }
+
+      _red_imap[k] = sred + _red_imap[lk];
+      _green_imap[k] = sgreen + _green_imap[lk];
+      _blue_imap[k] = sblue + _blue_imap[lk];
+
+      k++; lk++;
+      u++;
+    }
+  }
+}
+
+void Plotter::save_as_ppm(Universe *universe, const char *filename) {
+  reset();
+  for(int p = 0; p < universe->_nb_polygons; p++) {
+    if(universe->_polygons[p]) {
+      draw_polygon(universe->_polygons[p]);
+    }
+  }
+  fill();
+
+  unsigned char *image = new unsigned char[_width * _height * 3];
+
+  int n = 0;
+  for(int y = 0; y < _height / _scaling; y++) {
+    for(int x = 0; x < _width / _scaling; x++) {
+      image[n++] = red_sum(x * _scaling, y * _scaling, (x + 1) * _scaling, (y + 1) * _scaling) / scalar_t(_scaling * _scaling);
+      image[n++] = green_sum(x * _scaling, y * _scaling, (x + 1) * _scaling, (y + 1) * _scaling) / scalar_t(_scaling * _scaling);
+      image[n++] = blue_sum(x * _scaling, y * _scaling, (x + 1) * _scaling, (y + 1) * _scaling) / scalar_t(_scaling * _scaling);
+    }
+  }
+
+  ofstream out(filename);
+  out << "P6" << endl;
+  out << _width << " " << _height << endl;
+  out << 255 << endl;
+  out.write((char *) image, _width * _height * 3);
+  out.flush();
+
+  delete[] image;
+}
diff --git a/plotter.h b/plotter.h
new file mode 100644 (file)
index 0000000..d93490d
--- /dev/null
+++ b/plotter.h
@@ -0,0 +1,96 @@
+
+// Written and (C) by Francois Fleuret
+// Contact <francois.fleuret@idiap.ch> for comments & bug reports
+
+#ifndef PLOTTER_H
+#define PLOTTER_H
+
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+#include "misc.h"
+#include "universe.h"
+
+class Plotter {
+  int _width, _height;
+
+  class Tag {
+  public:
+    int index;
+    scalar_t red, green, blue;
+    Tag *next;
+  };
+
+  Tag **_tag_map;
+
+  // We have our own stack of tags to avoid numerous news and deletes
+  Tag *_tag_stack, *_tag_stack_top;
+  scalar_t *_red_imap, *_green_imap, *_blue_imap;
+  int _current_polygon;
+  int _scaling;
+
+  inline void protected_push_tag(int x, int y, scalar_t r, scalar_t g, scalar_t b) {
+    if(y >= 0 && y < _height) {
+
+      if(x < 0) { x = 0; }
+      else if(x >= _width) { x = _width - 1; }
+
+      int t = y * _width + x;
+
+      _tag_stack_top->next = _tag_map[t];
+      _tag_stack_top->index = _current_polygon;
+      _tag_stack_top->red = r;
+      _tag_stack_top->green = g;
+      _tag_stack_top->blue = b;
+      _tag_map[t] = _tag_stack_top;
+      _tag_stack_top++;
+    }
+  }
+
+  inline void push_tag(int x, int y, scalar_t r, scalar_t g, scalar_t b) {
+    int t = y * _width + x;
+    _tag_stack_top->next = _tag_map[t];
+    _tag_stack_top->index = _current_polygon;
+    _tag_stack_top->red = r;
+    _tag_stack_top->green = g;
+    _tag_stack_top->blue = b;
+    _tag_map[t] = _tag_stack_top;
+    _tag_stack_top++;
+  }
+
+  inline scalar_t red_sum(int xmin, int ymin, int xmax, int ymax) {
+    return _red_imap[xmax + (_width + 1) * ymax]
+      + _red_imap[xmin + (_width + 1) * ymin]
+      - _red_imap[xmax + (_width + 1) * ymin]
+      - _red_imap[xmin + (_width + 1) * ymax];
+  }
+
+  inline scalar_t green_sum(int xmin, int ymin, int xmax, int ymax) {
+    return _green_imap[xmax + (_width + 1) * ymax]
+      + _green_imap[xmin + (_width + 1) * ymin]
+      - _green_imap[xmax + (_width + 1) * ymin]
+      - _green_imap[xmin + (_width + 1) * ymax];
+  }
+
+  inline scalar_t blue_sum(int xmin, int ymin, int xmax, int ymax) {
+    return _blue_imap[xmax + (_width + 1) * ymax]
+      + _blue_imap[xmin + (_width + 1) * ymin]
+      - _blue_imap[xmax + (_width + 1) * ymin]
+      - _blue_imap[xmin + (_width + 1) * ymax];
+  }
+
+  void reset();
+
+  void draw_polygon(Polygon *p);
+  void fill();
+public:
+
+  Plotter(int width, int height, int scaling);
+  ~Plotter();
+
+  void save_as_ppm(Universe *universe, const char *filename);
+};
+
+#endif
index e121e2c..4068919 100644 (file)
@@ -81,31 +81,15 @@ void Polygon::draw_contours(SimpleWindow *window) {
 }
 #endif
 
-#ifdef CAIRO_SUPPORT
-void Polygon::draw(cairo_t* context_resource) {
-  cairo_set_line_width(context_resource, 1.0);
-  cairo_set_source_rgb (context_resource, _red, _green, _blue);
-  cairo_move_to(context_resource, _x[0], _y[0]);
-  for(int n = 0; n < _nb_vertices; n++) {
-    cairo_line_to(context_resource, _x[n], _y[n]);
-  }
-  cairo_close_path(context_resource);
-  cairo_stroke_preserve(context_resource);
-  cairo_fill(context_resource);
+void Polygon::draw(Canvas *canvas) {
+  canvas->set_drawing_color(_red, _green, _blue);
+  canvas->draw_polygon(1, _nb_vertices, _x, _y);
 }
 
-void Polygon::draw_contours(cairo_t* context_resource) {
-  cairo_set_line_width(context_resource, 1.0);
-  cairo_set_source_rgb (context_resource, 0.0, 0.0, 0.0);
-  // cairo_set_source_rgb (context_resource, 1.0, 1.0, 1.0);
-  cairo_move_to(context_resource, _x[0], _y[0]);
-  for(int n = 0; n < _nb_vertices; n++) {
-    cairo_line_to(context_resource, _x[n], _y[n]);
-  }
-  cairo_close_path(context_resource);
-  cairo_stroke(context_resource);
+void Polygon::draw_contours(Canvas *canvas) {
+  canvas->set_drawing_color(0.0, 0.0, 0.0);
+  canvas->draw_polygon(0, _nb_vertices, _x, _y);
 }
-#endif
 
 void Polygon::set_vertex(int k, scalar_t x, scalar_t y) {
   _relative_x[k] = x;
@@ -209,7 +193,9 @@ void Polygon::initialize(int nb_polygons) {
 
   _nb_polygons = nb_polygons;
 
-  a = _relative_x[_nb_vertices - 1] * _relative_y[0] - _relative_x[0] * _relative_y[_nb_vertices - 1];
+  a = _relative_x[_nb_vertices - 1] * _relative_y[0]
+    - _relative_x[0] * _relative_y[_nb_vertices - 1];
+
   for(int n = 0; n < _nb_vertices - 1; n++)
     a += _relative_x[n] * _relative_y[n+1] - _relative_x[n+1] * _relative_y[n];
   a *= 0.5;
index 48e6d3b..5a000be 100644 (file)
--- a/polygon.h
+++ b/polygon.h
@@ -6,16 +6,14 @@
 #define POLYGON_H
 
 #include "misc.h"
+#include "canvas.h"
+
 #include "xfig_tracer.h"
 
 #ifdef X11_SUPPORT
 #include "simple_window.h"
 #endif
 
-#ifdef CAIRO_SUPPORT
-#include <cairo.h>
-#endif
-
 class Polygon {
   struct Triangle {
     int a, b, c;
@@ -81,10 +79,8 @@ public:
   void draw_contours(SimpleWindow *window);
 #endif
 
-#ifdef CAIRO_SUPPORT
-  void draw(cairo_t* context_resource);
-  void draw_contours(cairo_t* context_resource);
-#endif
+  void draw(Canvas *canvas);
+  void draw_contours(Canvas *canvas);
 
   void set_vertex(int k, scalar_t x, scalar_t y);
   void set_position(scalar_t center_x, scalar_t center_y, scalar_t theta);
index 92b7a1b..55e1a6d 100644 (file)
@@ -7,8 +7,10 @@
 #include "universe.h"
 
 Universe::Universe(int nb_max_polygons,
-                   scalar_t width, scalar_t height) : _width(width), _height(height),
-                                                   _nb_max_polygons(nb_max_polygons), _nb_polygons(0) {
+                   scalar_t width, scalar_t height) : _width(width),
+                                                      _height(height),
+                                                      _nb_max_polygons(nb_max_polygons),
+                                                      _nb_polygons(0) {
   _polygons = new Polygon *[_nb_max_polygons];
   for(int n = 0; n < _nb_max_polygons; n++) _polygons[n] = 0;
 }
@@ -145,21 +147,19 @@ void Universe::draw(SimpleWindow *window) {
 }
 #endif
 
-#ifdef CAIRO_SUPPORT
-void Universe::draw(cairo_t *context_resource) {
+void Universe::draw(Canvas *canvas) {
   for(int n = 0; n < _nb_polygons; n++) {
     if(_polygons[n]) {
-      _polygons[n]->draw(context_resource);
+      _polygons[n]->draw(canvas);
     }
   }
 
   for(int n = 0; n < _nb_polygons; n++) {
     if(_polygons[n]) {
-      _polygons[n]->draw_contours(context_resource);
+      _polygons[n]->draw_contours(canvas);
     }
   }
 }
-#endif
 
 void Universe::apply_collision_forces(scalar_t dt) {
   const int nb_axis = 2;
index a9f55d7..b164d0b 100644 (file)
@@ -9,16 +9,13 @@
 #include <cmath>
 
 #include "misc.h"
+#include "canvas.h"
 #include "polygon.h"
 
 #ifdef X11_SUPPORT
 #include "simple_window.h"
 #endif
 
-#ifdef CAIRO_SUPPORT
-#include <cairo.h>
-#endif
-
 using namespace std;
 
 class Universe {
@@ -53,9 +50,7 @@ public:
   void draw(SimpleWindow *window);
 #endif
 
-#ifdef CAIRO_SUPPORT
-  void draw(cairo_t *context_resource);
-#endif
+  void draw(Canvas *canvas);
 };
 
 #endif