Subversion Repositories shark

Rev

Rev 1085 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1085 pj 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators:
5
 *   Giorgio Buttazzo    <giorgio@sssup.it>
6
 *   Paolo Gai           <pj@gandalf.sssup.it>
7
 *
8
 * Authors     :
9
 *   Paolo Gai           <pj@gandalf.sssup.it>
10
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
11
 *   Luca Abeni          <luca@gandalf.sssup.it>
12
 *   (see the web pages for full authors list)
13
 *
14
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
15
 *
16
 * http://www.sssup.it
17
 * http://retis.sssup.it
18
 * http://shark.sssup.it
19
 */
20
 
21
 
22
/**
23
 ------------
24
 CVS :        $Id: sensor.c,v 1.1.1.1 2002-09-02 09:37:42 pj Exp $
25
 
26
 File:        $File$
27
 Revision:    $Revision: 1.1.1.1 $
28
 Last update: $Date: 2002-09-02 09:37:42 $
29
 ------------
30
**/
31
 
32
/*
33
 * Copyright (C) 2000 Marco Dallera and Marco Fiocca
34
 *
35
 * This program is free software; you can redistribute it and/or modify
36
 * it under the terms of the GNU General Public License as published by
37
 * the Free Software Foundation; either version 2 of the License, or
38
 * (at your option) any later version.
39
 *
40
 * This program is distributed in the hope that it will be useful,
41
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43
 * GNU General Public License for more details.
44
 *
45
 * You should have received a copy of the GNU General Public License
46
 * along with this program; if not, write to the Free Software
47
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
48
 *
49
 */
50
 
51
/*
52
 *              AUTO
53
 *
54
 * Another Unuseful Track simulatOr
55
 *
56
 * Authors: Marco Dallera
57
 *          Marco Fiocca
58
 *
59
 */
60
 
61
/* ------------ */
62
/*  Camera car  */
63
/* ------------ */
64
 
65
#include "include/auto.h"
66
#include "include/const.h"
67
#include "include/utils.h"
68
#include <drivers/glib.h>
69
 
70
#define RADIUS                  1
71
#define TOLL_FACTOR         4.0
72
#define MIN_DIFF        3
73
#define ROAD_COLOR              27
74
#define OFFROAD_COLOR   0
75
#define DEBUG_COLOR             GREEN
76
#define OUT_OF_TRACK    230
77
#define STRIP_DEFAULT   TEL_WIDTH+1
78
 
79
extern sem_t grx_mutex;
80
extern car_params cars[MAX_CAR_NUMBER];
81
 
82
void scanline(point_f *buffer, float x1, float y1, float x2, float y2, int factor);
83
void get_camera_car(BYTE *buffer, car_status status);
84
int find_track(BYTE *image, road_info *info);
85
int find_opps(BYTE *image, road_info *info);
86
void find_collision(BYTE *image, road_info *info, car_status status);
87
 
88
/* ----------------------------------------------------------------- */
89
 
