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 
31 namespace 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  */
57 void
58 Drawer::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  */
70 void
71 Drawer::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  */
81 void
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  */
93 void
94 Drawer::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  */
198 void
199 Drawer::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  */
250 void
251 Drawer::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  */
292 void
293 Drawer::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  */
315 void
316 Drawer::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  */
338 void
339 Drawer::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  */
362 void
363 Drawer::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  */
448 void
449 Drawer::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
unsigned char V
V component.
Definition: yuv.h:61
void draw_point(unsigned int x, unsigned int y)
Draw point.
Definition: drawer.cpp:293
void draw_cross(unsigned int x_center, unsigned int y_center, unsigned int width)
Draws a cross.
Definition: drawer.cpp:449
~Drawer()
Destructor.
Definition: drawer.cpp:48
unsigned char Y
Y component.
Definition: yuv.h:59
void draw_rectangle_inverted(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
Draw inverted rectangle.
Definition: drawer.cpp:251
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
void set_buffer(unsigned char *buffer, unsigned int width, unsigned int height)
Set the buffer to draw to.
Definition: drawer.cpp:58
void draw_rectangle(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
Draw rectangle.
Definition: drawer.cpp:199
unsigned char U
U component.
Definition: yuv.h:60
void draw_circle(int center_x, int center_y, unsigned int radius)
Draw circle.
Definition: drawer.cpp:94
YUV pixel.
Definition: yuv.h:57
void color_point(unsigned int x, unsigned int y)
Color the given point.
Definition: drawer.cpp:316
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:71
Drawer()
Constructor.
Definition: drawer.cpp:41