Fawkes API  Fawkes Development Version
beams.cpp
1 
2 /***************************************************************************
3  * beams.cpp - Scanline model implementation: beams
4  *
5  * Created: Tue Apr 17 21:09:46 2007
6  * Copyright 2005-2007 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <core/exception.h>
25 #include <fvmodels/scanlines/beams.h>
26 
27 #include <cmath>
28 
29 using fawkes::upoint_t;
30 
31 namespace firevision {
32 
33 /** @class ScanlineBeams <fvmodels/scanlines/beams.h>
34  * Raytraced beams scanline model.
35  * This model uses a defined number of beams shot from the bottom of the image
36  * towards the top using Bresenham. With this you can have kind of a radar-like
37  * scanline model. Additionally the starting points at the bottom can be
38  * distributed over the full width of the image which alles for a scan aligned
39  * to the image.
40  *
41  * To ease the calculation of the finished state the very last point is traversed
42  * twice.
43  *
44  * @author Tim Niemueller
45  */
46 
47 /** Construtor.
48  * @param image_width image width
49  * @param image_height image height
50  * @param start_x x coordinate of the starting point, ignored if distributed (see below)
51  * @param start_y y coordinate of the starting point, this is the lowest points of the
52  * the lines and should thus be close to the bottom of the image
53  * @param stop_y Y coordinate for stopping the traversal
54  * @param offset_y number of pixel to advance in Y-direction per iteration
55  * @param distribute_start_x set to true, to distribute the start x coordinates
56  * equidistant over the whole width of the image.
57  * @param angle_from angle to start the scan at, a straight vertical line means
58  * zero rad, clock-wise positive, in radians
59  * @param angle_range the range to use to distribute the beams, clockwise positive,
60  * in radians
61  * @param num_beams number of beams to use
62  * @exception Exception thrown if parameters are out of bounds
63  */
64 ScanlineBeams::ScanlineBeams(unsigned int image_width,
65  unsigned int image_height,
66  unsigned int start_x,
67  unsigned int start_y,
68  unsigned int stop_y,
69  unsigned int offset_y,
70  bool distribute_start_x,
71  float angle_from,
72  float angle_range,
73  unsigned int num_beams)
74 {
75  if (start_y < stop_y)
76  throw fawkes::Exception("start_y < stop_y");
77  if ((stop_y > image_height) || (start_y > image_height)) {
78  throw fawkes::Exception("(stop_y > height) || (start_y > height)");
79  }
80 
81  this->start_x = start_x;
82  this->start_y = start_y;
83  this->angle_from = angle_from;
84  this->angle_range = angle_range;
85  this->num_beams = num_beams;
86  this->stop_y = stop_y;
87  this->offset_y = offset_y;
88  this->image_width = image_width;
89  this->image_height = image_height;
90  this->distribute_start_x = distribute_start_x;
91 
92  reset();
93 }
94 
97 {
98  return coord;
99 }
100 
101 upoint_t *
103 {
104  return &coord;
105 }
106 
107 bool
109 {
110  return _finished;
111 }
112 
113 void
114 ScanlineBeams::advance()
115 {
116  while (!_finished && (first_beam < last_beam)) {
117  unsigned int x_start = beam_current_pos[next_beam].x;
118  unsigned int y_start = beam_current_pos[next_beam].y;
119 
120  unsigned int x_end = beam_end_pos[next_beam].x;
121  unsigned int y_end = beam_end_pos[next_beam].y;
122 
123  int x, y, dist, xerr, yerr, dx, dy, incx, incy;
124 
125  // calculate distance in both directions
126  dx = x_end - x_start;
127  dy = y_end - y_start;
128 
129  // Calculate sign of the increment
130  if (dx < 0) {
131  incx = -1;
132  dx = -dx;
133  } else {
134  incx = dx ? 1 : 0;
135  }
136 
137  if (dy < 0) {
138  incy = -1;
139  dy = -dy;
140  } else {
141  incy = dy ? 1 : 0;
142  }
143 
144  // check which distance is larger
145  dist = (dx > dy) ? dx : dy;
146 
147  // Initialize for loops
148  x = x_start;
149  y = y_start;
150  xerr = dx;
151  yerr = dy;
152 
153  /* Calculate and draw pixels */
154  unsigned int offset = 0;
155  while ((x >= 0) && ((unsigned int)x < image_width) && ((unsigned int)y > stop_y)
156  && (offset < offset_y)) {
157  ++offset;
158 
159  xerr += dx;
160  yerr += dy;
161 
162  if (xerr > dist) {
163  xerr -= dist;
164  x += incx;
165  }
166 
167  if (yerr > dist) {
168  yerr -= dist;
169  y += incy;
170  }
171  }
172  if ((y < 0) || (unsigned int)y <= stop_y) {
173  _finished = true;
174  break;
175  }
176  if (x < 0) {
177  first_beam = ++next_beam;
178  continue;
179  }
180  if ((unsigned int)x > image_width) {
181  last_beam = next_beam - 1;
182  next_beam = first_beam;
183  continue;
184  }
185 
186  coord.x = x;
187  coord.y = y;
188 
189  beam_current_pos[next_beam] = coord;
190 
191  if (next_beam < last_beam) {
192  ++next_beam;
193  } else {
194  next_beam = first_beam;
195  }
196  break;
197  }
198 }
199 
200 upoint_t *
202 {
203  advance();
204  return &coord;
205 }
206 
207 upoint_t *
209 {
210  tmp_coord.x = coord.x;
211  tmp_coord.y = coord.y;
212  advance();
213  return &tmp_coord;
214 }
215 
216 void
218 {
219  _finished = false;
220 
221  beam_current_pos.clear();
222  if (distribute_start_x) {
223  unsigned int offset_start_x = image_width / (num_beams - 1);
224  for (unsigned int i = 0; i < num_beams; ++i) {
225  coord.x = i * offset_start_x;
226  coord.y = start_y;
227  beam_current_pos.push_back(coord);
228  }
229  coord.x = beam_current_pos[0].x;
230  coord.y = beam_current_pos[0].y;
231  } else {
232  coord.x = start_x;
233  coord.y = start_y;
234  beam_current_pos.resize(num_beams, coord);
235  }
236 
237  beam_end_pos.clear();
238  next_beam = 0;
239  float angle_between_beams = angle_range / num_beams;
240  for (unsigned int i = 0; i < num_beams; ++i) {
241  float diff_y = beam_current_pos[i].y - stop_y;
242  float diff_x = diff_y * tan(angle_from + (float)i * angle_between_beams);
243  upoint_t end_point;
244  end_point.y = stop_y;
245  end_point.x = (int)roundf(diff_x) + start_x;
246  beam_end_pos.push_back(end_point);
247  }
248  first_beam = 0;
249  last_beam = beam_end_pos.size() - 1;
250 }
251 
252 const char *
254 {
255  return "ScanlineModel::Beams";
256 }
257 
258 unsigned int
260 {
261  return offset_y;
262 }
263 
264 } // end namespace firevision
Base class for exceptions in Fawkes.
Definition: exception.h:36
void reset()
Reset model.
Definition: beams.cpp:217
ScanlineBeams(unsigned int image_width, unsigned int image_height, unsigned int start_x, unsigned int start_y, unsigned int stop_y, unsigned int offset_y, bool distribute_start_x, float angle_from, float angle_range, unsigned int num_beams)
Construtor.
Definition: beams.cpp:64
unsigned int get_margin()
Get margin around points.
Definition: beams.cpp:259
const char * get_name()
Get name of scanline model.
Definition: beams.cpp:253
fawkes::upoint_t * operator->()
Get pointer to current point.
Definition: beams.cpp:102
fawkes::upoint_t * operator++()
Postfix ++ operator.
Definition: beams.cpp:201
fawkes::upoint_t operator*()
Get the current coordinate.
Definition: beams.cpp:96
bool finished()
Check if all desired points have been processed.
Definition: beams.cpp:108
Point with cartesian coordinates as unsigned integers.
Definition: types.h:35
unsigned int x
x coordinate
Definition: types.h:36
unsigned int y
y coordinate
Definition: types.h:37