90
TASK sensor(int index) {
91
  car_status actual_car_status;         // the actual car state
92
  road_info actual_road_info;           // the actual road informations
93
  BYTE image[TEL_WIDTH*TEL_HEIGHT];     // buffer contenente la visione della telecamera ruotata
94
 
95
  point sq1, sq2;
96
  point im1, im2;
97
 
98
  CAB road_status_cab = cars[index].road_status_cab;
99
  CAB car_status_cab  = cars[index].car_status_cab;
100
 
101
  // Draws display squares
102
  sq1.x = TRACK_X1 + TRACK_WIDTH + TEL_HEIGHT;
103
  sq1.y = TEL_HEIGHT*index + 1 + index;
104
  sq2.x = sq1.x + TEL_WIDTH + 1;
105
  sq2.y = sq1.y + TEL_HEIGHT + 1;
106
 
107
  // Sets viewer coords
108
  im1.x = sq1.x + 1;
109
  im1.y = sq1.y + 1;
110
  im2.x = im1.x + TEL_WIDTH - 1;
111
  im2.y = im1.y + TEL_HEIGHT - 1;
112
 
113
  // Inizializza il cab della strada
114
  actual_road_info.left_border = TEL_WIDTH/2;
115
  actual_road_info.right_border = TEL_WIDTH/2;
116
  actual_road_info.distance = TEL_HEIGHT;
117
  actual_road_info.curve = 0.0;
118
  actual_road_info.opps_number = 0;
119
  actual_road_info.flag = ROAD_OK;
120
  actual_road_info.collision = NO_COLL;
121
  set_road_info(actual_road_info, road_status_cab);
122
 
123
  task_endcycle();
124
 
125
  while(1) {
126
    /* reads car informations */
127
    actual_car_status = get_car_status(car_status_cab);
128
 
129
    /* implementazione riconoscimento strada (sti cazzi!!!) */
130
    get_camera_car(image, actual_car_status);
131
    find_track(image, &actual_road_info);
132
    find_opps(image, &actual_road_info);
133
    find_collision(image, &actual_road_info, actual_car_status);
134
 
135
    sem_wait(&grx_mutex);
136
    grx_rect(sq1.x, sq1.y, sq2.x, sq2.y, cars[index].color);
137
    grx_putimage(im1.x, im1.y, im2.x, im2.y, image);
138
    sem_post(&grx_mutex);
139
 
140
    /* sends informations to control task */
141
    set_road_info(actual_road_info, road_status_cab);
142
    task_endcycle();
143
  }
144
 
145
}
146
 
147
/* ----------------------------------------------------------------- */
148
 
149
void find_collision(BYTE *image, road_info *info, car_status status)
150
{
151
  point_f lt,rt,lb,rb,ct;
152
  /* the lines used to scan the quadrilate */
153
  point_f height_line[CAR_HEIGHT];
154
  int i;
155
  BYTE pix;
156
 
157
  info->collision = NO_COLL;
158
 
159
  ct.x = status.pos.x + (float)(CAR_HEIGHT/2 + 1) * cos(degree_to_rad(status.orient));
160
  ct.y = status.pos.y - (float)(CAR_WIDTH/2 + 1) * sin(degree_to_rad(status.orient));
161
 
162
  lb.x = ct.x - (float)(CAR_WIDTH/2.0) * cos(degree_to_rad(90-status.orient));
163
  rb.x = ct.x + (float)(CAR_WIDTH/2.0) * cos(degree_to_rad(90-status.orient));
164
  lt.x = lb.x - (float)(CAR_HEIGHT) * cos(degree_to_rad(status.orient));
165
  rt.x = rb.x - (float)(CAR_HEIGHT) * cos(degree_to_rad(status.orient));
166
 
167
  lb.y = ct.y - (float)(CAR_WIDTH/2.0) * sin(degree_to_rad(90-status.orient));
168
  rb.y = ct.y + (float)(CAR_WIDTH/2.0) * sin(degree_to_rad(90-status.orient));
169
  lt.y = lb.y + (float)(CAR_HEIGHT) * sin(degree_to_rad(status.orient));
170
  rt.y = rb.y + (float)(CAR_HEIGHT) * sin(degree_to_rad(status.orient));
171
 
172
  sem_wait(&grx_mutex);
173
  scanline(height_line,rb.x,rb.y,rt.x,rt.y,CAR_HEIGHT);
174
  for (i=0; i < CAR_HEIGHT; i++) {
175
    pix = grx_getpixel(round(height_line[i].x),round(height_line[i].y));
176
    if (pix != OFFROAD_COLOR && pix != ROAD_COLOR)
177
      info->collision = COLLISION_RIGHT;
178
  }
179
  scanline(height_line,lb.x,lb.y,lt.x,lt.y,CAR_HEIGHT);
180
  for (i=0; i < CAR_HEIGHT; i++) {
181
    pix = grx_getpixel(round(height_line[i].x),round(height_line[i].y));
182
    if (pix != OFFROAD_COLOR && pix != ROAD_COLOR)
183
      info->collision = COLLISION_LEFT;
184
  }
185
  sem_post(&grx_mutex);
186
 
187
}
188
 
