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