add new comparison method rgb_difference that resembles arithmetical difference per...
[imager.git] / draw.c
diff --git a/draw.c b/draw.c
index 9103c78..647c9d2 100644 (file)
--- a/draw.c
+++ b/draw.c
@@ -500,8 +500,11 @@ i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r,
   i_color temp;
   i_img_dim ly;
   dIMCTXim(im);
-  i_img_dim first_row = floor(y) - ceil(rad);
-  i_img_dim last_row = ceil(y) + ceil(rad);
+  double ceil_rad = ceil(rad);
+  i_img_dim first_row = floor(y) - ceil_rad;
+  i_img_dim last_row = ceil(y) + ceil_rad;
+  i_img_dim first_col = floor(x) - ceil_rad;
+  i_img_dim last_col = ceil(x) + ceil_rad;
   double r_sqr = rad * rad;
   i_img_dim max_width = 2 * ceil(rad) + 1;
   unsigned char *coverage = NULL;
@@ -515,8 +518,12 @@ i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r,
     first_row = 0;
   if (last_row > im->ysize-1)
     last_row = im->ysize - 1;
+  if (first_col < 0)
+    first_col = 0;
+  if (last_col > im->xsize-1)
+    last_col = im->xsize - 1;
 
-  if (rad <= 0 || last_row < first_row) {
+  if (rad <= 0 || last_row < first_row || last_col < first_col) {
     /* outside the image */
     return;
   }
@@ -527,9 +534,9 @@ i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r,
   for(ly = first_row; ly < last_row; ly++) {
     frac min_frac_x[16];
     frac max_frac_x[16];
-    i_img_dim min_frac_left_x = im->xsize * 16;
+    i_img_dim min_frac_left_x = 16 *(ceil(x) + ceil(rad));
     i_img_dim max_frac_left_x = -1;
-    i_img_dim min_frac_right_x = im->xsize * 16;
+    i_img_dim min_frac_right_x = 16 * (floor(x) - ceil(rad));
     i_img_dim max_frac_right_x = -1;
     /* reset work_y each row so the error doesn't build up */
     double work_y = ly;
@@ -1760,10 +1767,36 @@ i_rspan(i_img *im, i_img_dim seedx, i_img_dim seedy, i_color const *val, ff_cmpf
   return seedx;
 }
 
+#ifdef DEBUG_FLOOD_FILL
+
+#define ST_PUSH_NOTE(left, right, dadl, dadr, y, dir) \
+  fprintf(stderr, "push(left %" i_DF ", right %" i_DF ", dadleft %" i_DF  ", dadright %" i_DF ", y %" i_DF ", dir %d, line %d)\n", \
+         i_DFc(left), i_DFc(right), i_DFc(dadl), i_DFc(dadr), i_DFc(y), (dir), __LINE__)
+
+#define ST_POP_NOTE(left, right, dadl, dadr, y, dir) \
+  fprintf(stderr, "popped(left %" i_DF ", right %" i_DF ", dadleft %" i_DF  ", dadright %" i_DF ", y %" i_DF ", dir %d, line %d)\n", \
+         i_DFc(left), i_DFc(right), i_DFc(dadl), i_DFc(dadr), i_DFc(y), (dir), __LINE__)
+
+#define ST_STACK_NOTE(dadl, dadr, left, right, y, dir)                 \
+  fprintf(stderr, "stack(left %" i_DF ", right %" i_DF ", dadleft %" i_DF  ", dadright %" i_DF ", y %" i_DF ", dir %d, line %d)\n", \
+         i_DFc(left), i_DFc(right), i_DFc(dadl), i_DFc(dadr), i_DFc(y), (dir), __LINE__)
+
+#else
+
+#define ST_PUSH_NOTE(left, right, dadl, dadr, y, dir)
+
+#define ST_POP_NOTE(left, right, dadl, dadr, y, dir)
+
+#define ST_STACK_NOTE(dadl, dadr, left, right, y, dir)
+
+#endif
+
+
 /* Macro to create a link and push on to the list */
 
 #define ST_PUSH(left,right,dadl,dadr,y,dir) do {                 \
   struct stack_element *s = crdata(left,right,dadl,dadr,y,dir);  \
+  ST_PUSH_NOTE(left, right, dadl, dadr, y, dir);                \
   llist_push(st,&s);                                             \
 } while (0)
 
@@ -1779,24 +1812,28 @@ i_rspan(i_img *im, i_img_dim seedx, i_img_dim seedy, i_color const *val, ff_cmpf
   dadRx     = s->dadRx;       \
   y         = s->myY;         \
   direction = s->myDirection; \
+  ST_POP_NOTE(lx, rx, dadLx, dadRx, y, direction);     \
   myfree(s);                  \
 } while (0)
 
 #define ST_STACK(dir,dadLx,dadRx,lx,rx,y) do {                    \
   i_img_dim pushrx = rx+1;                                              \
   i_img_dim pushlx = lx-1;                                              \
+  ST_STACK_NOTE(lx, rx, dadLx, dadRx, y, dir);          \
   ST_PUSH(lx,rx,pushlx,pushrx,y+dir,dir);                         \
   if (rx > dadRx)                                                 \
     ST_PUSH(dadRx+1,rx,pushlx,pushrx,y-dir,-dir);                 \
-  if (lx < dadLx) ST_PUSH(lx,dadLx-1,pushlx,pushrx,y-dir,-dir);   \
+  if (lx < dadLx)                                              \
+    ST_PUSH(lx,dadLx-1,pushlx,pushrx,y-dir,-dir);   \
 } while (0)
 
 #define SET(x,y) btm_set(btm,x,y)
 
 /* INSIDE returns true if pixel is correct color and we haven't set it before. */
-#define INSIDE(x,y, seed) ((!btm_test(btm,x,y) && ( i_gpix(im,x,y,&cval),cmpfunc(seed,&cval,channels)  ) ))
-
-
+#define INSIDE(x,y, seed) \
+  (assert((x) >= 0 && (x) < (im)->xsize && (y) >= 0 && (y) < (im)->ysize), \
+   (!btm_test(btm,x,y) && \
+     ( i_gpix(im,x,y,&cval),cmpfunc(seed,&cval,channels)  ) ))
 
 /* The function that does all the real work */
 
@@ -1817,7 +1854,7 @@ i_flood_fill_low(i_img *im,i_img_dim seedx,i_img_dim seedy,
 
   int channels;
   i_img_dim xsize,ysize;
-  i_color cval;
+  i_color cval; /* used by the INSIDE() macro */
 
   channels = im->channels;
   xsize    = im->xsize;
@@ -1862,6 +1899,8 @@ i_flood_fill_low(i_img *im,i_img_dim seedx,i_img_dim seedy,
        SET(lx,y);
        lx--;
       }
+      /* lx should point at the left-most INSIDE() pixel */
+      ++lx;
     }
 
     if (bxmin > lx) bxmin = lx;