189
/* ----------------------------------------------------------------- */
190
 
191
/* Puts in a buffer the image viewed from the camera according to the car status */
192
void get_camera_car(BYTE *buffer, car_status status) {
193
  /*
194
   *  lt ------ rt
195
   *   |            |
196
   *   |            |
197
   *  lb --ct-- rb
198
   */
199
  point_f lt,rt,lb,rb,ct;
200
  /* the lines used to scan the quadrilate */
201
  point_f width_line[TEL_WIDTH];
202
  point_f height_line[TEL_HEIGHT];
203
  int i,j;
204
  int tmpx,tmpy,tx,ty;
205
  float x,y;
206
  BYTE *row;
207
 
208
  ct.x = status.pos.x + (float)(CAR_WIDTH/2 + 1) * cos(degree_to_rad(status.orient));
209
  ct.y = status.pos.y - (float)(CAR_WIDTH/2 + 1) * sin(degree_to_rad(status.orient));
210
 
211
  /* for now the visual starts from the center of the car */
212
  lb.x = ct.x - (float)(TEL_WIDTH/2.0) * cos(degree_to_rad(90-status.orient));
213
  rb.x = ct.x + (float)(TEL_WIDTH/2.0) * cos(degree_to_rad(90-status.orient));
214
  lt.x = lb.x + (float)(TEL_HEIGHT) * cos(degree_to_rad(status.orient));
215
  rt.x = rb.x + (float)(TEL_HEIGHT) * cos(degree_to_rad(status.orient));
216
 
217
  lb.y = ct.y - (float)(TEL_WIDTH/2.0) * sin(degree_to_rad(90-status.orient));
218
  rb.y = ct.y + (float)(TEL_WIDTH/2.0) * sin(degree_to_rad(90-status.orient));
219
  lt.y = lb.y - (float)(TEL_HEIGHT) * sin(degree_to_rad(status.orient));
220
  rt.y = rb.y - (float)(TEL_HEIGHT) * sin(degree_to_rad(status.orient));
221
 
222
  /* scan only 2 sense thanks to parallelism */
223
  /*  ^ <-(height)
224
   *  ! lt
225
   *  !  |
226
   *  !  |
227
   *  ! lb ------ rb )
228
   *  0 -------------> <-(width
229
   */
230
  /* the width_line coordinates are relative, so in the for cycle
231
     they are summarized to absolute height_line values */
232
  scanline(width_line,0,0,rb.x - lb.x,rb.y - lb.y,TEL_WIDTH);
233
  scanline(height_line,lb.x,lb.y,lt.x,lt.y,TEL_HEIGHT);
234
 
235
  /* First fill row TEL_HEIGHT-1 of image and so on until row 0  */
236
  sem_wait(&grx_mutex);
237
  for (i=0; i <  TEL_HEIGHT; i++) {
238
    x = height_line[i].x;
239
    y = height_line[i].y;
240
    row = &buffer[TEL_WIDTH * (TEL_HEIGHT-1-i)];
241
    for (j=0; j <  TEL_WIDTH; j++) {
242
      tmpx = round(x + width_line[j].x);
243
      tmpy = round(y + width_line[j].y);
244
 
245
      // Test rispetto ai bordi
246
      if (tmpx >= 0 && tmpx < SCREEN_WIDTH && tmpy >= 0 && tmpy < SCREEN_HEIGHT) {
247
        tx = tmpx - TRACK_X1-1;
248
        ty = tmpy - TRACK_Y1-1;
249
        if (tx >= 0 && tx < TRACK_WIDTH && ty >= 0 && ty < TRACK_HEIGHT)
250
          row[j] = grx_getpixel(tmpx,tmpy);
251
        else
252
          row[j] = OUT_OF_TRACK;
253
      } else {
254
        row[j] = OUT_OF_TRACK;
255
      }
256
    }
257
  }
258
  sem_post(&grx_mutex);
259
}
260
 
