Visual Servoing Platform  version 3.5.1 under development (2022-07-05)
vpDisplayGTK.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Image display.
33  *
34  * Authors:
35  * Christophe Collewet
36  * Eric Marchand
37  * Fabien Spindler
38  *
39  *****************************************************************************/
40 
46 #include <visp3/core/vpConfig.h>
47 
48 #if (defined(VISP_HAVE_GTK))
49 
50 #include <cmath> // std::fabs
51 #include <iostream>
52 #include <limits> // numeric_limits
53 #include <stdio.h>
54 #include <stdlib.h>
55 
56 // Display stuff
57 #include <visp3/core/vpDisplay.h>
58 #include <visp3/gui/vpDisplayGTK.h>
59 
60 // debug / exception
61 #include <visp3/core/vpDebug.h>
62 #include <visp3/core/vpDisplayException.h>
63 #include <visp3/core/vpImageConvert.h>
64 #include <visp3/core/vpImageTools.h>
65 #include <visp3/core/vpMath.h>
66 
67 #ifndef DOXYGEN_SHOULD_SKIP_THIS
68 
69 #include <gdk/gdk.h>
70 #include <gdk/gdkrgb.h>
71 #include <gtk/gtk.h>
72 
73 class vpDisplayGTK::Impl
74 {
75 public:
76  Impl()
77  : m_widget(NULL), m_background(NULL), m_gc(NULL), m_blue(), m_red(), m_yellow(), m_green(), m_cyan(), m_orange(),
78  m_white(), m_black(), m_gdkcolor(), m_lightBlue(), m_darkBlue(), m_lightRed(), m_darkRed(), m_lightGreen(),
79  m_darkGreen(), m_purple(), m_lightGray(), m_gray(), m_darkGray(), m_colormap(NULL), m_font(NULL), m_vectgtk(NULL),
80  m_col(NULL)
81  {
82  }
83 
84  ~Impl() {}
85 
86  void init(unsigned int win_width, unsigned int win_height, int win_x, int win_y, const std::string &title)
87  {
88  gint width = static_cast<gint>(win_width);
89  gint height = static_cast<gint>(win_height);
90 
91  /* Initialisation of the gdk et gdk_rgb library */
92  int *argc = NULL;
93  char **argv;
94 
95  gtk_init(argc, &argv);
96 
97  /* Create the window*/
98  m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
99 
100  gtk_widget_add_events(m_widget, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
101 
102  gtk_window_set_default_size(GTK_WINDOW(m_widget), width, height);
103 
104  gtk_window_move(GTK_WINDOW(m_widget), win_x, win_y);
105 
106  gtk_widget_show(m_widget);
107 
108  gdk_rgb_init();
109 
110  /* Create background pixmap */
111  m_background = gdk_pixmap_new(m_widget->window, width, height, -1);
112 
113  /* Create graphic context */
114  m_gc = gdk_gc_new(m_widget->window);
115 
116  /* get the colormap */
117  m_colormap = gdk_window_get_colormap(m_widget->window);
118 
119  m_col = new GdkColor *[vpColor::id_unknown]; // id_unknown = number of predefined colors
120 
121  /* Create color */
122  gdk_color_parse("light blue", &m_lightBlue);
123  gdk_colormap_alloc_color(m_colormap, &m_lightBlue, FALSE, TRUE);
124  m_col[vpColor::id_lightBlue] = &m_lightBlue;
125 
126  gdk_color_parse("blue", &m_blue);
127  gdk_colormap_alloc_color(m_colormap, &m_blue, FALSE, TRUE);
128  m_col[vpColor::id_blue] = &m_blue;
129 
130  gdk_color_parse("dark blue", &m_darkBlue);
131  gdk_colormap_alloc_color(m_colormap, &m_darkBlue, FALSE, TRUE);
132  m_col[vpColor::id_darkBlue] = &m_darkBlue;
133 
134  gdk_color_parse("#FF8C8C", &m_lightRed);
135  gdk_colormap_alloc_color(m_colormap, &m_lightRed, FALSE, TRUE);
136  m_col[vpColor::id_lightRed] = &m_lightRed;
137 
138  gdk_color_parse("red", &m_red);
139  gdk_colormap_alloc_color(m_colormap, &m_red, FALSE, TRUE);
140  m_col[vpColor::id_red] = &m_red;
141 
142  gdk_color_parse("dark red", &m_darkRed);
143  gdk_colormap_alloc_color(m_colormap, &m_darkRed, FALSE, TRUE);
144  m_col[vpColor::id_darkRed] = &m_darkRed;
145 
146  gdk_color_parse("light green", &m_lightGreen);
147  gdk_colormap_alloc_color(m_colormap, &m_lightGreen, FALSE, TRUE);
148  m_col[vpColor::id_lightGreen] = &m_lightGreen;
149 
150  gdk_color_parse("green", &m_green);
151  gdk_colormap_alloc_color(m_colormap, &m_green, FALSE, TRUE);
152  m_col[vpColor::id_green] = &m_green;
153 
154  gdk_color_parse("dark green", &m_darkGreen);
155  gdk_colormap_alloc_color(m_colormap, &m_darkGreen, FALSE, TRUE);
156  m_col[vpColor::id_darkGreen] = &m_darkGreen;
157 
158  gdk_color_parse("yellow", &m_yellow);
159  gdk_colormap_alloc_color(m_colormap, &m_yellow, FALSE, TRUE);
160  m_col[vpColor::id_yellow] = &m_yellow;
161 
162  gdk_color_parse("cyan", &m_cyan);
163  gdk_colormap_alloc_color(m_colormap, &m_cyan, FALSE, TRUE);
164  m_col[vpColor::id_cyan] = &m_cyan;
165 
166  gdk_color_parse("orange", &m_orange);
167  gdk_colormap_alloc_color(m_colormap, &m_orange, FALSE, TRUE);
168  m_col[vpColor::id_orange] = &m_orange;
169 
170  gdk_color_parse("purple", &m_purple);
171  gdk_colormap_alloc_color(m_colormap, &m_purple, FALSE, TRUE);
172  m_col[vpColor::id_purple] = &m_purple;
173 
174  gdk_color_parse("white", &m_white);
175  gdk_colormap_alloc_color(m_colormap, &m_white, FALSE, TRUE);
176  m_col[vpColor::id_white] = &m_white;
177 
178  gdk_color_parse("black", &m_black);
179  gdk_colormap_alloc_color(m_colormap, &m_black, FALSE, TRUE);
180  m_col[vpColor::id_black] = &m_black;
181 
182  gdk_color_parse("#C0C0C0", &m_lightGray);
183  gdk_colormap_alloc_color(m_colormap, &m_lightGray, FALSE, TRUE);
184  m_col[vpColor::id_lightGray] = &m_lightGray;
185 
186  gdk_color_parse("#808080", &m_gray);
187  gdk_colormap_alloc_color(m_colormap, &m_gray, FALSE, TRUE);
188  m_col[vpColor::id_gray] = &m_gray;
189 
190  gdk_color_parse("#404040", &m_darkGray);
191  gdk_colormap_alloc_color(m_colormap, &m_darkGray, FALSE, TRUE);
192  m_col[vpColor::id_darkGray] = &m_darkGray;
193 
194  // Try to load a default font
195  m_font = gdk_font_load("-*-times-medium-r-normal-*-16-*-*-*-*-*-*-*");
196  if (m_font == NULL)
197  m_font = gdk_font_load("-*-courier-bold-r-normal-*-*-140-*-*-*-*-*-*");
198  if (m_font == NULL)
199  m_font = gdk_font_load("-*-courier 10 pitch-medium-r-normal-*-16-*-*-*-*-*-*-*");
200 
201  if (!title.empty())
202  gdk_window_set_title(m_widget->window, title.c_str());
203  }
204 
205  void setFont(const std::string &fontname) { m_font = gdk_font_load((const gchar *)fontname.c_str()); }
206 
207  void setTitle(const std::string &title) { gdk_window_set_title(m_widget->window, title.c_str()); }
208 
209  void setWindowPosition(int win_x, int win_y) { gtk_window_move(GTK_WINDOW(m_widget), win_x, win_y); }
210 
211  void displayImage(const vpImage<unsigned char> &I, unsigned int scale, gint width, gint height)
212  {
213  if (scale == 1) {
214  /* Copie de l'image dans le pixmap fond */
215  gdk_draw_gray_image(m_background, m_gc, 0, 0, width, height, GDK_RGB_DITHER_NONE, I.bitmap, width);
216  } else {
217  vpImage<unsigned char> sampled;
218  I.subsample(scale, scale, sampled);
219  gdk_draw_gray_image(m_background, m_gc, 0, 0, width, height, GDK_RGB_DITHER_NONE, sampled.bitmap, width);
220  }
221 
222  /* Le pixmap background devient le fond de la zone de dessin */
223  gdk_window_set_back_pixmap(m_widget->window, m_background, FALSE);
224  }
225 
226  void displayImage(const vpImage<vpRGBa> &I, unsigned int scale, gint width, gint height)
227  {
228  if (scale == 1) {
229  /* Copie de l'image dans le pixmap fond */
230  gdk_draw_rgb_32_image(m_background, m_gc, 0, 0, width, height, GDK_RGB_DITHER_NONE, (unsigned char *)I.bitmap,
231  4 * width);
232  } else {
233  vpImage<vpRGBa> sampled;
234  I.subsample(scale, scale, sampled);
235  gdk_draw_rgb_32_image(m_background, m_gc, 0, 0, width, height, GDK_RGB_DITHER_NONE,
236  (unsigned char *)sampled.bitmap, 4 * width);
237  }
238 
239  /* Le pixmap background devient le fond de la zone de dessin */
240  gdk_window_set_back_pixmap(m_widget->window, m_background, FALSE);
241  }
242 
243  void displayImageROI(const vpImage<unsigned char> &I, gint j_min, gint i_min, gint width, gint height)
244  {
245  gdk_draw_gray_image(m_background, m_gc, j_min, i_min, width, height, GDK_RGB_DITHER_NONE, I.bitmap, width);
246  /* Le pixmap background devient le fond de la zone de dessin */
247  gdk_window_set_back_pixmap(m_widget->window, m_background, FALSE);
248  }
249 
250  void displayImageROI(const vpImage<vpRGBa> &I, gint j_min, gint i_min, gint width, gint height)
251  {
252  gdk_draw_rgb_32_image(m_background, m_gc, j_min, i_min, width, height, GDK_RGB_DITHER_NONE,
253  (unsigned char *)I.bitmap, width * 4);
254 
255  /* Le pixmap background devient le fond de la zone de dessin */
256  gdk_window_set_back_pixmap(m_widget->window, m_background, FALSE);
257  }
258 
259  void closeDisplay()
260  {
261  if (m_col != NULL) {
262  delete[] m_col;
263  m_col = NULL;
264  }
265 
266  if (m_widget != NULL) {
267  gdk_window_hide(m_widget->window);
268  gdk_window_destroy(m_widget->window);
269  gtk_widget_destroy(m_widget);
270  m_widget = NULL;
271  }
272  }
273 
274  void flushDisplay()
275  {
276  gdk_window_clear(m_widget->window);
277  gdk_flush();
278  }
279 
280  void displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color, unsigned int scale)
281  {
282  if (color.id < vpColor::id_unknown)
283  gdk_gc_set_foreground(m_gc, m_col[color.id]);
284  else {
285  m_gdkcolor.red = 256 * color.R;
286  m_gdkcolor.green = 256 * color.G;
287  m_gdkcolor.blue = 256 * color.B;
288  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
289  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
290  }
291  if (m_font != NULL)
292  gdk_draw_string(m_background, m_font, m_gc, vpMath::round(ip.get_u() / scale), vpMath::round(ip.get_v() / scale),
293  (const gchar *)text);
294  else
295  std::cout << "Cannot draw string: no font is selected" << std::endl;
296  }
297 
298  void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
299  unsigned int thickness, unsigned int scale)
300  {
301  if (color.id < vpColor::id_unknown)
302  gdk_gc_set_foreground(m_gc, m_col[color.id]);
303  else {
304  m_gdkcolor.red = 256 * color.R;
305  m_gdkcolor.green = 256 * color.G;
306  m_gdkcolor.blue = 256 * color.B;
307  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
308  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
309  }
310 
311  gdk_gc_set_line_attributes(m_gc, static_cast<gint>(thickness), GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
312 
313  if (fill == false)
314  gdk_draw_arc(m_background, m_gc, FALSE, vpMath::round((center.get_u() - radius) / scale),
315  vpMath::round((center.get_v() - radius) / scale), static_cast<gint>(2. * radius / scale),
316  static_cast<gint>(2. * radius / scale), 23040, 23040); /* 23040 = 360*64 */
317  else
318  gdk_draw_arc(m_background, m_gc, TRUE, vpMath::round((center.get_u() - radius) / scale),
319  vpMath::round((center.get_v() - radius) / scale), static_cast<gint>(2. * radius / scale),
320  static_cast<gint>(2. * radius / scale), 23040, 23040); /* 23040 = 360*64 */
321  }
322 
323  void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness,
324  unsigned int scale)
325  {
326  if (color.id < vpColor::id_unknown)
327  gdk_gc_set_foreground(m_gc, m_col[color.id]);
328  else {
329  m_gdkcolor.red = 256 * color.R;
330  m_gdkcolor.green = 256 * color.G;
331  m_gdkcolor.blue = 256 * color.B;
332  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
333  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
334  }
335 
336  gdk_gc_set_line_attributes(m_gc, static_cast<gint>(thickness), GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
337  gdk_draw_line(m_background, m_gc, vpMath::round(ip1.get_u() / scale), vpMath::round(ip1.get_v() / scale),
338  vpMath::round(ip2.get_u() / scale), vpMath::round(ip2.get_v() / scale));
339  gdk_gc_set_line_attributes(m_gc, 0, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
340  }
341 
342  void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness,
343  unsigned int scale)
344  {
345  if (color.id < vpColor::id_unknown)
346  gdk_gc_set_foreground(m_gc, m_col[color.id]);
347  else {
348  m_gdkcolor.red = 256 * color.R;
349  m_gdkcolor.green = 256 * color.G;
350  m_gdkcolor.blue = 256 * color.B;
351  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
352  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
353  }
354 
355  gdk_gc_set_line_attributes(m_gc, static_cast<gint>(thickness), GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
356  gdk_draw_line(m_background, m_gc, vpMath::round(ip1.get_u() / scale), vpMath::round(ip1.get_v() / scale),
357  vpMath::round(ip2.get_u() / scale), vpMath::round(ip2.get_v() / scale));
358  }
359 
360  void displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness, unsigned int scale)
361  {
362  if (color.id < vpColor::id_unknown)
363  gdk_gc_set_foreground(m_gc, m_col[color.id]);
364  else {
365  m_gdkcolor.red = 256 * color.R;
366  m_gdkcolor.green = 256 * color.G;
367  m_gdkcolor.blue = 256 * color.B;
368  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
369  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
370  }
371 
372  if (thickness == 1) {
373  gdk_draw_point(m_background, m_gc, vpMath::round(ip.get_u() / scale), vpMath::round(ip.get_v() / scale));
374  } else {
375  gdk_draw_rectangle(m_background, m_gc, TRUE, vpMath::round(ip.get_u() / scale), vpMath::round(ip.get_v() / scale),
376  static_cast<gint>(thickness), static_cast<gint>(thickness));
377  }
378  }
379 
380  void displayRectangle(const vpImagePoint &topLeft, unsigned int w, unsigned int h, const vpColor &color, bool fill,
381  unsigned int thickness, unsigned int scale)
382  {
383  if (color.id < vpColor::id_unknown)
384  gdk_gc_set_foreground(m_gc, m_col[color.id]);
385  else {
386  m_gdkcolor.red = 256 * color.R;
387  m_gdkcolor.green = 256 * color.G;
388  m_gdkcolor.blue = 256 * color.B;
389  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
390  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
391  }
392  gdk_gc_set_line_attributes(m_gc, static_cast<gint>(thickness), GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
393 
394  if (fill == false)
395  gdk_draw_rectangle(m_background, m_gc, FALSE, vpMath::round(topLeft.get_u() / scale),
396  vpMath::round(topLeft.get_v() / scale), static_cast<gint>(w / scale),
397  static_cast<gint>(h / scale));
398  else
399  gdk_draw_rectangle(m_background, m_gc, TRUE, vpMath::round(topLeft.get_u() / scale),
400  vpMath::round(topLeft.get_v() / scale), static_cast<gint>(w / scale),
401  static_cast<gint>(h / scale));
402 
403  if (thickness > 1)
404  gdk_gc_set_line_attributes(m_gc, 0, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
405  }
406 
407  bool getClick(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking, unsigned int scale,
408  const GdkEventType &event_type)
409  {
410  bool ret = false;
411  do {
412  GdkEvent *ev = NULL;
413  while ((ev = gdk_event_get())) {
414  if (ev->any.window == m_widget->window && ev->type == event_type) {
415  double u = ((GdkEventButton *)ev)->x;
416  double v = ((GdkEventButton *)ev)->y;
417  ip.set_u(u * scale);
418  ip.set_v(v * scale);
419 
420  switch (static_cast<int>(((GdkEventButton *)ev)->button)) {
421  case 1:
422  button = vpMouseButton::button1;
423  break;
424  case 2:
425  button = vpMouseButton::button2;
426  break;
427  case 3:
428  button = vpMouseButton::button3;
429  break;
430  }
431  ret = true;
432  }
433  gdk_event_free(ev);
434  }
435  if (blocking) {
436  flushDisplay();
437  vpTime::wait(100);
438  }
439 
440  } while (ret == false && blocking == true);
441  return ret;
442  }
443 
444  void getImage(vpImage<vpRGBa> &I, gint width, gint height)
445  {
446  GdkImage *ImageGtk;
447  ImageGtk = gdk_image_get(m_background, 0, 0, width, height);
448 
449  I.resize(height, width);
450  guint32 pixel;
451 
452  guchar OctetRouge, OctetVert, OctetBleu, mask;
453  mask = 0x000000FF;
454 
455  for (gint y = 0; y < height; y++) {
456  for (gint x = 0; x < width; x++) {
457  pixel = gdk_image_get_pixel(ImageGtk, x, y);
458  OctetBleu = static_cast<guchar>(pixel) & mask;
459  OctetVert = static_cast<guchar>(pixel >> 8) & mask;
460  OctetRouge = static_cast<guchar>(pixel >> 16) & mask;
461  I[y][x].R = OctetRouge;
462  I[y][x].G = OctetVert;
463  I[y][x].B = OctetBleu;
464  I[y][x].A = vpRGBa::alpha_default; // default opacity
465  }
466  }
467  }
468 
469  unsigned int getScreenDepth() { return static_cast<unsigned int>(gdk_window_get_visual(m_widget->window)->depth); }
470 
471  bool getKeyboardEvent(std::string &key, bool blocking)
472  {
473  bool ret = false;
474  int cpt = 0;
475  do {
476  GdkEvent *ev = NULL;
477  while ((ev = gdk_event_get()) != NULL) {
478  cpt++;
479  // printf("event %d type %d on window %p My window %p\n",
480  // cpt, ev->type, ev->any.window, widget->window);
481 
482  if (ev->any.window == m_widget->window && ev->type == GDK_KEY_PRESS) {
483  // std::cout << "Key val: \"" << gdk_keyval_name (ev->key.keyval)
484  // /*ev->key.string*/ << "\"" << std::endl;
485  key = gdk_keyval_name(ev->key.keyval);
486  ret = true;
487  // printf("Key press detection\n");
488  }
489  gdk_event_free(ev);
490  }
491  if (blocking) {
492  flushDisplay();
493  vpTime::wait(100);
494  }
495  } while (ret == false && blocking == true);
496  return ret;
497  }
498 
499  bool getPointerMotionEvent(vpImagePoint &ip, unsigned int scale)
500  {
501  bool ret = false;
502  GdkEvent *ev = NULL;
503  if ((ev = gdk_event_get())) {
504  if (ev->any.window == m_widget->window && ev->type == GDK_MOTION_NOTIFY) {
505  double u = ((GdkEventMotion *)ev)->x;
506  double v = ((GdkEventMotion *)ev)->y;
507  ip.set_u(u * scale);
508  ip.set_v(v * scale);
509 
510  ret = true;
511  }
512  gdk_event_free(ev);
513  }
514  return ret;
515  }
516 
517  void getPointerPosition(vpImagePoint &ip, unsigned int scale)
518  {
519  gint u, v;
520  gdk_window_get_pointer(m_widget->window, &u, &v, NULL);
521  ip.set_u(static_cast<double>(u) * scale);
522  ip.set_v(static_cast<double>(v) * scale);
523  }
524 
525  void getScreenSize(bool is_init, unsigned int &w, unsigned int &h)
526  {
527  if (!is_init) {
528  int *argc = NULL;
529  char **argv;
530 
531  gtk_init(argc, &argv);
532 
533  GtkWidget *widget_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
534  gtk_window_set_default_size(GTK_WINDOW(widget_), 100, 100);
535  gtk_widget_show(widget_);
536 
537  GdkScreen *screen_ = gdk_window_get_screen(widget_->window);
538  w = static_cast<unsigned int>(gdk_screen_get_width(screen_));
539  h = static_cast<unsigned int>(gdk_screen_get_height(screen_));
540  gtk_widget_destroy(widget_);
541  } else {
542  GdkScreen *screen_ = gdk_window_get_screen(m_widget->window);
543  w = static_cast<unsigned int>(gdk_screen_get_width(screen_));
544  h = static_cast<unsigned int>(gdk_screen_get_height(screen_));
545  }
546  }
547 
548 private:
549  GtkWidget *m_widget;
550  GdkPixmap *m_background;
551  GdkGC *m_gc;
552  GdkColor m_blue, m_red, m_yellow, m_green, m_cyan, m_orange, m_white, m_black, m_gdkcolor;
553  GdkColor m_lightBlue, m_darkBlue, m_lightRed, m_darkRed, m_lightGreen, m_darkGreen, m_purple;
554  GdkColor m_lightGray, m_gray, m_darkGray;
555  GdkColormap *m_colormap;
556 
557  GdkFont *m_font;
558  guchar *m_vectgtk;
559  GdkColor **m_col;
560 };
561 
562 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
563 
586 {
587  setScale(scaleType, I.getWidth(), I.getHeight());
588  init(I);
589 }
590 
614 vpDisplayGTK::vpDisplayGTK(vpImage<unsigned char> &I, int win_x, int win_y, const std::string &win_title,
615  vpScaleType scaleType)
616  : vpDisplay(), m_impl(new Impl())
617 {
618  setScale(scaleType, I.getWidth(), I.getHeight());
619  init(I, win_x, win_y, win_title);
620 }
621 
641 vpDisplayGTK::vpDisplayGTK(vpImage<vpRGBa> &I, vpScaleType scaleType) : vpDisplay(), m_impl(new Impl())
642 {
643  setScale(scaleType, I.getWidth(), I.getHeight());
644  init(I);
645 }
646 
668 vpDisplayGTK::vpDisplayGTK(vpImage<vpRGBa> &I, int win_x, int win_y, const std::string &win_title,
669  vpScaleType scaleType)
670  : vpDisplay(), m_impl(new Impl())
671 {
672  setScale(scaleType, I.getWidth(), I.getHeight());
673  init(I, win_x, win_y, win_title);
674 }
675 
698 vpDisplayGTK::vpDisplayGTK(int win_x, int win_y, const std::string &win_title) : vpDisplay(), m_impl(new Impl())
699 {
700  m_windowXPosition = win_x;
701  m_windowYPosition = win_y;
702  m_title = win_title;
703 }
704 
724 vpDisplayGTK::vpDisplayGTK() : vpDisplay(), m_impl(new Impl()) {}
725 
730 {
731  closeDisplay();
732  delete m_impl;
733 }
734 
743 void vpDisplayGTK::init(vpImage<unsigned char> &I, int win_x, int win_y, const std::string &win_title)
744 {
745  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
746  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
747  }
748 
749  if (win_x != -1)
750  m_windowXPosition = win_x;
751  if (win_y != -1)
752  m_windowYPosition = win_y;
753 
754  if (!win_title.empty())
755  m_title = win_title;
756 
759 
760  I.display = this;
762 }
763 
773 void vpDisplayGTK::init(vpImage<vpRGBa> &I, int win_x, int win_y, const std::string &win_title)
774 {
775  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
776  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
777  }
778 
779  if (win_x != -1)
780  m_windowXPosition = win_x;
781  if (win_y != -1)
782  m_windowYPosition = win_y;
783 
784  if (!win_title.empty())
785  m_title = win_title;
786 
789 
790  I.display = this;
792 }
793 
802 void vpDisplayGTK::init(unsigned int win_width, unsigned int win_height, int win_x, int win_y,
803  const std::string &win_title)
804 {
805  setScale(m_scaleType, win_width, win_height);
806 
807  m_width = win_width / m_scale;
808  m_height = win_height / m_scale;
809 
810  if (win_x != -1)
811  m_windowXPosition = win_x;
812  if (win_y != -1)
813  m_windowYPosition = win_y;
814 
815  m_title = win_title;
816 
818 
820 }
821 
834 void vpDisplayGTK::setFont(const std::string &fontname) { m_impl->setFont(fontname); }
835 
840 void vpDisplayGTK::setTitle(const std::string &title)
841 {
843  m_title = title;
844  if (!title.empty()) {
845  m_impl->setTitle(title);
846  }
847  } else {
848  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
849  }
850 }
851 
861 void vpDisplayGTK::setWindowPosition(int win_x, int win_y)
862 {
864  m_impl->setWindowPosition(win_x, win_y);
865  } else {
866  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
867  }
868 }
869 
882 {
884  m_impl->displayImage(I, m_scale, static_cast<gint>(m_width), static_cast<gint>(m_height));
885  } else {
886  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
887  }
888 }
889 
907 void vpDisplayGTK::displayImageROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int w,
908  unsigned int h)
909 {
912  vpImageTools::crop(I, iP.get_i(), iP.get_j(), h, w, Itemp, m_scale, m_scale);
913 
914  /* Copie de l'image dans le pixmap fond */
915  int i_min = (std::max)(static_cast<int>(ceil(iP.get_i() / m_scale)), 0);
916  int j_min = (std::max)(static_cast<int>(ceil(iP.get_j() / m_scale)), 0);
917 
918  m_impl->displayImageROI(Itemp, static_cast<gint>(j_min), static_cast<gint>(i_min),
919  static_cast<gint>(Itemp.getWidth()), static_cast<gint>(Itemp.getHeight()));
920  } else {
921  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
922  }
923 }
924 
937 {
939  m_impl->displayImage(I, m_scale, static_cast<gint>(m_width), static_cast<gint>(m_height));
940  } else {
941  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
942  }
943 }
944 
962 void vpDisplayGTK::displayImageROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int w, unsigned int h)
963 {
965  vpImage<vpRGBa> Itemp;
966  vpImageTools::crop(I, iP.get_i(), iP.get_j(), h, w, Itemp, m_scale, m_scale);
967 
968  /* Copie de l'image dans le pixmap fond */
969  int i_min = (std::max)(static_cast<int>(ceil(iP.get_i() / m_scale)), 0);
970  int j_min = (std::max)(static_cast<int>(ceil(iP.get_j() / m_scale)), 0);
971 
972  m_impl->displayImageROI(Itemp, static_cast<gint>(j_min), static_cast<gint>(i_min),
973  static_cast<gint>(Itemp.getWidth()), static_cast<gint>(Itemp.getHeight()));
974  } else {
975  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
976  }
977 }
978 
984 void vpDisplayGTK::displayImage(const unsigned char * /* I */) { vpTRACE(" not implemented "); }
985 
992 {
994  m_impl->closeDisplay();
995 
997  }
998 }
999 
1005 {
1007  m_impl->flushDisplay();
1008  } else {
1009  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1010  }
1011 }
1012 
1017 void vpDisplayGTK::flushDisplayROI(const vpImagePoint & /*iP*/, const unsigned int /*width*/,
1018  const unsigned int /*height*/)
1019 {
1021  m_impl->flushDisplay();
1022  } else {
1023  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1024  }
1025 }
1026 
1030 void vpDisplayGTK::clearDisplay(const vpColor & /* color */) { vpTRACE("Not implemented"); }
1031 
1039 void vpDisplayGTK::displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int w,
1040  unsigned int h, unsigned int thickness)
1041 {
1043  double a = ip2.get_i() - ip1.get_i();
1044  double b = ip2.get_j() - ip1.get_j();
1045  double lg = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
1046 
1047  if ((std::fabs(a) > std::numeric_limits<double>::epsilon()) &&
1048  (std::fabs(b) > std::numeric_limits<double>::epsilon())) {
1049  a /= lg;
1050  b /= lg;
1051 
1052  vpImagePoint ip3;
1053  ip3.set_i(ip2.get_i() - w * a);
1054  ip3.set_j(ip2.get_j() - w * b);
1055 
1056  vpImagePoint ip4;
1057  ip4.set_i(ip3.get_i() - b * h);
1058  ip4.set_j(ip3.get_j() + a * h);
1059 
1060  if (lg > 2 * vpImagePoint::distance(ip2, ip4))
1061  displayLine(ip2, ip4, color, thickness);
1062 
1063  ip4.set_i(ip3.get_i() + b * h);
1064  ip4.set_j(ip3.get_j() - a * h);
1065 
1066  if (lg > 2 * vpImagePoint::distance(ip2, ip4))
1067  displayLine(ip2, ip4, color, thickness);
1068 
1069  displayLine(ip1, ip2, color, thickness);
1070  }
1071  } else {
1072  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1073  }
1074 }
1075 
1087 void vpDisplayGTK::displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color)
1088 {
1090  m_impl->displayCharString(ip, text, color, m_scale);
1091  } else {
1092  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1093  }
1094 }
1104 void vpDisplayGTK::displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
1105  unsigned int thickness)
1106 {
1108  if (thickness == 1)
1109  thickness = 0;
1110 
1111  m_impl->displayCircle(center, radius, color, fill, thickness, m_scale);
1112  } else {
1113  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1114  }
1115 }
1123 void vpDisplayGTK::displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness)
1124 {
1126  double i = ip.get_i();
1127  double j = ip.get_j();
1128  vpImagePoint ip1, ip2;
1129 
1130  ip1.set_i(i - size / 2);
1131  ip1.set_j(j);
1132  ip2.set_i(i + size / 2);
1133  ip2.set_j(j);
1134  displayLine(ip1, ip2, color, thickness);
1135 
1136  ip1.set_i(i);
1137  ip1.set_j(j - size / 2);
1138  ip2.set_i(i);
1139  ip2.set_j(j + size / 2);
1140 
1141  displayLine(ip1, ip2, color, thickness);
1142  }
1143 
1144  else {
1145  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1146  }
1147 }
1154 void vpDisplayGTK::displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
1155  unsigned int thickness)
1156 {
1157 
1159  if (thickness == 1)
1160  thickness = 0;
1161 
1162  m_impl->displayDotLine(ip1, ip2, color, thickness, m_scale);
1163  } else {
1164  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1165  }
1166 }
1167 
1174 void vpDisplayGTK::displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
1175  unsigned int thickness)
1176 {
1178  if (thickness == 1)
1179  thickness = 0;
1180 
1181  m_impl->displayLine(ip1, ip2, color, thickness, m_scale);
1182  } else {
1183  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1184  }
1185 }
1186 
1193 void vpDisplayGTK::displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness)
1194 {
1196  m_impl->displayPoint(ip, color, thickness, m_scale);
1197  } else {
1198  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1199  }
1200 }
1201 
1215 void vpDisplayGTK::displayRectangle(const vpImagePoint &topLeft, unsigned int w, unsigned int h, const vpColor &color,
1216  bool fill, unsigned int thickness)
1217 {
1219  if (thickness == 1)
1220  thickness = 0;
1221 
1222  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
1223  } else {
1224  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1225  }
1226 }
1227 
1240 void vpDisplayGTK::displayRectangle(const vpImagePoint &topLeft, const vpImagePoint &bottomRight, const vpColor &color,
1241  bool fill, unsigned int thickness)
1242 {
1244  if (thickness == 1)
1245  thickness = 0;
1246 
1247  unsigned int w = static_cast<unsigned int>(vpMath::round(bottomRight.get_u() - topLeft.get_u()));
1248  unsigned int h = static_cast<unsigned int>(vpMath::round(bottomRight.get_v() - topLeft.get_v()));
1249 
1250  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
1251  } else {
1252  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1253  }
1254 }
1255 
1268 void vpDisplayGTK::displayRectangle(const vpRect &rectangle, const vpColor &color, bool fill, unsigned int thickness)
1269 {
1271  if (thickness == 1)
1272  thickness = 0;
1273 
1274  vpImagePoint topLeft = rectangle.getTopLeft();
1275  unsigned int w = static_cast<unsigned int>(vpMath::round(rectangle.getWidth()));
1276  unsigned int h = static_cast<unsigned int>(vpMath::round(rectangle.getRight()));
1277  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
1278  } else {
1279  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1280  }
1281 }
1282 
1298 bool vpDisplayGTK::getClick(bool blocking)
1299 {
1300  bool ret = false;
1301 
1303  vpImagePoint ip;
1305  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_PRESS);
1306  } else {
1307  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1308  }
1309  return ret;
1310 }
1311 
1328 bool vpDisplayGTK::getClick(vpImagePoint &ip, bool blocking)
1329 {
1330  bool ret = false;
1331 
1334  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_PRESS);
1335  } else {
1336  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1337  }
1338  return ret;
1339 }
1340 
1361 {
1362  bool ret = false;
1363 
1365  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_PRESS);
1366  } else {
1367  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1368  }
1369  return ret;
1370 }
1371 
1396 {
1397  bool ret = false;
1398 
1400  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_RELEASE);
1401  } else {
1402  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1403  }
1404  return ret;
1405 }
1406 
1407 /*
1408  \brief gets the displayed image (including the overlay plane)
1409  and returns an RGBa image
1410 */
1412 {
1413  // should certainly be optimized.
1415  m_impl->getImage(I, static_cast<gint>(m_width), static_cast<gint>(m_height));
1416  } else {
1417  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1418  }
1419 }
1420 
1427 {
1428  unsigned int depth = m_impl->getScreenDepth();
1429 
1430  return (depth);
1431 }
1432 
1449 {
1450  bool ret = false;
1451 
1453  std::string key;
1454  ret = m_impl->getKeyboardEvent(key, blocking);
1455  } else {
1456  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1457  }
1458  return ret;
1459 }
1460 
1480 bool vpDisplayGTK::getKeyboardEvent(std::string &key, bool blocking)
1481 {
1482  bool ret = false;
1483 
1485  ret = m_impl->getKeyboardEvent(key, blocking);
1486  } else {
1487  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1488  }
1489  return ret;
1490 }
1491 
1505 {
1506  bool ret = false;
1507 
1509  ret = m_impl->getPointerMotionEvent(ip, m_scale);
1510  } else {
1511  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1512  }
1513  return ret;
1514 }
1515 
1527 {
1529  m_impl->getPointerPosition(ip, m_scale);
1530  } else {
1531  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1532  }
1533 
1534  return true;
1535 }
1536 
1541 void vpDisplayGTK::getScreenSize(unsigned int &w, unsigned int &h)
1542 {
1543  w = h = 0;
1544 
1545  m_impl->getScreenSize(m_displayHasBeenInitialized, w, h);
1546 }
1547 
1552 {
1553  unsigned int width, height;
1554  getScreenSize(width, height);
1555  return width;
1556 }
1557 
1562 {
1563  unsigned int width, height;
1564  getScreenSize(width, height);
1565  return height;
1566 }
1567 
1568 #elif !defined(VISP_BUILD_SHARED_LIBS)
1569 // Work arround to avoid warning: libvisp_core.a(vpDisplayGTK.cpp.o) has no
1570 // symbols
1571 void dummy_vpDisplayGTK(){};
1572 #endif
Class to define RGB colors available for display functionnalities.
Definition: vpColor.h:158
vpColorIdentifier id
Definition: vpColor.h:206
@ id_lightBlue
Definition: vpColor.h:184
@ id_yellow
Definition: vpColor.h:190
@ id_darkGray
Definition: vpColor.h:170
@ id_green
Definition: vpColor.h:180
@ id_darkRed
Definition: vpColor.h:176
@ id_lightGray
Definition: vpColor.h:166
@ id_red
Definition: vpColor.h:174
@ id_lightRed
Definition: vpColor.h:172
@ id_white
Definition: vpColor.h:164
@ id_black
Definition: vpColor.h:162
@ id_blue
Definition: vpColor.h:186
@ id_darkGreen
Definition: vpColor.h:182
@ id_gray
Definition: vpColor.h:168
@ id_lightGreen
Definition: vpColor.h:178
@ id_purple
Definition: vpColor.h:196
@ id_orange
Definition: vpColor.h:194
@ id_cyan
Definition: vpColor.h:192
@ id_darkBlue
Definition: vpColor.h:188
@ id_unknown
Definition: vpColor.h:199
Error that can be emited by the vpDisplay class and its derivates.
void displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
void setFont(const std::string &fontname)
void init(vpImage< unsigned char > &I, int win_x=-1, int win_y=-1, const std::string &win_title="")
void displayImageROI(const vpImage< unsigned char > &I, const vpImagePoint &iP, unsigned int width, unsigned int height)
virtual ~vpDisplayGTK()
void flushDisplayROI(const vpImagePoint &iP, unsigned int width, unsigned int height)
void displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
bool getClick(bool blocking=true)
void closeDisplay()
bool getKeyboardEvent(bool blocking=true)
bool getPointerMotionEvent(vpImagePoint &ip)
void displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color=vpColor::white, unsigned int w=4, unsigned int h=2, unsigned int thickness=1)
bool getClickUp(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking=true)
void getScreenSize(unsigned int &screen_width, unsigned int &screen_height)
void getImage(vpImage< vpRGBa > &I)
get the window pixmap and put it in vpRGBa image
void clearDisplay(const vpColor &color=vpColor::white)
void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
unsigned int getScreenDepth()
get the window depth (8,16,24,32)
unsigned int getScreenWidth()
void setTitle(const std::string &win_title)
bool getPointerPosition(vpImagePoint &ip)
unsigned int getScreenHeight()
void setWindowPosition(int win_x, int win_y)
void displayImage(const vpImage< vpRGBa > &I)
void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1)
void displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color=vpColor::green)
Class that defines generic functionnalities for display.
Definition: vpDisplay.h:178
unsigned int m_height
Definition: vpDisplay.h:216
vpScaleType m_scaleType
Definition: vpDisplay.h:219
unsigned int m_width
Definition: vpDisplay.h:215
int m_windowXPosition
display position
Definition: vpDisplay.h:212
std::string m_title
Definition: vpDisplay.h:217
int m_windowYPosition
display position
Definition: vpDisplay.h:214
unsigned int m_scale
Definition: vpDisplay.h:218
bool m_displayHasBeenInitialized
display has been initialized
Definition: vpDisplay.h:210
void setScale(vpScaleType scaleType, unsigned int width, unsigned int height)
Definition: vpDisplay.cpp:259
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:89
void set_j(double jj)
Definition: vpImagePoint.h:309
double get_j() const
Definition: vpImagePoint.h:132
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
void set_i(double ii)
Definition: vpImagePoint.h:298
double get_u() const
Definition: vpImagePoint.h:143
void set_u(double u)
Definition: vpImagePoint.h:335
void set_v(double v)
Definition: vpImagePoint.h:346
double get_i() const
Definition: vpImagePoint.h:121
double get_v() const
Definition: vpImagePoint.h:154
static void crop(const vpImage< Type > &I, double roi_top, double roi_left, unsigned int roi_height, unsigned int roi_width, vpImage< Type > &crop, unsigned int v_scale=1, unsigned int h_scale=1)
Definition: vpImageTools.h:306
void subsample(unsigned int v_scale, unsigned int h_scale, vpImage< Type > &sampled) const
Definition: vpImage.h:1217
unsigned int getWidth() const
Definition: vpImage.h:246
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:799
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
unsigned int getHeight() const
Definition: vpImage.h:188
vpDisplay * display
Definition: vpImage.h:144
static double sqr(double x)
Definition: vpMath.h:123
static int round(double x)
Definition: vpMath.h:318
unsigned char B
Blue component.
Definition: vpRGBa.h:150
unsigned char R
Red component.
Definition: vpRGBa.h:148
unsigned char G
Green component.
Definition: vpRGBa.h:149
@ alpha_default
Definition: vpRGBa.h:69
Defines a rectangle in the plane.
Definition: vpRect.h:80
double getWidth() const
Definition: vpRect.h:228
vpImagePoint getTopLeft() const
Definition: vpRect.h:200
double getRight() const
Definition: vpRect.h:180
#define vpTRACE
Definition: vpDebug.h:416
VISP_EXPORT int wait(double t0, double t)