Fawkes API Fawkes Development Version
drawer.cpp
1
2/***************************************************************************
3 * drawer.cpp - Utility to draw in a buffer
4 *
5 * Generated: Wed Feb 08 20:55:38 2006
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 <fvutils/color/yuv.h>
25#include <fvutils/draw/drawer.h>
26
27#include <algorithm>
28#include <cmath>
29#include <unistd.h>
30
31namespace firevision {
32
33/** @class Drawer <fvutils/draw/drawer.h>
34 * Draw to an image.
35 * @author Tim Niemueller
36 */
37
38/** Constructor.
39 * Default paint color is white.
40 */
42{
43 buffer_ = NULL;
44 color_ = YUV_t::white();
45}
46
47/** Destructor */
49{
50}
51
52/** Set the buffer to draw to
53 * @param buffer buffer to draw to, must be YUV422 planar formatted
54 * @param width width of the buffer
55 * @param height height of the buffer
56 */
57void
58Drawer::set_buffer(unsigned char *buffer, unsigned int width, unsigned int height)
59{
60 this->buffer_ = buffer;
61 this->width_ = width;
62 this->height_ = height;
63}
64
65/** Set drawing color.
66 * @param y Y component of YUV drawing color
67 * @param u U component of YUV drawing color
68 * @param v V component of YUV drawing color
69 */
70void
71Drawer::set_color(unsigned char y, unsigned char u, unsigned char v)
72{
73 color_.Y = y;
74 color_.U = u;
75 color_.V = v;
76}
77
78/** Set drawing color.
79 * @param color the YUV drawing color
80 */
81void
83{
84 color_ = color;
85}
86
87/** Draw circle.
88 * Draws a circle at the given center point and with the given radius.
89 * @param center_x x coordinate of circle center
90 * @param center_y y coordinate of circle center
91 * @param radius radius of circle
92 */
93void
94Drawer::draw_circle(int center_x, int center_y, unsigned int radius)
95{
96 if (buffer_ == NULL)
97 return;
98
99 unsigned int x = 0, y = radius, r2 = radius * radius;
100
101 unsigned char *up = YUV422_PLANAR_U_PLANE(buffer_, width_, height_);
102 unsigned char *vp = YUV422_PLANAR_V_PLANE(buffer_, width_, height_);
103
104 unsigned int x_tmp, y_tmp, ind_tmp;
105
106 while (x <= y) {
107 x_tmp = center_x + x;
108 y_tmp = center_y + y;
109 if ((x_tmp < width_) && (y_tmp < height_)) {
110 ind_tmp = y_tmp * width_ + x_tmp;
111 buffer_[ind_tmp] = color_.Y;
112 ind_tmp /= 2;
113 up[ind_tmp] = color_.U;
114 vp[ind_tmp] = color_.V;
115 }
116
117 x_tmp = center_x - x;
118 y_tmp = center_y + y;
119 if ((x_tmp < width_) && (y_tmp < height_)) {
120 ind_tmp = y_tmp * width_ + x_tmp;
121 buffer_[ind_tmp] = color_.Y;
122 ind_tmp /= 2;
123 up[ind_tmp] = color_.U;
124 vp[ind_tmp] = color_.V;
125 }
126
127 x_tmp = center_x + y;
128 y_tmp = center_y + x;
129 if ((x_tmp < width_) && (y_tmp < height_)) {
130 ind_tmp = y_tmp * width_ + x_tmp;
131 buffer_[ind_tmp] = color_.Y;
132 ind_tmp /= 2;
133 up[ind_tmp] = color_.U;
134 vp[ind_tmp] = color_.V;
135 }
136
137 x_tmp = center_x - y;
138 y_tmp = center_y + x;
139 if ((x_tmp < width_) && (y_tmp < height_)) {
140 ind_tmp = y_tmp * width_ + x_tmp;
141 buffer_[ind_tmp] = color_.Y;
142 ind_tmp /= 2;
143 up[ind_tmp] = color_.U;
144 vp[ind_tmp] = color_.V;
145 }
146
147 x_tmp = center_x + x;
148 y_tmp = center_y - y;
149 if ((x_tmp < width_) && (y_tmp < height_)) {
150 ind_tmp = y_tmp * width_ + x_tmp;
151 buffer_[ind_tmp] = color_.Y;
152 ind_tmp /= 2;
153 up[ind_tmp] = color_.U;
154 vp[ind_tmp] = color_.V;
155 }
156
157 x_tmp = center_x - x;
158 y_tmp = center_y - y;
159 if ((x_tmp < width_) && (y_tmp < height_)) {
160 ind_tmp = y_tmp * width_ + x_tmp;
161 buffer_[ind_tmp] = color_.Y;
162 ind_tmp /= 2;
163 up[ind_tmp] = color_.U;
164 vp[ind_tmp] = color_.V;
165 }
166
167 x_tmp = center_x + y;
168 y_tmp = center_y - x;
169 if ((x_tmp < width_) && (y_tmp < height_)) {
170 ind_tmp = y_tmp * width_ + x_tmp;
171 buffer_[ind_tmp] = color_.Y;
172 ind_tmp /= 2;
173 up[ind_tmp] = color_.U;
174 vp[ind_tmp] = color_.V;
175 }
176
177 x_tmp = center_x - y;
178 y_tmp = center_y - x;
179 if ((x_tmp < width_) && (y_tmp < height_)) {
180 ind_tmp = y_tmp * width_ + x_tmp;
181 buffer_[ind_tmp] = color_.Y;
182 ind_tmp /= 2;
183 up[ind_tmp] = color_.U;
184 vp[ind_tmp] = color_.V;
185 }
186
187 ++x;
188 y = (int)(sqrt((float)(r2 - x * x)) + 0.5);
189 }
190}
191
192/** Draw rectangle.
193 * @param x x coordinate of rectangle's upper left corner
194 * @param y y coordinate of rectangle's upper left corner
195 * @param w width of rectangle from x to the right
196 * @param h height of rectangle from y to the bottom
197 */
198void
199Drawer::draw_rectangle(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
200{
201 unsigned char *up = YUV422_PLANAR_U_PLANE(buffer_, width_, height_);
202 unsigned char *vp = YUV422_PLANAR_V_PLANE(buffer_, width_, height_);
203
204 // horizontal line at top
205 for (unsigned int i = x; i < x + w; ++i) {
206 if (i < width_) {
207 buffer_[y * width_ + i] = color_.Y;
208 up[(y * width_ + i) / 2] = color_.U;
209 vp[(y * width_ + i) / 2] = color_.V;
210 } else {
211 break;
212 }
213 }
214
215 // left and right
216 for (unsigned int i = y; i < y + h; ++i) {
217 // left
218 buffer_[i * width_ + x] = color_.Y;
219 up[(i * width_ + x) / 2] = color_.U;
220 vp[(i * width_ + x) / 2] = color_.V;
221
222 if ((x + w) < width_) {
223 // right
224 buffer_[i * width_ + x + w] = color_.Y;
225 up[(i * width_ + x + w) / 2] = color_.U;
226 vp[(i * width_ + x + w) / 2] = color_.V;
227 }
228 }
229
230 // horizontal line at bottom
231 for (unsigned int i = x; i < x + w; ++i) {
232 if (i < width_) {
233 buffer_[(y + h) * width_ + i] = color_.Y;
234 up[((y + h) * width_ + i) / 2] = color_.U;
235 vp[((y + h) * width_ + i) / 2] = color_.V;
236 } else {
237 break;
238 }
239 }
240}
241
242/** Draw inverted rectangle.
243 * This draws a rectangle but instead of using the draw color it is drawn
244 * in the inverted color of the pixel where it is drawn.
245 * @param x x coordinate of rectangle's upper left corner
246 * @param y y coordinate of rectangle's upper left corner
247 * @param w width of rectangle from x to the right
248 * @param h height of rectangle from y to the bottom
249 */
250void
251Drawer::draw_rectangle_inverted(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
252{
253 unsigned int ind = 0;
254
255 // horizontal line at top
256 for (unsigned int i = x; i < x + w; ++i) {
257 if (i < width_) {
258 ind = y * width_ + i;
259 buffer_[ind] = 255 - buffer_[ind];
260 } else {
261 break;
262 }
263 }
264
265 // left and right
266 for (unsigned int i = y; i < y + h; ++i) {
267 // left
268 ind = i * width_ + x;
269 buffer_[ind] = 255 - buffer_[ind];
270
271 if ((x + w) < width_) {
272 // right
273 ind += w;
274 buffer_[ind] = 255 - buffer_[ind];
275 }
276 }
277
278 // horizontal line at bottom
279 for (unsigned int i = x; i < x + w; ++i) {
280 if (i < width_) {
281 buffer_[ind] = 255 - buffer_[ind];
282 } else {
283 break;
284 }
285 }
286}
287
288/** Draw point.
289 * @param x x coordinate of point
290 * @param y y coordinate of point
291 */
292void
293Drawer::draw_point(unsigned int x, unsigned int y)
294{
295 if (x > width_)
296 return;
297 if (y > height_)
298 return;
299
300 unsigned char *up = YUV422_PLANAR_U_PLANE(buffer_, width_, height_);
301 unsigned char *vp = YUV422_PLANAR_V_PLANE(buffer_, width_, height_);
302
303 buffer_[y * width_ + x] = color_.Y;
304 up[(y * width_ + x) / 2] = color_.U;
305 vp[(y * width_ + x) / 2] = color_.V;
306}
307
308/** Color the given point.
309 * This will leave the Y-component of the given pixel unchanged and will
310 * just set the U and V components. This can be used to keep a little bit
311 * of original image information but marking special regions.
312 * @param x x coordinate of point
313 * @param y y coordinate of point
314 */
315void
316Drawer::color_point(unsigned int x, unsigned int y)
317{
318 if (x > width_)
319 return;
320 if (y > height_)
321 return;
322
323 unsigned char *up = YUV422_PLANAR_U_PLANE(buffer_, width_, height_);
324 unsigned char *vp = YUV422_PLANAR_V_PLANE(buffer_, width_, height_);
325
326 buffer_[y * width_ + x] = color_.Y;
327 up[(y * width_ + x) / 2] = color_.U;
328 vp[(y * width_ + x) / 2] = color_.V;
329}
330
331/** Color the given point.
332 * This will color a single point (to save excessive function calls the color
333 * is also a parameter)
334 * @param x x coordinate of point
335 * @param y y coordinate of point
336 * @param color Color to set
337 */
338void
339Drawer::color_point(unsigned int x, unsigned int y, YUV_t color)
340{
341 if (x > width_)
342 return;
343 if (y > height_)
344 return;
345
346 unsigned char *up = YUV422_PLANAR_U_PLANE(buffer_, width_, height_);
347 unsigned char *vp = YUV422_PLANAR_V_PLANE(buffer_, width_, height_);
348
349 buffer_[y * width_ + x] = color.Y;
350 up[(y * width_ + x) / 2] = color.U;
351 vp[(y * width_ + x) / 2] = color.V;
352}
353
354/** Draw line.
355 * Standard Bresenham in all directions. For in-depth information
356 * have a look at http://de.wikipedia.org/wiki/Bresenham-Algorithmus
357 * @param x_start x coordinate of start point
358 * @param y_start y coordinate of start point
359 * @param x_end x coordinate of end point
360 * @param y_end y coordinate of end point
361 */
362void
363Drawer::draw_line(unsigned int x_start,
364 unsigned int y_start,
365 unsigned int x_end,
366 unsigned int y_end)
367{
368 /* heavily inspired by an article on German Wikipedia about
369 * Bresenham's algorithm, confer
370 * http://de.wikipedia.org/wiki/Bresenham-Algorithmus
371 */
372
373 int x, y, dist, xerr, yerr, dx, dy, incx, incy;
374 bool was_inside_image = false;
375
376 unsigned char *up = YUV422_PLANAR_U_PLANE(buffer_, width_, height_);
377 unsigned char *vp = YUV422_PLANAR_V_PLANE(buffer_, width_, height_);
378
379 // calculate distance in both directions
380 dx = x_end - x_start;
381 dy = y_end - y_start;
382
383 // Calculate sign of the increment
384 if (dx < 0) {
385 incx = -1;
386 dx = -dx;
387 } else {
388 incx = dx ? 1 : 0;
389 }
390
391 if (dy < 0) {
392 incy = -1;
393 dy = -dy;
394 } else {
395 incy = dy ? 1 : 0;
396 }
397
398 // check which distance is larger
399 dist = (dx > dy) ? dx : dy;
400
401 // Initialize for loops
402 x = x_start;
403 y = y_start;
404 xerr = dx;
405 yerr = dy;
406
407 /* Calculate and draw pixels */
408 for (int t = 0; t < dist; ++t) {
409 if (((unsigned int)x < width_) && ((unsigned int)y < height_)) {
410 if ((x >= 0) && (y >= 0)) {
411 was_inside_image = true;
412 buffer_[y * width_ + x] = color_.Y;
413 up[(y * width_ + x) / 2] = color_.U;
414 vp[(y * width_ + x) / 2] = color_.V;
415 }
416 } else {
417 if (was_inside_image) {
418 break;
419 }
420 }
421
422 xerr += dx;
423 yerr += dy;
424
425 if (xerr > dist) {
426 xerr -= dist;
427 x += incx;
428 }
429
430 if (yerr > dist) {
431 yerr -= dist;
432 y += incy;
433 }
434 }
435
436 if ((x_end < width_) && (y_end < height_)) {
437 buffer_[y_end * width_ + x_end] = color_.Y;
438 up[(y_end * width_ + x_end) / 2] = color_.U;
439 vp[(y_end * width_ + x_end) / 2] = color_.V;
440 }
441}
442
443/** Draws a cross.
444 * @param x_center Center of the cross
445 * @param y_center Center of the cross
446 * @param width of the bars
447 */
448void
449Drawer::draw_cross(unsigned int x_center, unsigned int y_center, unsigned int width)
450{
451 x_center = std::min(x_center, width_);
452 y_center = std::min(y_center, height_);
453
454 int r = width / 2;
455 unsigned int a = std::max(0, (int)x_center - r);
456 unsigned int b = std::min(x_center + r, width_);
457 draw_line(a, y_center, b, y_center);
458
459 a = std::max(0, (int)y_center - r);
460 b = std::min(y_center + r, height_);
461 draw_line(x_center, a, x_center, b);
462}
463
464} // end namespace firevision
void color_point(unsigned int x, unsigned int y)
Color the given point.
Definition: drawer.cpp:316
void draw_rectangle_inverted(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
Draw inverted rectangle.
Definition: drawer.cpp:251
void set_color(unsigned char y, unsigned char u, unsigned char v)
Set drawing color.
Definition: drawer.cpp:71
~Drawer()
Destructor.
Definition: drawer.cpp:48
void draw_rectangle(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
Draw rectangle.
Definition: drawer.cpp:199
void draw_cross(unsigned int x_center, unsigned int y_center, unsigned int width)
Draws a cross.
Definition: drawer.cpp:449
void draw_line(unsigned int x_start, unsigned int y_start, unsigned int x_end, unsigned int y_end)
Draw line.
Definition: drawer.cpp:363
Drawer()
Constructor.
Definition: drawer.cpp:41
void set_buffer(unsigned char *buffer, unsigned int width, unsigned int height)
Set the buffer to draw to.
Definition: drawer.cpp:58
void draw_point(unsigned int x, unsigned int y)
Draw point.
Definition: drawer.cpp:293
void draw_circle(int center_x, int center_y, unsigned int radius)
Draw circle.
Definition: drawer.cpp:94
YUV pixel.
Definition: yuv.h:58
unsigned char V
V component.
Definition: yuv.h:61
static YUV_t_struct white()
Definition: yuv.h:76
unsigned char U
U component.
Definition: yuv.h:60
unsigned char Y
Y component.
Definition: yuv.h:59