261
/* ----------------------------------------------------------------- */
262
 
263
void scanline(point_f *buffer, float x1, float y1, float x2, float y2, int factor) {
264
  int i;
265
  float x,y;
266
  float xstep,ystep;
267
 
268
  xstep = (x2 - x1) / factor;
269
  ystep = (y2 - y1) / factor;
270
 
271
  // Start scan at <x1, y1>
272
  x = x1;
273
  y = y1;
274
 
275
  for (i = 0; i < factor; i++) {
276
    buffer[i].x = x;
277
    buffer[i].y = y;
278
    x += xstep;
279
    y += ystep;
280
  }
281
}
282
 
283
/* ----------------------------------------------------------------- */
284
 
285
/*
286
 * Approssima la curva quando non è più possibile farlo con la scansione
287
 * orizzontale
288
 * - image
289
 * - index              l'indice da cui cominciare la ricerca della curva
290
 * - distance   la distanza dalla curva
291
 */
292
float approx_curve(BYTE *image, int index, int distance, int d_center, road_strip *strips) {
293
  BYTE *p,tmp;
294
  int i,j,k,ctrl=0;
295
  point ms_center,ct;
296
 
297
  // Decide se la curva e' verso sinistra o verso destra
298
  p = &image[(TEL_HEIGHT - index - 1) * TEL_WIDTH];
299
 
300
  ms_center.x = strips[index-1].left;
301
  for (i = 0; i < min(3,strips[index-1].left); i++) {
302
    // La curva è a destra
303
    tmp = *(p + round(ms_center.x) - i);
304
    if (tmp != ROAD_COLOR) {
305
      ms_center.x = strips[index-1].right;
306
      break;
307
    }
308
  }
309
 
310
  p += round(ms_center.x);
311
  // Scandisce la colonna fino alla fine della strada
312
  for (i = index; i < TEL_HEIGHT; i++, p -= TEL_WIDTH) {
313
    if (*p != ROAD_COLOR)       break;
314
  }
315
 
316
  // Imposta il nuovo max_scost empirico
317
  ms_center.y = (i-1 + index) / 2;
318
 
319
  // i-1 è l'indice dell'ultima riga bianca
320
  p = &image[(TEL_HEIGHT - (i-1) - 1) * TEL_WIDTH + round(ms_center.x)];
321
  // scandisce da destra a sinistra
322
  if (round(ms_center.x) > 0) {
323
    for (j = 0; j < (round(ms_center.x) - strips[index-1].left); j++, p--) {
324
      if (*p != ROAD_COLOR)     break;
325
      // scandisce dall'alto in basso finchè non trova nero
326
      for (k = i-1; k > index; k--) {
327
        tmp = *(p + (i-1-k)*TEL_WIDTH);
328
        if (tmp != ROAD_COLOR) {
329
          ms_center.y = (k + index) / 2;
330
          ctrl = 1;
331
          break;
332
        }
333
      }
334
      if (ctrl) break;
335
    }
336
    ct.x = ms_center.x - j/2;
337
    ct.y = ms_center.y;
338
  } else {
339
    // scandisce da sinistra a destra
340
    for (j = 0; j < (strips[index-1].right - round(ms_center.x)); j++, p++) {
341
      if (*p != ROAD_COLOR)     break;
342
      // scandisce dall'alto in basso finchè non trova nero
343
      for (k = i-1; k > index; k--) {
344
        tmp = *(p + (i-1-k)*TEL_WIDTH);
345
        if (tmp != ROAD_COLOR) {
346
          ms_center.y = (k + index) / 2;
347
          ctrl = 1;
348
          break;
349
        }
350
      }
351
      if (ctrl) break;
352
    }
353
    ct.x = ms_center.x + j/2;
354
    ct.y = ms_center.y;
355
  }
356
 
357
  return rad_to_degree(atan2((double)(ct.y - distance),(double)(ct.x - d_center)));
358
}
359
 
