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 
96 {
97  return coord;
98 }
99 
101 {
102  return &coord;
103 }
104 
105 bool
107 {
108  return _finished;
109 }
110 
111 void
112 ScanlineBeams::advance()
113 {
114  while (!_finished && (first_beam < last_beam)) {
115  unsigned int x_start = beam_current_pos[next_beam].x;
116  unsigned int y_start = beam_current_pos[next_beam].y;
117 
118  unsigned int x_end = beam_end_pos[next_beam].x;
119  unsigned int y_end = beam_end_pos[next_beam].y;
120 
121  int x, y, dist, xerr, yerr, dx, dy, incx, incy;
122 
123  // calculate distance in both directions
124  dx = x_end - x_start;
125  dy = y_end - y_start;
126 
127  // Calculate sign of the increment
128  if (dx < 0) {
129  incx = -1;
130  dx = -dx;
131  } else {
132  incx = dx ? 1 : 0;
133  }
134 
135  if (dy < 0) {
136  incy = -1;
137  dy = -dy;
138  } else {
139  incy = dy ? 1 : 0;
140  }
141 
142  // check which distance is larger
143  dist = (dx > dy) ? dx : dy;
144 
145  // Initialize for loops
146  x = x_start;
147  y = y_start;
148  xerr = dx;
149  yerr = dy;
150 
151  /* Calculate and draw pixels */
152  unsigned int offset = 0;
153  while ((x >= 0) && ((unsigned int)x < image_width) && ((unsigned int)y > stop_y)
154  && (offset < offset_y)) {
155  ++offset;
156 
157  xerr += dx;
158  yerr += dy;
159 
160  if (xerr > dist) {
161  xerr -= dist;
162  x += incx;
163  }
164 
165  if (yerr > dist) {
166  yerr -= dist;
167  y += incy;
168  }
169  }
170  if ((y < 0) || (unsigned int)y <= stop_y) {
171  _finished = true;
172  break;
173  }
174  if (x < 0) {
175  first_beam = ++next_beam;
176  continue;
177  }
178  if ((unsigned int)x > image_width) {
179  last_beam = next_beam - 1;
180  next_beam = first_beam;
181  continue;
182  }
183 
184  coord.x = x;
185  coord.y = y;
186 
187  beam_current_pos[next_beam] = coord;
188 
189  if (next_beam < last_beam) {
190  ++next_beam;
191  } else {
192  next_beam = first_beam;
193  }
194  break;
195  }
196 }
197 
198 upoint_t *
200 {
201  advance();
202  return &coord;
203 }
204 
205 upoint_t *
207 {
208  tmp_coord.x = coord.x;
209  tmp_coord.y = coord.y;
210  advance();
211  return &tmp_coord;
212 }
213 
214 void
216 {
217  _finished = false;
218 
219  beam_current_pos.clear();
220  if (distribute_start_x) {
221  unsigned int offset_start_x = image_width / (num_beams - 1);
222  for (unsigned int i = 0; i < num_beams; ++i) {
223  coord.x = i * offset_start_x;
224  coord.y = start_y;
225  beam_current_pos.push_back(coord);
226  }
227  coord.x = beam_current_pos[0].x;
228  coord.y = beam_current_pos[0].y;
229  } else {
230  coord.x = start_x;
231  coord.y = start_y;
232  beam_current_pos.resize(num_beams, coord);
233  }
234 
235  beam_end_pos.clear();
236  next_beam = 0;
237  float angle_between_beams = angle_range / num_beams;
238  for (unsigned int i = 0; i < num_beams; ++i) {
239  float diff_y = beam_current_pos[i].y - stop_y;
240  float diff_x = diff_y * tan(angle_from + (float)i * angle_between_beams);
241  upoint_t end_point;
242  end_point.y = stop_y;
243  end_point.x = (int)roundf(diff_x) + start_x;
244  beam_end_pos.push_back(end_point);
245  }
246  first_beam = 0;
247  last_beam = beam_end_pos.size() - 1;
248 }
249 
250 const char *
252 {
253  return "ScanlineModel::Beams";
254 }
255 
256 unsigned int
258 {
259  return offset_y;
260 }
261 
262 } // end namespace firevision
bool finished()
Check if all desired points have been processed.
Definition: beams.cpp:106
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
fawkes::upoint_t operator*()
Get the current coordinate.
Definition: beams.cpp:95
unsigned int y
y coordinate
Definition: types.h:37
unsigned int x
x coordinate
Definition: types.h:36
const char * get_name()
Get name of scanline model.
Definition: beams.cpp:251
unsigned int get_margin()
Get margin around points.
Definition: beams.cpp:257
Base class for exceptions in Fawkes.
Definition: exception.h:35
fawkes::upoint_t * operator++()
Postfix ++ operator.
Definition: beams.cpp:199
void reset()
Reset model.
Definition: beams.cpp:215
Point with cartesian coordinates as unsigned integers.
Definition: types.h:34
fawkes::upoint_t * operator->()
Get pointer to current point.
Definition: beams.cpp:100