prepare cobboard and ballboard
[aversive.git] / projects / microb2010 / sensorboard / img_processing.c
diff --git a/projects/microb2010/sensorboard/img_processing.c b/projects/microb2010/sensorboard/img_processing.c
deleted file mode 100644 (file)
index d030478..0000000
+++ /dev/null
@@ -1,1619 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include <aversive/pgmspace.h>
-#include <aversive/error.h>
-
-#include <stdint.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include <vect_base.h>
-#include <lines.h>
-#include <polygon.h>
-
-#include "img_processing.h"
-
-
-#define debug_printf(fmt, ...) printf_P(PSTR(fmt), ##__VA_ARGS__)
-
-#ifndef HOST_VERSION
-
-#include <aversive.h>
-#include <pwm_ng.h>
-#include <pid.h>
-#include <time.h>
-#include <quadramp.h>
-#include <blocking_detection_manager.h>
-#include <rdline.h>
-
-#include <control_system_manager.h>
-#include <adc.h>
-#include <spi.h>
-#include <ax12.h>
-
-#include "main.h"
-
-#define IMG_DEBUG(args...) DEBUG(E_USER_IMGPROCESS, args)
-#define IMG_NOTICE(args...) NOTICE(E_USER_IMGPROCESS, args)
-#define IMG_ERROR(args...) ERROR(E_USER_IMGPROCESS, args)
-
-#else
-
-#define IMG_DEBUG(args...) debug_printf(args)
-#define IMG_NOTICE(args...) debug_printf(args)
-#define IMG_ERROR(args...) debug_printf(args)
-
-#endif
-
-
-
-
-#define OBJECT_MINIMUM_DEMI_PERIMETER (2*3)
-/* store object in pool if never seen 
- * returns:
- * 1 if new object
- * 0 if already known
- */
-int store_obj(Object_bb* tab_o,  int total, Object_bb*o)
-{
-       uint8_t i;
-
-       if (o->x_max - o->x_min + o->y_max - o->y_min < OBJECT_MINIMUM_DEMI_PERIMETER) 
-               return 0;
-
-       for (i=0;i<total;i++){
-               if (!memcmp(&tab_o[i], o, sizeof(Object_bb)))
-                       return 0;
-                       
-               if (tab_o[i].x_min==0 && tab_o[i].x_max==0 && 
-                   tab_o[i].y_min==0 && tab_o[i].y_max==0){
-                       memcpy(&tab_o[i], o, sizeof(Object_bb));
-                       return 1;
-               }
-                       
-       }
-       return 0;
-}
-
-/* step around object of given color and compute its bounding box */
-void object_find_bounding_box(unsigned char* data, 
-                             int16_t x_in, int16_t y_in, 
-                             int16_t start_x, int16_t start_y, 
-                             int16_t color, int16_t color_w,Object_bb* o)
-{
-       int16_t pos_x = start_x;
-       int16_t pos_y = start_y;
-       int16_t start =0;
-       int16_t len = 0;
-       int16_t count_stand = 0;
-
-       vect_t v, vi;
-
-
-       v.x = 1;
-       v.y = 0;
-    
-       vi = v;
-    
-       o->x_max = 0;
-       o->y_max = 0;
-       o->x_min = x_in;
-       o->y_min = y_in;
-    
-       
-       while(1){
-               if (pos_x == start_x && pos_y == start_y){
-                       count_stand++;
-                       if (count_stand>4)
-                               break;
-                       if( v.x == vi.x && v.y == vi.y && start)
-                               break;
-               }
-                
-               if (pos_x<o->x_min)
-                       o->x_min = pos_x;
-               if (pos_y<o->y_min)
-                       o->y_min = pos_y;
-               if (pos_x>o->x_max)
-                       o->x_max = pos_x;
-               if (pos_y>o->y_max)
-                       o->y_max = pos_y;
-        
-               /* is next pixel is good color */
-               if (data[(pos_y+v.y)*x_in + pos_x+v.x] != color){
-                       pos_x = pos_x+v.x;
-                       pos_y = pos_y+v.y;
-                       len++;
-                       vect_rot_retro(&v);
-                       start = 1;
-                       continue;
-               }    
-               vect_rot_trigo(&v);
-       }    
-       
-       o->len = len;
-}
-
-
-
-
-
-/* step around object of given color and computes its polygon */
-void object_find_poly(unsigned char* data, 
-                     int16_t x_in, int16_t y_in, 
-                     int16_t start_x, int16_t start_y, 
-                     int16_t color, int16_t color_w, Object_poly* o)
-{
-       int16_t pos_x = start_x;
-       int16_t pos_y = start_y;
-       int16_t start =0;
-       int16_t len = 0;
-       int16_t count_stand = 0;
-       uint16_t pt_step, pt_num;
-       vect_t v, vi;
-
-       v.x = 1;
-       v.y = 0;
-
-       vi = v;    
-       
-       pt_step = o->len/POLY_MAX_PTS + 1;
-       
-       pt_num = 0;
-
-       while(1){
-               if (pos_x == start_x && pos_y == start_y){
-                       count_stand++;
-                       if (count_stand>4)
-                               break;
-                       if( v.x == vi.x && v.y == vi.y && start)
-                               break;
-               }
-        
-               /* is next pixel is good color */
-               if (data[(pos_y+v.y)*x_in + pos_x+v.x] != color){
-                       pos_x = pos_x+v.x;
-                       pos_y = pos_y+v.y;
-                       len++;
-                       
-                       if (len >pt_num*pt_step){
-                               o->pts[pt_num].x = pos_x;
-                               o->pts[pt_num].y = pos_y;
-                               pt_num+=1;
-                               if (pt_num>=POLY_MAX_PTS)
-                                       break;
-                       }
-
-                       vect_rot_retro(&v);
-                       start = 1;
-                       continue;
-               }    
-               vect_rot_trigo(&v);
-       }    
-
-       o->pts_num = pt_num;
-
-}
-
-#define PT_LEFT 0
-#define PT_RIGHT 2
-#define PT_TOP 1
-#define PT_DOWN 3
-
-/* return most left/right/top/down pts indexes of given polygon */
-void object_find_extrem_points_index(Object_poly* o, 
-                                    unsigned int *pts)
-{
-       unsigned int i;
-       for (i=0;i<4;i++)
-               pts[i] = 0;
-
-
-       for (i=1;i<o->pts_num;i++){
-               if (o->pts[i].x < o->pts[pts[PT_LEFT]].x)
-                       pts[PT_LEFT] = i;
-               if (o->pts[i].x > o->pts[pts[PT_RIGHT]].x)
-                       pts[PT_RIGHT] = i;
-               if (o->pts[i].y < o->pts[pts[PT_TOP]].y)
-                       pts[PT_TOP] = i;
-               if (o->pts[i].y > o->pts[pts[PT_DOWN]].y)
-                       pts[PT_DOWN] = i;
-       }
-
-}
-
-
-#define NUM_CALIPERS 4
-/* for debug purpose: display a vector on image */
-void draw_pt_vect(unsigned char *buf, int16_t x_in, int16_t y_in, 
-                 vect_t *v, point_t p)
-{
-       unsigned int i;
-       float n;
-       int16_t x, y;
-       float coef=1.0;
-
-       if (!v->x && !v->y)
-               return;
-
-       n = vect_norm(v);
-       coef = 1/n;
-       for (i=0;i<5;i++){
-               x = p.x;
-               y = p.y;
-               
-               x+=(float)((v->x)*(float)i*(float)coef);
-               y+=(float)((v->y)*(float)i*(float)coef);
-               if ((x== p.x) && (y == p.y))
-                       buf[y*x_in+x] = 0x0;
-               else
-                       buf[y*x_in+x] = 0x0;
-       }
-       
-}
-
-#define CAL_X 3
-#define CAL_Y 0
-
-
-/* compute minimum rectangle area including the given convex polygon */
-void object_poly_get_min_ar(Object_poly *o, unsigned int *pts_index_out, 
-                            vect_t *v_out, vect_t *r1, vect_t*r2)
-{
-       vect_t calipers[NUM_CALIPERS];
-       vect_t edges[NUM_CALIPERS];
-
-       unsigned int i;
-       unsigned int calipers_pts_index[NUM_CALIPERS];
-       float angles[NUM_CALIPERS];
-       float min_angle;
-       float total_rot_angle = 0;
-       int caliper_result_index;
-
-       vect_t res1, res2;
-       float ps, n1, n2, caliper_n;
-
-       float aera_tmp;
-       /* XXX hack sould be max*/
-       float aera_min=0x100000;
-
-       object_find_extrem_points_index(o, calipers_pts_index);
-               
-       calipers[0].x = 0;
-       calipers[0].y = 1;
-
-       calipers[1].x = -1;
-       calipers[1].y = 0;
-
-       calipers[2].x = 0;
-       calipers[2].y = -1;
-
-       calipers[3].x = 1;
-       calipers[3].y = 0;
-
-
-       while (total_rot_angle <= M_PI/2){
-
-               for (i=0;i<NUM_CALIPERS;i++){
-                       /* compute polygon edge vector */
-                       edges[i].x = o->pts[(calipers_pts_index[i] + 1)%o->pts_num].x - 
-                               o->pts[calipers_pts_index[i]].x;
-                       edges[i].y = o->pts[(calipers_pts_index[i] + 1)%o->pts_num].y - 
-                               o->pts[calipers_pts_index[i]].y;
-
-                       /* compute angle between caliper and polygon edge */
-                       angles[i] = vect_get_angle(&edges[i], &calipers[i]);
-               }
-
-               /* find min angle */
-               min_angle = angles[0];
-               caliper_result_index = 0;
-               for (i=1;i<NUM_CALIPERS;i++){
-                       if (angles[i]<min_angle){
-                               min_angle = angles[i];
-                               caliper_result_index = i;
-                       }
-               }
-
-               /* rotate calipers */
-               calipers[caliper_result_index] = edges[caliper_result_index];
-               
-               for (i=caliper_result_index; i<caliper_result_index + o->pts_num; i++){
-                       calipers[(i+1) % NUM_CALIPERS] = calipers[i % NUM_CALIPERS];
-                       vect_rot_trigo(&calipers[(i+1) % NUM_CALIPERS]);
-               }
-
-               /* update calipers point */
-               for (i=0;i<NUM_CALIPERS;i++){
-                       if (angles[i]==min_angle)
-                               calipers_pts_index[i] = (calipers_pts_index[i] + 1) % o->pts_num;
-               }
-               
-               res1.x = o->pts[calipers_pts_index[2]].x - o->pts[calipers_pts_index[0]].x;
-               res1.y = o->pts[calipers_pts_index[2]].y - o->pts[calipers_pts_index[0]].y;
-
-               res2.x = o->pts[calipers_pts_index[3]].x - o->pts[calipers_pts_index[1]].x;
-               res2.y = o->pts[calipers_pts_index[3]].y - o->pts[calipers_pts_index[1]].y;
-               
-               ps = vect_pscal(&res1, &calipers[CAL_X]);
-               n1 = vect_norm(&res1);
-               caliper_n = vect_norm(&calipers[CAL_X]);
-               caliper_n*=caliper_n;
-
-               res1 = calipers[CAL_X];
-               
-               res1.x *= ps/(caliper_n);
-               res1.y *= ps/(caliper_n);
-
-
-               ps = vect_pscal(&res2, &calipers[CAL_Y]);
-               n1 = vect_norm(&res2);
-
-               res2 = calipers[CAL_Y];
-               
-               res2.x *= ps/(caliper_n);
-               res2.y *= ps/(caliper_n);
-               
-               n1 = vect_norm(&res1);
-               n2 = vect_norm(&res2);
-               
-               aera_tmp = n1*n2;
-               
-               if (aera_min >aera_tmp){
-                       aera_min = aera_tmp;
-                       for (i=0;i<NUM_CALIPERS;i++){
-                               pts_index_out[i] = calipers_pts_index[i];
-                       }
-                       *v_out = calipers[0];
-                       *r1 = res1;
-                       *r2 = res2;
-                       
-               }
-               total_rot_angle+=min_angle;
-       }
-
-       return;
-}
-
-#define COEF_CALIP 1
-/* transform caliper to rectangle coordinates */
-int object_poly_caliper_to_rectangle(Object_poly *o, 
-                                    unsigned int *pts_index_out, vect_t* caliper, 
-                                    vect_t *r1, vect_t*r2, point_t *p)
-{
-       line_t l1, l2;
-       vect_t caliper_tmp;
-       int ret, i;
-       double mp_x, mp_y;
-       point_t p_int1;//, p_int2;
-
-       point_t p1, p2;
-
-       caliper_tmp = *caliper;
-
-       //IMG_DEBUG("cal: %" PRIi32 " %" PRIi32 "", caliper_tmp.x, caliper_tmp.y);
-  
-       mp_x = 0;
-       mp_y = 0;
-
-       /* to be precise, calc 4 intersection of 4 calipers */
-       for (i=0;i<NUM_CALIPERS;i++){
-               p1.x = o->pts[pts_index_out[i]].x;
-               p1.y = o->pts[pts_index_out[i]].y;
-  
-               p2.x = p1.x+COEF_CALIP*caliper_tmp.x;
-               p2.y = p1.y+COEF_CALIP*caliper_tmp.y;
-  
-               pts2line(&p1, &p2, &l1);
-       
-               vect_rot_trigo(&caliper_tmp);  
-  
-               p1.x = o->pts[pts_index_out[(i+1)%NUM_CALIPERS]].x;
-               p1.y = o->pts[pts_index_out[(i+1)%NUM_CALIPERS]].y;
-  
-               p2.x = p1.x+COEF_CALIP*caliper_tmp.x;
-               p2.y = p1.y+COEF_CALIP*caliper_tmp.y;
-  
-               pts2line(&p1, &p2, &l2);
-       
-               ret = intersect_line(&l1, &l2, &p_int1);
-               if (ret!=1)
-                       return 0;
-               //IMG_DEBUG("int1 (%d): %" PRIi32 " %" PRIi32 " ", ret, p_int1.x, p_int1.y);
-  
-               mp_x+=p_int1.x;
-               mp_y+=p_int1.y;
-        
-       }
-  
-  
-  
-       p->x = lround(mp_x/NUM_CALIPERS);
-       p->y = lround(mp_y/NUM_CALIPERS);
-  
-
-       return 1;
-
-}
-
-#define OBJECT_DIM 5
-/* split zone in many column's sized area */
-int split_rectangle(point_t *p, vect_t *r1, vect_t* r2, uint8_t max_zone, zone* zones, uint8_t color)
-{
-       int n1, n2;
-       int i, j;
-       int index=0;
-       int r1_s, r2_s;
-       point_t ptmp;
-  
-  
-       n1 = vect_norm(r1);
-       n2 = vect_norm(r2);
-
-       r1_s = n1/OBJECT_DIM;
-       r2_s = n2/OBJECT_DIM;
-
-       if (!r1_s || ! r2_s)
-               return 0;
-  
-       ptmp.x = p->x - r1->x/2 - r2->x/2 + (r1->x/(r1_s*2))+(r2->x/(r2_s*2));
-       ptmp.y = p->y - r1->y/2 - r2->y/2 + (r1->y/(r1_s*2))+(r2->y/(r2_s*2));
-  
-       for(i=0;i<r1_s;i++){
-               for(j=0;j<r2_s;j++){
-                       zones[index].p.x = ptmp.x + (i*r1->x)/r1_s+(j*r2->x)/r2_s;
-                       zones[index].p.y = ptmp.y + (i*r1->y)/r1_s+(j*r2->y)/r2_s;
-                       zones[index].h = color;
-                       zones[index].valid = 1;
-
-                       index++;
-                       if (index>=max_zone)
-                               return index;
-
-
-               }
-       }
-    
-       return index;
-}
-
-#define OBJECT_SEMI_DIM (OBJECT_DIM/2)
-#define MIN_SURFACE_PERCENT 50
-#define HIGHER_MAX_PIXEL 5
-
-
-int zone_has_enought_pixels(unsigned char* data, int16_t x_in, int16_t y_in, zone* z)
-{
-       int x, y;
-       uint16_t count, total_pix, higher_pixels;
-
-       count = 0;
-       total_pix=0;
-       higher_pixels = 0;
-
-       for (x = -OBJECT_SEMI_DIM; 
-            (x <= OBJECT_SEMI_DIM) && (higher_pixels < HIGHER_MAX_PIXEL); 
-            x++){
-               for (y = -OBJECT_SEMI_DIM; 
-                    (y <= OBJECT_SEMI_DIM) && (higher_pixels < HIGHER_MAX_PIXEL); 
-                    y++){
-                       total_pix++;
-                       if (data[x_in * (y + z->p.y) + x + z->p.x] == z->h)
-                               count++;
-                       
-                       if (data[x_in * (y + z->p.y) + x + z->p.x] > z->h)
-                               higher_pixels++;
-                       
-               }
-               
-       }
-
-       IMG_DEBUG("has enougth pixel (h: %d x %"PRIi32": y:%"PRIi32") total: %d/%d (tt: %d, hmax: %d)", z->h, z->p.x, z->p.y, 
-                 count, (total_pix *  MIN_SURFACE_PERCENT) / 100, total_pix, higher_pixels);
-                       
-       if ((count > (total_pix *  MIN_SURFACE_PERCENT) / 100) && 
-           (higher_pixels <HIGHER_MAX_PIXEL))
-               return 1;
-       
-       return 0;
-}
-
-int zone_filter_min_surface(unsigned char* data, int16_t x_in, int16_t y_in, 
-                           uint8_t color, unsigned int zones_num, zone* p)
-{
-       int i;
-       
-       for (i = 0; i < zones_num ; i++){
-               if (zone_has_enought_pixels(data, x_in, y_in, &p[i]))
-                       continue;
-
-               p[i].valid = 0;         
-       }
-
-       IMG_NOTICE("num zone after min surf: %d", zones_num);
-       
-       return zones_num;
-       
-}
-
-/* center is 15 cm radius*/
-#define CENTER_RADIUS 15
-
-/* the complete column must be in the drop zone*/
-#define CENTER_MAX_DIST (15-3)
-
-/* the column must not be too close from center*/
-#define CENTER_MIN_DIST (8)
-
-int zone_filter_center(unsigned int zones_num, zone* p, int16_t center_x, int16_t center_y, int tweak_min_margin)
-{
-       int i;
-       vect_t v;
-       
-       for (i = 0; i < zones_num; i++){
-               
-               v.x = p[i].p.x - center_x;
-               v.y = p[i].p.y - center_y;
-               IMG_DEBUG("square dist to center %"PRIi32" (%d %d)",
-                         v.x*v.x + v.y*v.y,  (CENTER_MIN_DIST+tweak_min_margin) * (CENTER_MIN_DIST+tweak_min_margin), CENTER_MAX_DIST * CENTER_MAX_DIST);
-
-               if (v.x*v.x + v.y*v.y < CENTER_MAX_DIST * CENTER_MAX_DIST && 
-                   v.x*v.x + v.y*v.y > (CENTER_MIN_DIST+tweak_min_margin) * (CENTER_MIN_DIST+tweak_min_margin))
-                       continue;
-
-               p[i].valid = 0;
-
-       }
-
-       return zones_num;
-}
-
-#define MAX_DIST_TO_ZONE 2
-
-unsigned int zone_filter_zone_rect(unsigned int zones_num, zone* p, int16_t center_x, int16_t center_y , uint8_t working_zone)
-{
-       int i;
-       
-       for (i = 0; i < zones_num; i++){                
-               
-               IMG_DEBUG("rct x:%"PRIi32" y:%"PRIi32" (centerx: %d)",p[i].p.x , p[i].p.y,  center_x);
-               
-               if ((p[i].p.x > center_x - MAX_DIST_TO_ZONE) && (p[i].h > working_zone))
-                       continue;
-
-               p[i].valid = 0;
-       }
-
-       return zones_num;
-}
-
-
-/* delete point to render polygon convex */
-int object_poly_to_convex(Object_poly *o)
-{
-       unsigned int i, j;
-       vect_t v, w;
-       int16_t z;
-       unsigned int del_pts_num = 0;
-       
-       for (i=0;i<o->pts_num;){
-               v.x = o->pts[(i + o->pts_num - 1)%o->pts_num].x - o->pts[i].x;
-               v.y = o->pts[(i + o->pts_num - 1)%o->pts_num].y - o->pts[i].y;
-
-               w.x = o->pts[(i+1)%o->pts_num].x - o->pts[i].x;
-               w.y = o->pts[(i+1)%o->pts_num].y - o->pts[i].y;
-               
-               z = vect_pvect(&v, &w);
-               if (z>0){
-                       i+=1;
-                       continue;
-               }
-               
-               /* found a convex angle (or colinear points) */
-               for (j = i; j < o->pts_num-1; j++){
-                       o->pts[j] = o->pts[j+1];
-               }
-               if (i!=0)
-                       i-=1;
-               o->pts_num--;
-               del_pts_num++;
-       }
-
-       return del_pts_num;
-}
-
-
-
-
-
-#define DEFAULT_COLOR 255
-/* scan all image and find objects*/
-unsigned char *parcour_img(unsigned char* data, int16_t x_in, int16_t y_in, 
-                          Object_bb *sac_obj, Object_poly *sac_obj_poly, int16_t max_obj)
-{
-       int16_t i, obj_num;
-
-       uint8_t in_color=0;    
-       int16_t etat;
-
-       Object_bb o;
-       int ret;
-
-       obj_num = 0;
-       /*
-         first, delete borders
-       */
-       for (i=0;i<x_in;i++){
-               data[i] = 0;
-               data[(y_in - 1) * x_in + i] = 0;
-       }
-
-       for (i=0;i<y_in;i++){
-               data[i * x_in] = 0;
-               data[i * x_in + x_in - 1] = 0;
-       }
-      
-
-    
-       etat = 0; 
-       /*
-         0 look for color (object or edge)
-         1 look for edge end
-       */
-    
-       for (i=1;i<x_in*y_in;i++){
-               switch(etat){
-               case 0:
-                       //we are in the dark
-                       switch(data[i]){
-                       case 0:
-                               //look for in dark
-                               break;
-                               /*
-                                 case 1:
-                                 case 2:
-                                 case 0x15:
-                                 case 0x24:
-                               */
-                       default:
-                               in_color = data[i];
-                               etat = 1;
-                               // we found an object
-                               object_find_bounding_box(data, x_in, y_in, (i-1)%x_in, (i-1)/x_in, data[i], 255, &o);
-
-                               ret = store_obj(sac_obj,  max_obj, &o);
-                               /* if new object, process rotating calipers */
-                               if (ret){
-                                       sac_obj_poly[obj_num].len = o.len;
-                                       object_find_poly(data, x_in, y_in, 
-                                                        (i-1)%x_in, (i-1)/x_in, 
-                                                        data[i], 255, &sac_obj_poly[obj_num]);
-                                       IMG_DEBUG("%d",sac_obj_poly[obj_num].pts_num);
-                                       object_poly_to_convex(&sac_obj_poly[obj_num]);
-                                       /*
-                                         for (j=0;j<sac_obj_poly[obj_num].pts_num;j++){
-                                         data[sac_obj_poly[obj_num].pts[j].y*x_in + sac_obj_poly[obj_num].pts[j].x] = 8;
-                                         }*/
-                                       sac_obj_poly[obj_num].color = data[i];
-                                       obj_num++;
-                               }
-                        
-                               break;
-
-                       case DEFAULT_COLOR:
-                               //we must out of color
-                               break;
-                       }    
-                       break;
-
-               case 1:
-                       if (data[i] != in_color){
-                               i--;
-                               etat = 0;
-                       }
-                       /*
-                         we are in a color and want to go out of it
-                       */
-                       break;
-
-               }    
-        
-        
-        
-       }    
-
-    
-       return data;
-    
-    
-}    
-/* space between twin tower is 13 pixels*/
-#define SPACE_INTER_TWIN_TOWER (13)
-
-#define SPACE_INTER_TWIN_TOWER_TOLERENCE 3
-
-
-
-/* find best twin tower for each zone */
-void find_twin_tower(uint8_t zones_num, zone* zones, int8_t sisters[MAX_ZONES][MAX_SISTER_PER_ZONE], 
-                    int16_t center_x, int16_t center_y)
-{
-
-       uint8_t i, j;
-       uint8_t z_n;
-       int n1, n2;
-       unsigned int z1, z2, z3;
-       //int32_t scal1, scal2;
-       vect_t v, v1, v2;
-       line_t l;
-       point_t p;
-       unsigned int good_zone;
-       double dist, dist2;
-       unsigned int current_sister;
-
-       /* init dummy sisters */
-       for (i = 0; i < zones_num; i++)
-               for (j = 0; j < MAX_SISTER_PER_ZONE; j++)
-                       sisters[i][j] = -1;
-
-
-
-       for (z_n = 0; z_n < zones_num; z_n++){
-               if (!zones[z_n].valid)
-                       continue;
-
-               current_sister = 0;
-
-               for (i = 0; i < zones_num; i++){
-
-
-                       /* we already have max sisters */
-                       if (current_sister >= MAX_SISTER_PER_ZONE)
-                               break;
-
-
-                       if (!zones[i].valid)
-                               continue;
-
-
-                       if (i == z_n)
-                               continue;
-            
-                       /* twin tower must have same high */
-                       if (zones[i].h != zones[z_n].h)
-                               continue;
-
-                       IMG_DEBUG("test sisters (%"PRIi32" %"PRIi32") (%"PRIi32" %"PRIi32")", 
-                                 zones[z_n].p.x,   zones[z_n].p.y,
-                                 zones[i].p.x,   zones[i].p.y);
-                       
-                       
-                       dist = sqrt( (zones[i].p.x - zones[z_n].p.x) * (zones[i].p.x - zones[z_n].p.x) + 
-                                    (zones[i].p.y - zones[z_n].p.y) * (zones[i].p.y - zones[z_n].p.y) );
-                       
-                       
-                       IMG_DEBUG("sister space is %2.2f may be near %d", dist, SPACE_INTER_TWIN_TOWER);
-                       
-                       /* 
-                          twin tower must be close/far enought to drop lintel
-                        */
-                       if (ABS(dist - SPACE_INTER_TWIN_TOWER) > SPACE_INTER_TWIN_TOWER_TOLERENCE)
-                               continue;
-
-
-                       pts2line(&zones[i].p, &zones[z_n].p, &l);
-                       
-                       /* 
-                          test the paralelism of the temple:
-                          zone may be on same distance from center 
-                       */
-                       
-
-                       v1.x = zones[z_n].p.x - center_x;
-                       v1.y = zones[z_n].p.y - center_y;
-                       
-                       dist = vect_norm(&v1);
-
-                       v2.x = zones[i].p.x - center_x;
-                       v2.y = zones[i].p.y - center_y;
-                       
-                       dist2 = vect_norm(&v2);
-
-                       IMG_DEBUG("zone dist %2.2f %2.2f", dist, dist2);
-                       if (ABS(dist-dist2) > 3){
-                               IMG_DEBUG("bad parallelism %2.2f", ABS(dist-dist2));
-                               continue;
-                       }
-                               
-                       
-
-            
-                       /* no other aligned tower to avoid dropping on a lintel 
-                        *  (3 aligned zone may mean lintel) 
-                        */
-
-                       good_zone = 1;
-            
-                       for (j = 0; j < zones_num; j++){
-                               if (j==i ||j == z_n)
-                                       continue;
-            
-                               /* if third zone, but lower */
-                               if (zones[j].h <= zones[i].h)
-                                       continue;
-            
-                               /* 
-                                  check distance from dropping zone to
-                                  line formed by twin towers
-                               */
-            
-                               proj_pt_line(&zones[j].p, &l, &p);
-
-
-                               /* test if projected point is in the segement */
-                               
-
-                               v.x = zones[z_n].p.x - zones[i].p.x;
-                               v.y = zones[z_n].p.y - zones[i].p.y;
-
-                               v1.x = p.x - zones[i].p.x;
-                               v1.y = p.y - zones[i].p.y;
-
-                               n1 = vect_pscal_sign(&v, &v1);
-
-                               v.x = -v.x;
-                               v.y = -v.y;
-
-                               v1.x = p.x - zones[z_n].p.x;
-                               v1.y = p.y - zones[z_n].p.y;
-                               
-
-                               n2 =vect_pscal_sign(&v, &v1);
-
-                               v.x = p.x - zones[j].p.x;
-                               v.y = p.y - zones[j].p.y;
-            
-                               dist = vect_norm(&v);
-                               IMG_DEBUG("dist pt  h %d n: (%d %d) (%"PRIi32" %"PRIi32") to line %2.2f", zones[j].h, n1, n2, zones[j].p.x, zones[j].p.y, dist);
-
-            
-                               if ((n1>=0 && n2>=0) && dist < OBJECT_DIM+2.){
-                                       good_zone = 0;
-                                       break;
-                               }
-                                       
-            
-                               /* test if zone is far from points*/
-                               
-                               v1.x = zones[j].p.x - zones[z_n].p.x;
-                               v1.y = zones[j].p.y - zones[z_n].p.y;
-            
-                               dist = vect_norm(&v1);
-                               IMG_DEBUG("dist pt to z1 %2.2f", dist);
-            
-                               if (dist < OBJECT_DIM){
-                                       good_zone = 0;
-                                       break;
-                               }
-                               
-                               v2.x = zones[j].p.x - zones[i].p.x;
-                               v2.y = zones[j].p.y - zones[i].p.y;
-            
-            
-                               dist = vect_norm(&v2);
-                               IMG_DEBUG("dist pt to z2 %2.2f", dist);
-            
-                               if (dist < OBJECT_DIM){
-                                       good_zone = 0;
-                                       break;
-                               }
-
-                               
-            
-                               z1 = i;
-                               z2 = z_n;
-                               z3 = j;
-            
-
-                               
-            
-            
-                               /*
-                                 XXX may be a lintel on lintel !!
-                                */
-
-                       }
-            
-                       if (!good_zone)
-                               continue;
-            
-                       IMG_DEBUG("sisters ok (%"PRIi32" %"PRIi32") (%"PRIi32" %"PRIi32")", 
-                                 zones[z_n].p.x,   zones[z_n].p.y,
-                                 zones[i].p.x,   zones[i].p.y);
-
-                       
-                       sisters[z_n][current_sister] = i;
-                       current_sister++;
-               }
-       }
-}
-
-/* test if a higher zone is too close */
-int test_close_zone(uint8_t zones_num, zone* zones, unsigned int z_n)
-{
-       uint8_t i;
-       vect_t v;
-       double dist;
-
-       for (i = 0; i < zones_num; i++){
-               if (i == z_n)
-                       continue;
-               if (zones[i].h <= zones[z_n].h)
-                       continue;
-               
-               v.x = zones[i].p.x - zones[z_n].p.x;
-               v.y = zones[i].p.y - zones[z_n].p.y;
-
-               dist = vect_norm(&v);
-               //IMG_DEBUG("dist pt to pt %2.2f", dist);
-                       
-               if (dist < OBJECT_DIM){
-                       return 1;
-               }
-
-       }
-
-       return 0;
-}
-
-#define MAX_COLUMN 4
-#define MAX_LINTEL 2
-
-drop_column_zone drop_c[MAX_COLUMN];
-drop_lintel_zone drop_l[MAX_LINTEL];
-
-
-void reset_drop_zone(void)
-{
-       memset(drop_c, 0, sizeof(drop_c));
-       memset(drop_l, 0, sizeof(drop_l));
-
-}
-
-
-void display_drop_zones(uint8_t n_columns, uint8_t n_lintels, zone* zones)
-{
-       unsigned int i;
-
-       for (i=0;i<n_columns;i++)
-               IMG_NOTICE("c %d:(h:%d) (%"PRIi32" %"PRIi32") valid=%d",
-                            i, drop_c[i].h,
-                            zones[drop_c[i].z].p.x, zones[drop_c[i].z].p.y,
-                            drop_c[i].valid);
-
-       for (i=0;i<n_lintels;i++)
-               IMG_NOTICE("l %d:(h:%d) (%"PRIi32" %"PRIi32") "
-                            "(%"PRIi32" %"PRIi32") valid=%d",
-                            i, drop_l[i].h,
-                            zones[drop_l[i].z1].p.x, zones[drop_l[i].z1].p.y, 
-                            zones[drop_l[i].z2].p.x, zones[drop_l[i].z2].p.y, drop_l[i].valid);
-       
-}
-
-#define MY_MAX(a, b) ((a)>(b)?(a):(b))
-
-
-#if 0
-#define MAX_DROP_HIGH  8
-
-
-/* 
-   recursive function to maximize points during object
-   dropping, given lintel/column number
-   working zone may be 1, 2 or 3
- */
-unsigned int solve_objects_dropping(unsigned int points, unsigned int points_max,
-                                   uint8_t n_columns, uint8_t n_lintels, 
-                                   uint8_t zones_num, zone* zones, int8_t sisters[MAX_ZONES][MAX_SISTER_PER_ZONE], uint8_t working_zone)
-{
-       
-       uint8_t i, j;
-       unsigned int points_calc;
-       //unsigned int points_added = 0;
-       int sister;
-       int ret;
-
-
-       /* if no more objects, return points */
-       if (n_columns == 0 && n_lintels == 0)
-               return MY_MAX(points, points_max);
-       
-       /* start by putting columns if so */
-       for (i = 0; i < zones_num; i++){
-               if (zones[i].h >= MAX_DROP_HIGH)
-                       continue;
-
-               if (n_columns){
-
-                       ret = test_close_zone(zones_num, zones, i);
-                       if (ret)
-                               continue;
-
-                       zones[i].h++;
-                       points_calc = solve_objects_dropping(points + zones[i].h, points_max,
-                                                            n_columns - 1, n_lintels, 
-                                                            zones_num, zones, sisters, working_zone);
-                       
-                       if (points_calc > points_max){
-                               points_max = points_calc;
-                               drop_c[n_columns - 1].z = i;
-                               drop_c[n_columns - 1].h = zones[i].h;
-                               drop_c[n_columns - 1].valid  = 1;
-                               
-                       }
-                       zones[i].h--;
-               }
-               /* we must depose all columns before dropping lintels */
-               else if (n_lintels){
-                       
-                       /* dont drop lintel on ground */
-                       if (zones[i].h  <= working_zone)
-                               continue;
-
-                       /* XXX todo need get second zone near selected one */
-                       //ret = find_twin_tower(zones_num, zones, i, &sister);
-
-                       for (j = 0; j < MAX_SISTER_PER_ZONE; j++){
-                               sister = sisters[i][j];
-                               if (sister == -1)
-                                       break;
-                               if (zones[i].h != zones[sister].h){
-                                       sister = -1;
-                               }
-                               
-                       }
-
-                       if (sister == -1)
-                               continue;
-                       //IMG_DEBUG("sister found: %d %d (h=%d %p)", i, sister, zones[i].h, &zones[i].h);
-                       
-                       zones[i].h++;
-                       zones[sister].h++;
-
-                       
-                       points_calc = solve_objects_dropping(points + zones[i].h * 3, points_max,
-                                                            n_columns, n_lintels - 1, 
-                                                            zones_num, zones, sisters, working_zone);
-                       
-                       if (points_calc > points_max){
-                               points_max = points_calc;
-
-                               drop_l[n_lintels - 1].z1 = i;
-                               drop_l[n_lintels - 1].z2 = sister;
-                               drop_l[n_lintels - 1].h = zones[i].h;
-                               drop_l[n_lintels - 1].valid = 1;
-                               
-                       }
-
-                       
-                       zones[sister].h--;
-                       zones[i].h--;
-               }
-       }
-       
-       return MY_MAX(points, points_max);
-}
-#endif
-
-
-/*  */
-int find_column_dropzone(uint8_t zones_num, zone* zones)
-{
-       uint8_t i;
-       
-       uint8_t z_n = 0;
-
-       if (zones_num <= 0)
-               return -1;
-
-       for (i = 0; i < zones_num; i++){
-               if (!zones[i].valid)
-                       continue;
-               if (zones[i].h > zones[z_n].h)
-                       z_n = i;
-       }
-
-
-       /* 
-          now, chose dropzone closest to robot 
-          meaning little x, big y
-          so maximise y-x
-        */
-       for (i = 0; i < zones_num; i++){
-               if (zones[i].h != zones[z_n].h)
-                       continue;
-               if (!zones[i].valid)
-                       continue;
-               if (zones[i].p.y - zones[i].p.x > zones[z_n].p.y - zones[z_n].p.x)
-                       z_n = i;
-       }
-       
-       
-       
-       return z_n;
-}
-
-
-
-uint8_t color2h(uint8_t color)
-{
-       return (0x100-color)/0x20;
-}
-
-uint8_t h2color(uint8_t color)
-{
-       return color*0x20;
-}
-
-
-#define NUM_ZONE_GENERATE 8
-#define DIST_ZONE_GEN 9
-
-/*
-  remove zone at ground level, and generate zones on 
-  a circle at X cm from center
- */
-unsigned int generate_center_ground_zones(unsigned char* data, int16_t x_in, int16_t y_in,
-                                         zone * zones, unsigned int zones_num, uint8_t max_zones, int16_t center_x, int16_t center_y)
-{
-       double c_a, s_a;
-       uint8_t i, j;
-       double px1, py1, px2, py2;
-
-       
-       /* first del zone at level 2 */
-       for (i = 0; i < zones_num; ){
-               if (zones[i].h!=2){
-                       i++;
-                       continue;
-               }
-
-               for (j = i; j < zones_num-1; j++)
-                       zones[j] = zones[j+1];
-
-               zones_num--;
-
-       }
-
-       /* generate zones around circle  */
-
-       c_a = cos(2*M_PI/NUM_ZONE_GENERATE);
-       s_a = sin(2*M_PI/NUM_ZONE_GENERATE);
-
-       px1 = DIST_ZONE_GEN;
-       py1 = 0;
-
-       for (i = 0; i < NUM_ZONE_GENERATE; i++){
-               
-               zones[zones_num].p.x = center_x + px1;
-               zones[zones_num].p.y = center_y + py1;
-               zones[zones_num].h = 2;
-               zones[zones_num].valid = 1;
-
-               
-               px2 = px1*c_a + py1*s_a;
-               py2 = -px1*s_a + py1*c_a;
-
-               px1 = px2;
-               py1 = py2;
-
-               /* skip zone if it is not in img */
-               if (zones[zones_num].p.x < 0 ||  zones[zones_num].p.y < 0 ||
-                   zones[zones_num].p.x >= x_in ||  zones[zones_num].p.y > y_in)
-                       continue;
-
-               /* skip zone if not enougth pixels */
-               if (!zone_has_enought_pixels(data, x_in, y_in, &zones[zones_num]))
-                       continue;
-               
-               zones_num++;
-               if (zones_num >= max_zones)
-                       break;
-               
-       }
-
-       return zones_num;
-
-       
-}
-
-
-/*
-  remove zone at ground level, and generate zones on 
-  a line at X cm from robot
- */
-unsigned int generate_rectangle_ground_zones(unsigned char* data, int16_t x_in, int16_t y_in,
-                                            zone * zones, unsigned int zones_num, uint8_t max_zones, int16_t center_x, int16_t center_y,
-                                            uint8_t working_zone)
-{
-       uint8_t i, j;
-       uint8_t y;
-
-       /* first del zone at level i */
-       for (i = 0; i < zones_num; ){
-               if (zones[i].h != working_zone ){
-                       i++;
-                       continue;
-               }
-
-               for (j = i; j < zones_num-1; j++)
-                       zones[j] = zones[j+1];
-
-               zones_num--;
-       }
-
-
-       /* generate zones on a line  */
-       for (y = OBJECT_DIM; y < y_in; y+=OBJECT_DIM){
-
-               zones[zones_num].p.x = center_x;
-               zones[zones_num].p.y = y;
-               zones[zones_num].h = working_zone ;
-               zones[zones_num].valid = 1;
-
-               if (!zone_has_enought_pixels(data, x_in, y_in, &zones[zones_num]))
-                       continue;
-               zones_num++;
-
-               if (zones_num >= max_zones)
-                       break;
-               
-       } 
-       return zones_num;
-       
-}
-
-
-#define MAX_DECAL_LINE 5
-#define ENOUGHT_ZONE_PIXEL 2
-
-void recal_img_y(unsigned char* buffer, int16_t x_in, int16_t y_in, 
-                uint8_t working_zone)
-{
-       uint8_t i, j;
-       uint8_t cpt;
-
-       /* recal img only for central zone */
-       if (working_zone !=2)
-               return;
-       
-       for (i = 0; i < MAX_DECAL_LINE; i++){
-               cpt = 0;
-               for (j = 0; j < x_in; j++){
-                       if (buffer[i*x_in + j] ==2)
-                               cpt++;
-               }
-
-               if (cpt >= ENOUGHT_ZONE_PIXEL)
-                       break;
-       }
-
-       memmove(buffer, &buffer[i * x_in], x_in * y_in - i*x_in);
-       memset(&buffer[x_in * y_in - i * x_in], 0,  i*x_in);
-}
-
-
-#define MAX_OBJECTS 20
-
-#define MAX_ZONES_PER_OBJECT 20
-
-
-uint8_t g_zone_num;
-zone g_all_zones[MAX_ZONES];
-
-uint8_t process_img(unsigned char *buffer, int16_t x_in, int16_t y_in,
-                   zone * all_zones, uint8_t max_zones)
-{
-
-       int ret;
-       int i, j;
-
-       zone zones[MAX_ZONES_PER_OBJECT];
-  
-       vect_t caliper;
-       unsigned int pts_cal[4];
-       point_t ptmp;
-       vect_t r1, r2;
-       int zone_len;
-  
-  
-       uint8_t zone_num = 0;
-
-       Object_bb sac_obj[MAX_OBJECTS];
-       Object_poly sac_obj_poly[MAX_OBJECTS];
-  
-
-
-       /* 
-          XXX fix: only decal for working zone 2/(1?) 
-          but we dont have info yet
-       */
-       recal_img_y(buffer, x_in, y_in, 2);
-
-       memset(sac_obj, 0, sizeof(sac_obj));
-       memset(sac_obj_poly, 0, sizeof(sac_obj_poly));
-
-
-       /* first, find polygons*/
-       parcour_img(buffer, x_in, y_in, sac_obj, sac_obj_poly, MAX_OBJECTS);
-
-       /* enclose each poygon in the min area polygon
-          then, split each rectangle in dropping zone
-       */
-       for (i=0;i<MAX_OBJECTS;i++){
-
-               if (!sac_obj_poly[i].pts_num)
-                       continue;
-               
-               IMG_DEBUG("obj: %d %d %d %d %d", 
-                         i, 
-                         sac_obj[i].x_min, 
-                         sac_obj[i].y_min, 
-                         sac_obj[i].x_max, 
-                         sac_obj[i].y_max);
-               
-               //IMG_DEBUG("poly pts_num: %d", sac_obj_poly[i].pts_num);
-        
-               object_poly_get_min_ar(&sac_obj_poly[i], &pts_cal[0], &caliper, &r1, &r2);
-    
-               ret = object_poly_caliper_to_rectangle(&sac_obj_poly[i], &pts_cal[0], &caliper,
-                                                      &r1, &r2, &ptmp);
-    
-               if (!ret)
-                       continue;
-
-               /*
-               IMG_DEBUG("r: (%3"PRIi32" %3"PRIi32")  "
-                            "(%3"PRIi32" %3"PRIi32")",
-                            r1.x, r1.y, r2.x, r2.y);
-               IMG_DEBUG("intersection: %"PRIi32" %"PRIi32"",
-                            ptmp.x, ptmp.y);
-               */
-    
-               zone_len = split_rectangle(&ptmp, &r1, &r2, 
-                                             MAX_ZONES_PER_OBJECT, &zones[0], sac_obj_poly[i].color);
-               //IMG_DEBUG("split ok %d", zone_len);
-    
-               zone_len =  zone_filter_min_surface(buffer, x_in, y_in, 
-                                                   sac_obj_poly[i].color, 
-                                                   zone_len, &zones[0]);               
-               
-               for (j = 0; j < zone_len && zone_num < max_zones; zone_num++, j++)
-                       all_zones[zone_num] = zones[j];
-
-       }
-
-
-       IMG_NOTICE("num zones end: %d", zone_num);
-       
-       return zone_num;
-}
-
-
-void process_img_to_zone(unsigned char *buffer, int16_t x_in, int16_t y_in)
-{
-       g_zone_num = process_img(buffer, x_in, y_in,
-                                g_all_zones, MAX_ZONES);
-}
-
-uint8_t filter_zones(unsigned char *buffer, int16_t x_in, int16_t y_in,
-                    zone * all_zones, uint8_t zone_num, uint8_t max_zones,
-                    uint8_t working_zone, int16_t center_x, int16_t center_y,
-                    int tweak_min_margin)
-{
-       uint8_t i;
-
-       /* first valid all zones */
-       for (i = 0; i < zone_num; i++){
-               all_zones[i].valid = 1;
-
-               /* filter zone lower thatn working zone */
-               if (all_zones[i].h  < working_zone)
-                       all_zones[i].valid = 0;
-       }
-
-
-       /* 
-          generate correct zone at ground level 
-          (depending on working zone)
-       */
-       if (working_zone == 2)
-               zone_num =  generate_center_ground_zones(buffer, x_in, y_in, 
-                                                        all_zones, zone_num, max_zones, center_x, center_y);
-       else
-               zone_num =  generate_rectangle_ground_zones(buffer, x_in, y_in, 
-                                                           all_zones, zone_num, max_zones, center_x, center_y,
-                                                           working_zone);
-
-       /* filter zone position, depending on workingzone */    
-       if (working_zone == 2)
-               zone_num = zone_filter_center(zone_num, all_zones, center_x, center_y, tweak_min_margin);
-       else
-               zone_num = zone_filter_zone_rect(zone_num, all_zones, center_x, center_y , working_zone);
-               
-
-
-       /* display zones (debug purpose) */
-
-       for (i = 0; i < zone_num; i++){
-               //buffer[all_zones[i].p.y*x_in+all_zones[i].p.x] = 0x3;
-               IMG_NOTICE("h:%d (v:%d) x:%"PRIi32" y:%"PRIi32"", all_zones[i].h, all_zones[i].valid, all_zones[i].p.x, all_zones[i].p.y);
-       }
-  
-       IMG_NOTICE("num zones: %d", zone_num);
-
-       
-       
-
-       return zone_num;
-}
-
-
-/*
-  return -1 if not column dropzone is found
-  return column hight if found
-*/
-int8_t get_column_dropzone(unsigned char *buffer, int16_t x_in, int16_t y_in, 
-                          uint8_t working_zone, int16_t center_x, int16_t center_y,
-                          int16_t * dropzone_x, int16_t * dropzone_y)
-{
-       uint8_t zone_num;
-       int c_drop_zone;
-
-
-
-       zone_num = filter_zones(buffer, x_in, y_in,
-                               g_all_zones, g_zone_num, MAX_ZONES,
-                               working_zone, center_x, center_y,
-                               0);
-
-       c_drop_zone = find_column_dropzone(zone_num, g_all_zones);
-
-       if (c_drop_zone<0)
-               return -1;
-
-       *dropzone_x = g_all_zones[c_drop_zone].p.x;
-       *dropzone_y = g_all_zones[c_drop_zone].p.y;
-
-       *dropzone_x = (*dropzone_x) * PIXEL2CM;
-       *dropzone_y = (*dropzone_y) * PIXEL2CM + 30;
-
-       return g_all_zones[c_drop_zone].h;
-}
-
-#define ROBOT_SEMI_INTERCOLUMN_SPACE 75
-
-uint8_t is_temple_there(unsigned char * buffer, int16_t x_in, int16_t y_in, 
-                       uint8_t h, int16_t center_x, int16_t center_y)
-{
-       zone z;
-       int ret;
-       int i;
-
-       
-       IMG_NOTICE("test z (mm) : x:%d y:%d", center_x, center_y);
-       IMG_NOTICE("test z:(pix): x:%d y:%d", (int)(center_x/ PIXEL2CM), (int)(center_y/ PIXEL2CM));
-       
-       
-       z.p.x = center_x / PIXEL2CM;
-       z.p.y = (center_y - ROBOT_SEMI_INTERCOLUMN_SPACE) / PIXEL2CM ;
-       z.h = h;
-       z.valid = 1;
-       ret = zone_has_enought_pixels(buffer, x_in, y_in, &z);
-       IMG_NOTICE("test z1: %d", ret);
-
-       if (!ret)
-               return 0;
-
-       z.p.x = center_x / PIXEL2CM;
-       z.p.y = (center_y  + ROBOT_SEMI_INTERCOLUMN_SPACE)/ PIXEL2CM;
-       z.h = h;
-       z.valid = 1;
-       ret = zone_has_enought_pixels(buffer, x_in, y_in, &z);
-       IMG_NOTICE("test z2: %d", ret);
-       if (!ret)
-               return 0;
-
-
-       /* 
-          if middle zone is less or egual to tested temple 
-        */
-       z.p.x = center_x / PIXEL2CM;
-       z.p.y = center_y / PIXEL2CM;
-       
-       for (i = h; i > 0; i--){
-               z.h = i;
-               z.valid = 1;
-               ret = zone_has_enought_pixels(buffer, x_in, y_in, &z);
-               IMG_NOTICE("test z3:(h=%d) %d", i, ret);
-               
-               if (ret)
-                       return 1;
-       }
-
-       return 0;
-
-}
-
-
-int8_t find_temple_dropzone(unsigned char *buffer, int16_t x_in, int16_t y_in, 
-                           uint8_t working_zone, int16_t center_x, int16_t center_y,
-                           int16_t * dropzone_x, int16_t * dropzone_y)
-{
-       uint8_t zone_num;
-       int8_t sisters[MAX_ZONES][MAX_SISTER_PER_ZONE];
-       int8_t z_n = -1;
-       uint8_t i, j;
-
-
-       /* find all drop zone */
-       zone_num = filter_zones(buffer, x_in, y_in,
-                               g_all_zones, g_zone_num, MAX_ZONES,
-                               working_zone, center_x, center_y,
-                               -2);
-
-       /* precompute possible twin towers */
-       find_twin_tower(zone_num, g_all_zones, sisters, center_x, center_y);
-       
-
-       for (i=0; i< zone_num; i++){
-               IMG_DEBUG("all sisters: %d", i);
-               for (j=0;j<MAX_SISTER_PER_ZONE;j++){
-                       IMG_DEBUG("s: %d", sisters[i][j]);
-               }
-       }
-
-       /* only use first sister of each zone */
-       for (i=0; i< zone_num; i++){
-               
-               /* if zone doesn't have twin tower */
-               if (sisters[i][0] == -1)
-                       continue;
-
-               if (!g_all_zones[i].valid)
-                       continue;
-
-               if (z_n == -1){
-                       z_n = i;
-                       continue;
-               }
-
-               /* if we found higher twin tower */
-               if (g_all_zones[z_n].h > g_all_zones[i].h)
-                       continue;
-
-               z_n = i;
-       }
-
-       IMG_NOTICE("twin tower found :z_n=%d", z_n);
-       if (z_n ==  -1)
-               return -1;
-       
-       IMG_NOTICE("(%"PRIi32" %"PRIi32") (%"PRIi32" %"PRIi32")", 
-                  g_all_zones[z_n].p.x, g_all_zones[z_n].p.y,
-                  g_all_zones[sisters[z_n][0]].p.x, g_all_zones[sisters[z_n][0]].p.y);
-       
-
-       *dropzone_x = ((double)(g_all_zones[z_n].p.x + g_all_zones[sisters[z_n][0]].p.x)*PIXEL2CM ) / 2;
-       *dropzone_y = ((double)(g_all_zones[z_n].p.y + g_all_zones[sisters[z_n][0]].p.y)*PIXEL2CM ) / 2 + 30;
-
-
-       return g_all_zones[z_n].h;
-
-}