360
/* ----------------------------------------------------------------- */
361
 
362
int find_distance(road_strip *strips, int max_scost, int rett_tol) {
363
  int i, distance;
364
  int center_car = TEL_WIDTH/2;
365
 
366
  // La distanza non puo' essere maggiore del max_scost
367
  distance = max_scost;
368
 
369
  for (i=1; i < max_scost; i++) {
370
    // Calcola la distanza dalla curva
371
    if (abs(strips[i].center - center_car) > rett_tol) {
372
      distance = i;
373
      break;
374
    }
375
  }
376
  return distance;
377
}
378
 
379
/* ----------------------------------------------------------------- */
380
 
381
/* Scandisce la linea row e inserisce nella strip index le informazioni.
382
 * Ritorna 1 se trova entrambi i bordi, altrimenti 0
383
 */
384
int scan_strip(BYTE *row, int index, road_strip *strips) {
385
  // Tiene conto della posizione dei bordi precedenti per trattare
386
  // meglio il caso di curve molto strette, dove possono esistere
387
  // 2 bordi destri o sinistri
388
 
389
  // Per evitare problemi nei casi in cui siano possibili 2
390
  // bordi destri o sinistri
391
  int lfound = 0;
392
  int rfound = 0;
393
  int center_car = TEL_WIDTH/2;
394
  int i;
395
 
396
  // Parte dal secondo pixel e finisce al penultimo
397
  for(i=1; i < (TEL_WIDTH-1); i++) {
398
    // Se trova la strada controlla se si tratta di bordo
399
    // destro o sinistro
400
    if (row[i] == ROAD_COLOR) {
401
      // bordo sinistro
402
      if (row[i - 1] != ROAD_COLOR) {
403
                                // Se ho già trovato questo tipo di bordo cerco
404
                                // quello + plausibile ...
405
        if (lfound) {
406
          // Test sulla striscia precedente
407
          if (index > 0) {
408
            if (abs(i - strips[index-1].left) <
409
                abs(strips[index].left - strips[index-1].left))
410
              strips[index].left = i;
411
          } else {
412
            // Test sul centro della macchina
413
            if (abs(i - center_car) < abs(strips[0].left - center_car))
414
              strips[index].left = i;
415
          }
416
          lfound++;
417
        } else {
418
          // ... altrimenti lo inizializzo
419
          strips[index].left = i;
420
          lfound = 1;
421
        }
422
                                // bordo destro
423
      } else if ((row[i + 1] != ROAD_COLOR) && lfound) {
424
                                // Se ho già trovato questo tipo di bordo cerco
425
                                // quello + plausibile ...
426
        if (rfound) {
427
          // Test sulla striscia precedente
428
          if (index > 0) {
429
            if (abs(i - strips[index-1].right) <
430
                abs(strips[index].right - strips[index-1].right))
431
              strips[index].right = i;
432
          } else {
433
            // Test sul centro della macchina
434
            if (abs(i - center_car) < abs(strips[0].right - center_car))
435
              strips[index].right = i;
436
          }
437
          rfound++;
438
        } else {
439
          // ... altrimenti lo inizializzo
440
          strips[index].right = i;
441
          rfound = 1;
442
        }
443
      }
444
    }
445
  }
446
 
447
  // Calcola il centro della strada se trova i bordi
448
  if (lfound && rfound)
449
    strips[index].center = (strips[index].left + strips[index].right) / 2;
450
 
451
  return (lfound && rfound);
452
}
453
 
454
/* ----------------------------------------------------------------- */
455
 
