radial.cpp

00001
00002 /***************************************************************************
00003  *  radial.cpp - Implementation of the radial scanline model
00004  *
00005  *  Generated: Tue Jul 19 12:46:52 2005
00006  *  Copyright  2005  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <models/scanlines/radial.h>
00025
00026 #include <utils/system/console_colors.h>
00027
00028 #include <cmath>
00029 #include <cstring>
00030
00031 using fawkes::point_t;
00032 
00033 /** @class ScanlineRadial <models/scanlines/radial.h>
00034  * Radial scanlines.
00035  * Uses circles to generate scanline points. A dead radius is ignored in the
00036  * center of the image (for example for the camera itself in an omni-vision system).
00037  * From there circles are used in radius_increment distances. On each circle points are
00038  * generated in a distance of about step pixels. This is done up to a given maximum
00039  * radius. If no maximum radius is supplied (max_radius=0) it is automatically
00040  * calculated depending on the image size.
00041  */
00042 
00043 /** Constructor.
00044  * @param width image width
00045  * @param height image height
00046  * @param center_x radial center center x
00047  * @param center_y radial center center y
00048  * @param radius_increment radius increment
00049  * @param step step
00050  * @param max_radius maximum radius, if set to 0 will be calculated
00051  * automatically depending on the image dimensions.
00052  * @param dead_radius inner radius to ignore
00053  */
00054 ScanlineRadial::ScanlineRadial(unsigned int width, unsigned int height,
00055                                unsigned int center_x, unsigned int center_y,
00056                                unsigned int radius_increment,
00057                                unsigned int step,
00058                                unsigned int max_radius, unsigned int dead_radius
00059                                )
00060 {
00061   this->width            = width;
00062   this->height           = height;
00063   this->center_x         = center_x;
00064   this->center_y         = center_y;
00065   this->radius_increment = radius_increment;
00066   this->step             = step;
00067   this->dead_radius      = dead_radius;
00068   this->max_radius       = max_radius;
00069   this->auto_max_radius  = (max_radius == 0);
00070
00071   reset();
00072 }
00073
00074 point_t
00075 ScanlineRadial::operator*()
00076 {
00077   return coord;
00078 }
00079
00080 point_t*
00081 ScanlineRadial::operator->()
00082 {
00083   return &coord;
00084 }
00085
00086 point_t *
00087 ScanlineRadial::operator++()
00088 {
00089
00090   if ( done ) return &coord;
00091
00092   bool ok = false;
00093
00094   do {
00095
00096     tmp_x = 0;
00097     tmp_y = 0;
00098
00099     if ( current_radius == 0 ) {
00100       // Special case, after first reset
00101       current_radius += radius_increment;
00102       x = 0;
00103       y = current_radius;
00104       ok = true;
00105     } else {
00106
00107       if ( x < y ) {
00108
00109         switch (sector) {
00110         case 0:
00111           tmp_x = x;
00112           tmp_y = -y;
00113           break;
00114
00115         case 1:
00116           tmp_x = y;
00117           tmp_y = -x;
00118           break;
00119
00120         case 2:
00121           tmp_x = y;
00122           tmp_y = x;
00123           break;
00124
00125         case 3:
00126           tmp_x = x;
00127           tmp_y = y;
00128           break;
00129
00130         case 4:
00131           tmp_x = -x;
00132           tmp_y = y;
00133           break;
00134
00135         case 5:
00136           tmp_x = -y;
00137           tmp_y = x;
00138           break;
00139
00140         case 6:
00141           tmp_x = -y;
00142           tmp_y = -x;
00143           break;
00144
00145         case 7:
00146           tmp_x = -x;
00147           tmp_y = -y;
00148           break;
00149
00150         default:
00151           tmp_x = 0;
00152           tmp_y = 0;
00153           break;
00154
00155         }
00156
00157         x += step;
00158         y = (int)(sqrt( (float(current_radius * current_radius) - float(x * x)) ) + 0.5);
00159
00160         ok = true;
00161
00162       } else {
00163         //      cout << "x !< y" << endl;
00164         if (sector == 7) {
00165           // Need to go to next circle
00166           current_radius += radius_increment;
00167           x = 0;
00168           y = current_radius;
00169           sector = 0;
00170           if (current_radius >= max_radius) { done = true; ok = true; }
00171         } else {
00172           sector += 1;
00173           x = 0;
00174           y = current_radius;
00175         }
00176       }
00177
00178     }
00179
00180     if ( (tmp_x < -(int)center_x) ||
00181          (tmp_x > (int)(width - center_x)) ||
00182          (tmp_y < -(int)center_y) ||
00183          (tmp_y > (int)(height - center_y))
00184          ) {
00185       coord.x = 0;
00186       coord.y = 0;
00187       // out of image, not ok
00188       ok = false;
00189       //done = true;
00190     } else {
00191       coord.x = center_x + tmp_x;
00192       coord.y = center_y + tmp_y;
00193     }
00194
00195   } while (! ok);
00196
00197   return &coord;
00198 }
00199
00200 point_t *
00201 ScanlineRadial::operator++(int)
00202 {
00203   memcpy(&tmp_coord, &coord, sizeof(point_t));
00204   return &tmp_coord;
00205 }
00206
00207 bool
00208 ScanlineRadial::finished()
00209 {
00210   return done;
00211 }
00212
00213 
00214 /** Do a simple sort of the given array, sorted descending, biggest first
00215  * this sort is stable
00216  */
00217 void
00218 ScanlineRadial::simpleBubbleSort(unsigned int array[], unsigned int num_elements)
00219 {
00220   bool modified = false;
00221   unsigned int end = num_elements;
00222   unsigned int tmp;
00223   do {
00224     modified = false;
00225
00226     for (unsigned int i = 0; i < end-1; ++i) {
00227       if ( array[i] < array[i+1] ) {
00228         tmp        = array[i];
00229         array[i]   = array[i+1];
00230         array[i+1] = tmp;
00231         end -= 1;
00232         modified = true;
00233       }
00234     }
00235
00236   } while ( modified );
00237 }
00238
00239 void
00240 ScanlineRadial::reset()
00241 {
00242   current_radius = radius_increment;
00243   while (current_radius < dead_radius) {
00244     current_radius += radius_increment;
00245   }
00246   x = 0;
00247   y = current_radius;
00248   sector = 0;
00249
00250   coord.x = center_x;
00251   coord.y = center_y;
00252
00253   if ( auto_max_radius ) {
00254     // Calculate distances to corners of image
00255     unsigned int dists[4];
00256     dists[0] = (unsigned int)sqrt( float(center_x * center_x) + float(center_y * center_y) );
00257     dists[1] = (unsigned int)sqrt( float((width - center_x) * (width - center_x)) + float(center_y * center_y) );
00258     dists[2] = (unsigned int)sqrt( float((width - center_x) * (width - center_x)) + float((height - center_y) * (height - center_y)) );
00259     dists[3] = (unsigned int)sqrt( float(center_x * center_x) + float((height - center_y) * (height - center_y)) );
00260
00261     // now the maximum corner distance is the maximum radius
00262     simpleBubbleSort(dists, 4);
00263     max_radius = dists[0] - 1;
00264   }
00265
00266   done = false;
00267
00268   if (radius_increment > max_radius) {
00269     // cout << msg_prefix << cred << "radius_increment > max_radius, resetting radius_increment to one!" << cnormal << endl;
00270     radius_increment = 1;
00271   }
00272
00273   if (dead_radius > max_radius) {
00274     // cout << msg_prefix << cred << "dead_radius > max_radius, resetting dead_radius to zero!" << cnormal << endl;
00275     dead_radius = 0;
00276     current_radius = radius_increment;
00277   }
00278
00279 }
00280
00281 const char *
00282 ScanlineRadial::get_name()
00283 {
00284   return "ScanlineModel::Radial";
00285 }
00286
00287
00288 unsigned int
00289 ScanlineRadial::get_margin()
00290 {
00291   return radius_increment;
00292 }
00293
00294 
00295 /** Set new center point.
00296  * Sets new center point to move around the scanlines in the image.
00297  * Does an implicit reset().
00298  * @param center_x x coordinate of the new center
00299  * @param center_y y coordinate of the new center
00300  */
00301 void
00302 ScanlineRadial::set_center(unsigned int center_x, unsigned int center_y)
00303 {
00304   this->center_x = center_x;
00305   this->center_y = center_y;
00306   reset();
00307 }
00308
00309 
00310 /** Set new radius.
00311  * Sets the new maximum and dead radius. Does an implicit reset().
00312  * @param dead_radius new dead radius
00313  * @param max_radius new maximum radius, if set to 0 this is automatically
00314  * calculated depending on the image size.
00315  */
00316 void
00317 ScanlineRadial::set_radius(unsigned int dead_radius, unsigned int max_radius)
00318 {
00319   this->max_radius      = 0;
00320   this->dead_radius     = dead_radius;
00321   this->auto_max_radius = (max_radius == 0);
00322
00323   reset();
00324 }