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
30
31namespace 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 */
64ScanlineBeams::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
101upoint_t *
103{
104 return &coord;
105}
106
107bool
109{
110 return _finished;
111}
112
113void
114ScanlineBeams::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
200upoint_t *
202{
203 advance();
204 return &coord;
205}
206
207upoint_t *
209{
210 tmp_coord.x = coord.x;
211 tmp_coord.y = coord.y;
212 advance();
213 return &tmp_coord;
214}
215
216void
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
252const char *
254{
255 return "ScanlineModel::Beams";
256}
257
258unsigned 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