456
void where_am_i(BYTE *row, road_strip strip, road_info *info) {
457
  int i;
458
  int lfound = 0;
459
  int rfound = 0;
460
  int car_center = TEL_WIDTH/2;
461
 
462
  for(i=1; i < (TEL_WIDTH-1); i++) {
463
    // Se trova la strada controlla se si tratta di bordo
464
    // destro o sinistro
465
    if (row[i] == ROAD_COLOR) {
466
      // bordo sinistro
467
      if (row[i - 1] != ROAD_COLOR) {
468
        strip.left = i;
469
        lfound = 1;
470
        break;
471
      } else if (row[i + 1] != ROAD_COLOR) {
472
        strip.right = i;
473
        rfound = 1;
474
        break;
475
      }
476
    }
477
  }
478
 
479
  if (lfound && rfound) {
480
    info->flag = ROAD_OK;
481
  }
482
  else if (lfound && !rfound)   info->flag = LEFT_ONLY;
483
  else if (!lfound && rfound)    info->flag = RIGHT_ONLY;
484
  else {
485
    if (row[car_center] == OFFROAD_COLOR) info->flag = NO_ROAD;
486
    else    info->flag = ROAD_OK;
487
  }
488
  info->left_border = car_center - strip.left;
489
  info->right_border = strip.right - car_center;
490
}
491
 
492
/* ----------------------------------------------------------------- */
493
 
494
/* Analizza l'immagine vista dalla telecamera inserendo le informazioni
495
 * necessarie in info, ovvero la distanza dai bordi destro e sinistro,
496
 * la distanza dalla prossima curva e il suo angolo di curvatura.
497
 * Per il momento ritorna -1 se non riesce a trovare entrambi i bordi della
498
 * strada; in futuro gestiremo anche questa situazione.
499
 */
500
int find_track(BYTE *image, road_info *info) {
501
  // vettore contenente le informazioni su ogni striscia
502
  road_strip strips[TEL_HEIGHT];
503
  BYTE *row;
504
  int car_center = TEL_WIDTH/2;
505
  int max_scost=0;
506
  int once_scost=0;
507
  int j, rett_tol=0;
508
 
509
  info->flag = ROAD_OK;
510
 
511
  strips[0].left = STRIP_DEFAULT;
512
  strips[0].right = STRIP_DEFAULT;
513
  /* Tratta in modo personalizzato il primo tratto di strada per
514
     inizializzare alcune variabili e per capire situazioni particolari */
515
  row = &image[(TEL_HEIGHT - 1)*TEL_WIDTH];
516
  // Se trova i bordi ...
517
  if (scan_strip(row,0,strips)) {
518
    // ... calcola i bordi della strada e ...
519
    info->left_border = car_center - strips[0].left;
520
    info->right_border = strips[0].right - car_center;
521
    // ... inizializza la tolleranza per il rettilineo.
522
    rett_tol = (strips[0].right - strips[0].left) / TOLL_FACTOR;
523
  } else {
524
    // Se non trova il bordo ...
525
    // Mi sono perso, cercami la strada
526
    where_am_i(row,strips[0],info);
527
    return 1;
528
  }
529
 
530
  /* Ora controlla le altre strisce della strada */
531
 
532
  for(j=1; j < TEL_HEIGHT ; j++) {
533
    row = &image[(TEL_HEIGHT - j - 1)*TEL_WIDTH];
534
    // Se trova i bordi ...
535
    if (scan_strip(row, j, strips)) {
536
      // ... aggiorna l'indice di max scostamento.
537
      if (abs(strips[j].center - car_center) >
538
          abs(strips[max_scost].center - car_center)
539
          && abs(strips[j].center - car_center) > rett_tol) {
540
 
541
        max_scost = j;
542
        once_scost=1; // ha trovato almeno un max scost
543
      }
544
    } else {
545
      // Se max_scost non è mai stato settato, prendo il max
546
      if (!once_scost) {
547
        max_scost = j-1;
548
        once_scost = 1;
549
      }
550
 
551
      // se la distanza e il max_scost sono troppo vicini approssima la curva
552
      info->distance = find_distance(strips, max_scost, rett_tol);
553
      if ((max_scost - info->distance) < MIN_DIFF) {
554
        info->curve = approx_curve(image, j, info->distance,
555
                                   strips[info->distance].center,strips) - 90.0;
556
        return 1;
557
      }
558
      break;
559
    }
560
  }
561
 
562
  // Se max_scost non è mai stato settato, prendo il max
563
  if (!once_scost)      max_scost = TEL_HEIGHT-1;
564
  max_scost = min(max_scost,TEL_HEIGHT-1);
565
 
566
  info->distance = find_distance(strips,max_scost,rett_tol);
567
 
568
  // calcola l'angolo di curvatura solo se il conto e' attendibile
569
  if ((info->distance < (TEL_HEIGHT*0.9)) &&
570
      ((max_scost - info->distance) >= MIN_DIFF))
571
    info->curve = rad_to_degree(atan2((double)(max_scost - info->distance),
572
                                      (double)(strips[max_scost].center - strips[info->distance].center)));
573
  else {
574
    // se i conti sono empirici, si guarda la posizione dei due centri
575
    if (strips[max_scost].center > strips[info->distance].center)
576
      info->curve = 88.0;
577
    else if (strips[max_scost].center < strips[info->distance].center)
578
      info->curve = 92.0;
579
    else
580
      info->curve = 90.0;
581
  }
582
  info->curve -= 90.0;
583
  return 0;
584
}
585
 
586
/* ----------------------------------------------------------------- */
587
 
588
int find_opps(BYTE *image, road_info *info)
589
{
590
  int i, j;
591
  int l_limit, r_limit;         // the opposite empiric limits
592
  BYTE *row;
593
  int car_center = TEL_WIDTH/2;
594
  int opps_number = 0;
595
 
596
  // by default it needs to scan the entire row
597
  l_limit = TEL_WIDTH - 1;
598
  r_limit = 0;
599
 
600
  // Scans one row at a time
601
  for(j=1; j<TEL_HEIGHT; j++) {
602
    row = &image[(TEL_HEIGHT - j - 1) * TEL_WIDTH];
603
 
604
    // if some of the previous row has been identified as a car...
605
    if (opps_number > 0 &&
606
        j < (info->opps_list[opps_number - 1].y + CAR_HEIGHT + 1)) {
607
      // excludes CAR_HEIGHT lines from the bottom if the car
608
      l_limit = (car_center + info->opps_list[opps_number - 1].x) - CAR_WIDTH;
609
      r_limit = (car_center + info->opps_list[opps_number - 1].x) + CAR_WIDTH;
610
    }
611
    else {
612
      // it needs to scan the entire row
613
      l_limit = TEL_WIDTH - 1;
614
      r_limit = 0;
615
    }
616
 
617
    // Scans the current row
618
    for (i=0; i<TEL_WIDTH; i++) {
619
      if( (i < l_limit || i > r_limit) &&
620
          row[i] != ROAD_COLOR && row[i] != OFFROAD_COLOR &&
621
          row[i] != DEBUG_COLOR && row[i] != OUT_OF_TRACK) {
622
                                // there is an opponent car!!
623
                                // stores its position
624
        info->opps_list[opps_number].x = i - car_center;                // left -, right +
625
        info->opps_list[opps_number].y = j;
626
 
627
                                // increases number of opposites car in the sensor view range
628
        opps_number++;
629
      }
630
    }
631
  }
632
 
633
  info->opps_number = opps_number;
634
 
635
  return 0;
636
}
637
 
638
 
639
 
640
 
641
 
642
 
643
 
644
 
645
 
646
 
647
 
648
 
649
 
650