Visual Servoing Platform  version 3.6.1 under development (2024-04-22)
vpDisplayX.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 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 https://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  * Anthony Saunier
36  *
37 *****************************************************************************/
38 
44 #include <visp3/core/vpConfig.h>
45 #ifdef VISP_HAVE_X11
46 
47 #include <cmath> // std::fabs
48 #include <iostream>
49 #include <limits> // numeric_limits
50 #include <stdio.h>
51 #include <stdlib.h>
52 
53 // Display stuff
54 #include <visp3/core/vpDisplay.h>
55 #include <visp3/gui/vpDisplayX.h>
56 
57 // debug / exception
58 #include <visp3/core/vpDebug.h>
59 #include <visp3/core/vpDisplayException.h>
60 
61 // math
62 #include <visp3/core/vpMath.h>
63 
64 #ifndef DOXYGEN_SHOULD_SKIP_THIS
65 
66 #include <X11/Xlib.h>
67 #include <X11/Xutil.h>
68 
69 // Work around to use this class with Eigen3
70 #ifdef Success
71 #undef Success // See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=253
72 #endif
73 
74 class vpDisplayX::Impl
75 {
76 public:
77  Impl()
78  : display(nullptr), window(), Ximage(nullptr), lut(), context(), screen(0), event(), pixmap(), x_color(nullptr),
79  screen_depth(8), xcolor(), values(), ximage_data_init(false), RMask(0), GMask(0), BMask(0), RShift(0), GShift(0),
80  BShift(0)
81  { }
82 
83  ~Impl() { }
84 
85  void clearDisplay(const vpColor &color, unsigned int width, unsigned int height)
86  {
87  if (color.id < vpColor::id_unknown)
88  XSetWindowBackground(display, window, x_color[color.id]);
89  else {
90  xcolor.pad = 0;
91  xcolor.red = 256 * color.R;
92  xcolor.green = 256 * color.G;
93  xcolor.blue = 256 * color.B;
94  XAllocColor(display, lut, &xcolor);
95  XSetForeground(display, context, xcolor.pixel);
96  }
97 
98  XClearWindow(display, window);
99 
100  XFreePixmap(display, pixmap);
101  // Pixmap creation.
102  pixmap = XCreatePixmap(display, window, width, height, screen_depth);
103  }
104 
105  void closeDisplay()
106  {
107  if (ximage_data_init == true)
108  free(Ximage->data);
109 
110  Ximage->data = nullptr;
111  XDestroyImage(Ximage);
112 
113  XFreePixmap(display, pixmap);
114 
115  XFreeGC(display, context);
116  XDestroyWindow(display, window);
117  XCloseDisplay(display);
118 
119  if (x_color != nullptr) {
120  delete[] x_color;
121  x_color = nullptr;
122  }
123  }
124 
125  void displayText(const vpImagePoint &ip, const std::string &text, const vpColor &color, unsigned int scale)
126  {
127  if (color.id < vpColor::id_unknown)
128  XSetForeground(display, context, x_color[color.id]);
129  else {
130  xcolor.pad = 0;
131  xcolor.red = 256 * color.R;
132  xcolor.green = 256 * color.G;
133  xcolor.blue = 256 * color.B;
134  XAllocColor(display, lut, &xcolor);
135  XSetForeground(display, context, xcolor.pixel);
136  }
137  XDrawString(display, pixmap, context, (int)(ip.get_u() / scale), (int)(ip.get_v() / scale), text.c_str(),
138  (int)text.size());
139  }
140 
141  void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
142  unsigned int thickness, unsigned int scale)
143  {
144  if (color.id < vpColor::id_unknown)
145  XSetForeground(display, context, x_color[color.id]);
146  else {
147  xcolor.pad = 0;
148  xcolor.red = 256 * color.R;
149  xcolor.green = 256 * color.G;
150  xcolor.blue = 256 * color.B;
151  XAllocColor(display, lut, &xcolor);
152  XSetForeground(display, context, xcolor.pixel);
153  }
154 
155  XSetLineAttributes(display, context, thickness, LineSolid, CapButt, JoinBevel);
156 
157  if (fill == false) {
158  XDrawArc(display, pixmap, context, vpMath::round((center.get_u() - radius) / scale),
159  vpMath::round((center.get_v() - radius) / scale), radius * 2 / scale, radius * 2 / scale, 0,
160  23040); /* 23040 = 360*64 */
161  }
162  else {
163  XFillArc(display, pixmap, context, vpMath::round((center.get_u() - radius) / scale),
164  vpMath::round((center.get_v() - radius) / scale), radius * 2 / scale, radius * 2 / scale, 0,
165  23040); /* 23040 = 360*64 */
166  }
167  }
168 
169  void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness,
170  unsigned int scale)
171  {
172  if (color.id < vpColor::id_unknown)
173  XSetForeground(display, context, x_color[color.id]);
174  else {
175  xcolor.pad = 0;
176  xcolor.red = 256 * color.R;
177  xcolor.green = 256 * color.G;
178  xcolor.blue = 256 * color.B;
179  XAllocColor(display, lut, &xcolor);
180  XSetForeground(display, context, xcolor.pixel);
181  }
182 
183  XSetLineAttributes(display, context, thickness, LineOnOffDash, CapButt, JoinBevel);
184 
185  XDrawLine(display, pixmap, context, vpMath::round(ip1.get_u() / scale), vpMath::round(ip1.get_v() / scale),
186  vpMath::round(ip2.get_u() / scale), vpMath::round(ip2.get_v() / scale));
187  }
188 
189  void displayImage(const vpImage<unsigned char> &I, unsigned int scale, unsigned int width, unsigned int height)
190  {
191  switch (screen_depth) {
192  case 8: {
193  // Correction de l'image de facon a liberer les niveaux de gris
194  // ROUGE, VERT, BLEU, JAUNE
195  unsigned char nivGrisMax = 255 - vpColor::id_unknown;
196  if (scale == 1) {
197  unsigned char *src_8 = (unsigned char *)I.bitmap;
198  unsigned char *dst_8 = (unsigned char *)Ximage->data;
199  unsigned int i = 0;
200  unsigned int size = width * height;
201 
202  while (i < size) {
203  unsigned char nivGris = src_8[i];
204  if (nivGris > nivGrisMax)
205  dst_8[i] = 255;
206  else
207  dst_8[i] = nivGris;
208  i++;
209  }
210  }
211  else {
212  // Correction de l'image de facon a liberer les niveaux de gris
213  // ROUGE, VERT, BLEU, JAUNE
214  unsigned char *dst_8 = (unsigned char *)Ximage->data;
215  unsigned int k = 0;
216  for (unsigned int i = 0; i < height; i++) {
217  for (unsigned int j = 0; j < width; j++) {
218  unsigned char nivGris = I[i * scale][j * scale];
219  if (nivGris > nivGrisMax)
220  dst_8[k++] = 255;
221  else
222  dst_8[k++] = nivGris;
223  }
224  }
225  }
226 
227  // Affichage de l'image dans la Pixmap.
228  XPutImage(display, pixmap, context, Ximage, 0, 0, 0, 0, width, height);
229  XSetWindowBackgroundPixmap(display, window, pixmap);
230  break;
231  }
232  case 16: {
233  unsigned int bytes_per_line = (unsigned int)Ximage->bytes_per_line;
234  if (scale == 1) {
235  for (unsigned int i = 0; i < height; i++) {
236  unsigned char *dst_8 = (unsigned char *)Ximage->data + i * bytes_per_line;
237  unsigned short *dst_16 = (unsigned short *)dst_8;
238  for (unsigned int j = 0; j < width; j++) {
239  *(dst_16 + j) = (unsigned short)colortable[I[i][j]];
240  }
241  }
242  }
243  else {
244  for (unsigned int i = 0; i < height; i++) {
245  unsigned char *dst_8 = (unsigned char *)Ximage->data + i * bytes_per_line;
246  unsigned short *dst_16 = (unsigned short *)dst_8;
247  for (unsigned int j = 0; j < width; j++) {
248  *(dst_16 + j) = (unsigned short)colortable[I[i * scale][j * scale]];
249  }
250  }
251  }
252 
253  // Affichage de l'image dans la Pixmap.
254  XPutImage(display, pixmap, context, Ximage, 0, 0, 0, 0, width, height);
255  XSetWindowBackgroundPixmap(display, window, pixmap);
256  break;
257  }
258 
259  case 24:
260  default: {
261  unsigned char *dst_32 = (unsigned char *)Ximage->data;
262  if (scale == 1) {
263  unsigned int size_ = width * height;
264  unsigned char *bitmap = I.bitmap;
265  unsigned char *n = I.bitmap + size_;
266  // for (unsigned int i = 0; i < size; i++) // suppression de
267  // l'iterateur i
268  if (XImageByteOrder(display) == 1) {
269  // big endian
270  while (bitmap < n) {
271  unsigned char val = *(bitmap++);
272  *(dst_32++) = vpRGBa::alpha_default;
273  *(dst_32++) = val; // Red
274  *(dst_32++) = val; // Green
275  *(dst_32++) = val; // Blue
276  }
277  }
278  else {
279  // little endian
280  while (bitmap < n) {
281  unsigned char val = *(bitmap++);
282  *(dst_32++) = val; // Blue
283  *(dst_32++) = val; // Green
284  *(dst_32++) = val; // Red
285  *(dst_32++) = vpRGBa::alpha_default;
286  }
287  }
288  }
289  else {
290  if (XImageByteOrder(display) == 1) {
291  // big endian
292  for (unsigned int i = 0; i < height; i++) {
293  for (unsigned int j = 0; j < width; j++) {
294  unsigned char val = I[i * scale][j * scale];
295  *(dst_32++) = vpRGBa::alpha_default;
296  *(dst_32++) = val; // Red
297  *(dst_32++) = val; // Green
298  *(dst_32++) = val; // Blue
299  }
300  }
301  }
302  else {
303  // little endian
304  for (unsigned int i = 0; i < height; i++) {
305  for (unsigned int j = 0; j < width; j++) {
306  unsigned char val = I[i * scale][j * scale];
307  *(dst_32++) = val; // Blue
308  *(dst_32++) = val; // Green
309  *(dst_32++) = val; // Red
310  *(dst_32++) = vpRGBa::alpha_default;
311  }
312  }
313  }
314  }
315 
316  // Affichage de l'image dans la Pixmap.
317  XPutImage(display, pixmap, context, Ximage, 0, 0, 0, 0, width, height);
318  XSetWindowBackgroundPixmap(display, window, pixmap);
319  break;
320  }
321  }
322  }
323 
324  void displayImage(const vpImage<vpRGBa> &I, unsigned int scale, unsigned int width, unsigned int height)
325  {
326  switch (screen_depth) {
327  case 16: {
328  vpRGBa *bitmap = I.bitmap;
329  unsigned int r, g, b;
330  unsigned int bytes_per_line = (unsigned int)Ximage->bytes_per_line;
331 
332  if (scale == 1) {
333  for (unsigned int i = 0; i < height; i++) {
334  unsigned char *dst_8 = (unsigned char *)Ximage->data + i * bytes_per_line;
335  unsigned short *dst_16 = (unsigned short *)dst_8;
336  for (unsigned int j = 0; j < width; j++) {
337  r = bitmap->R;
338  g = bitmap->G;
339  b = bitmap->B;
340  *(dst_16 + j) =
341  (((r << 8) >> RShift) & RMask) | (((g << 8) >> GShift) & GMask) | (((b << 8) >> BShift) & BMask);
342  bitmap++;
343  }
344  }
345  }
346  else {
347  for (unsigned int i = 0; i < height; i++) {
348  unsigned char *dst_8 = (unsigned char *)Ximage->data + i * bytes_per_line;
349  unsigned short *dst_16 = (unsigned short *)dst_8;
350  for (unsigned int j = 0; j < width; j++) {
351  vpRGBa val = I[i * scale][j * scale];
352  r = val.R;
353  g = val.G;
354  b = val.B;
355  *(dst_16 + j) =
356  (((r << 8) >> RShift) & RMask) | (((g << 8) >> GShift) & GMask) | (((b << 8) >> BShift) & BMask);
357  bitmap++;
358  }
359  }
360  }
361 
362  XPutImage(display, pixmap, context, Ximage, 0, 0, 0, 0, width, height);
363  XSetWindowBackgroundPixmap(display, window, pixmap);
364 
365  break;
366  }
367  case 24:
368  case 32: {
369  /*
370  * 32-bit source, 24/32-bit destination
371  */
372  unsigned char *dst_32 = nullptr;
373  dst_32 = (unsigned char *)Ximage->data;
374  if (scale == 1) {
375  vpRGBa *bitmap = I.bitmap;
376  unsigned int sizeI = width * height;
377  if (XImageByteOrder(display) == 1) {
378  // big endian
379  for (unsigned int i = 0; i < sizeI; i++) {
380  *(dst_32++) = bitmap->A;
381  *(dst_32++) = bitmap->R;
382  *(dst_32++) = bitmap->G;
383  *(dst_32++) = bitmap->B;
384  bitmap++;
385  }
386  }
387  else {
388  // little endian
389  for (unsigned int i = 0; i < sizeI; i++) {
390  *(dst_32++) = bitmap->B;
391  *(dst_32++) = bitmap->G;
392  *(dst_32++) = bitmap->R;
393  *(dst_32++) = bitmap->A;
394  bitmap++;
395  }
396  }
397  }
398  else {
399  if (XImageByteOrder(display) == 1) {
400  // big endian
401  for (unsigned int i = 0; i < height; i++) {
402  for (unsigned int j = 0; j < width; j++) {
403  vpRGBa val = I[i * scale][j * scale];
404  *(dst_32++) = val.A;
405  *(dst_32++) = val.R;
406  *(dst_32++) = val.G;
407  *(dst_32++) = val.B;
408  }
409  }
410  }
411  else {
412  // little endian
413  for (unsigned int i = 0; i < height; i++) {
414  for (unsigned int j = 0; j < width; j++) {
415  vpRGBa val = I[i * scale][j * scale];
416  *(dst_32++) = val.B;
417  *(dst_32++) = val.G;
418  *(dst_32++) = val.R;
419  *(dst_32++) = val.A;
420  }
421  }
422  }
423  }
424 
425  // Affichage de l'image dans la Pixmap.
426  XPutImage(display, pixmap, context, Ximage, 0, 0, 0, 0, width, height);
427  XSetWindowBackgroundPixmap(display, window, pixmap);
428  break;
429  }
430  default:
432  "Unsupported depth (%d bpp) for color display", screen_depth));
433  }
434  }
435 
436  void displayImage(const unsigned char *bitmap, unsigned int width, unsigned int height)
437  {
438  unsigned char *dst_32 = (unsigned char *)Ximage->data;
439  for (unsigned int i = 0; i < width * height; i++) {
440  *(dst_32++) = *bitmap; // red component.
441  *(dst_32++) = *bitmap; // green component.
442  *(dst_32++) = *bitmap; // blue component.
443  *(dst_32++) = *bitmap; // luminance component.
444  bitmap++;
445  }
446 
447  // Affichage de l'image dans la Pixmap.
448  XPutImage(display, pixmap, context, Ximage, 0, 0, 0, 0, width, height);
449  XSetWindowBackgroundPixmap(display, window, pixmap);
450  }
451 
452  void displayImageROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int w, unsigned int h,
453  unsigned int scale, unsigned int width, unsigned int height)
454  {
455  switch (screen_depth) {
456  case 8: {
457  // Correction de l'image de facon a liberer les niveaux de gris
458  // ROUGE, VERT, BLEU, JAUNE
459  unsigned char nivGrisMax = 255 - vpColor::id_unknown;
460  if (scale == 1) {
461  unsigned char *src_8 = (unsigned char *)I.bitmap;
462  unsigned char *dst_8 = (unsigned char *)Ximage->data;
463  unsigned int iwidth = I.getWidth();
464 
465  src_8 = src_8 + (int)(iP.get_i() * iwidth + iP.get_j());
466  dst_8 = dst_8 + (int)(iP.get_i() * width + iP.get_j());
467 
468  unsigned int i = 0;
469  while (i < h) {
470  unsigned int j = 0;
471  while (j < w) {
472  unsigned char nivGris = *(src_8 + j);
473  if (nivGris > nivGrisMax)
474  *(dst_8 + j) = 255;
475  else
476  *(dst_8 + j) = nivGris;
477  j++;
478  }
479  src_8 = src_8 + iwidth;
480  dst_8 = dst_8 + width;
481  i++;
482  }
483 
484  XPutImage(display, pixmap, context, Ximage, (int)iP.get_u(), (int)iP.get_v(), (int)iP.get_u(), (int)iP.get_v(),
485  w, h);
486  }
487  else {
488  // Correction de l'image de facon a liberer les niveaux de gris
489  // ROUGE, VERT, BLEU, JAUNE
490  int i_min = std::max<int>((int)ceil(iP.get_i() / scale), 0);
491  int j_min = std::max<int>((int)ceil(iP.get_j() / scale), 0);
492  int i_max = std::min<int>((int)ceil((iP.get_i() + h) / scale), (int)height);
493  int j_max = std::min<int>((int)ceil((iP.get_j() + w) / scale), (int)width);
494 
495  unsigned int i_min_ = (unsigned int)i_min;
496  unsigned int i_max_ = (unsigned int)i_max;
497  unsigned int j_min_ = (unsigned int)j_min;
498  unsigned int j_max_ = (unsigned int)j_max;
499 
500  for (unsigned int i = i_min_; i < i_max_; i++) {
501  unsigned char *dst_8 = (unsigned char *)Ximage->data + i * width;
502  for (unsigned int j = j_min_; j < j_max_; j++) {
503  unsigned char nivGris = I[i * scale][j * scale];
504  if (nivGris > nivGrisMax)
505  dst_8[j] = 255;
506  else
507  dst_8[j] = nivGris;
508  }
509  }
510  XPutImage(display, pixmap, context, Ximage, j_min, i_min, j_min, i_min, j_max_ - j_min_, i_max_ - i_min_);
511  }
512 
513  // Affichage de l'image dans la Pixmap.
514  XSetWindowBackgroundPixmap(display, window, pixmap);
515  break;
516  }
517  case 16: {
518  unsigned int bytes_per_line = (unsigned int)Ximage->bytes_per_line;
519  if (scale == 1) {
520  for (unsigned int i = (unsigned int)iP.get_i(); i < (unsigned int)(iP.get_i() + h); i++) {
521  unsigned char *dst_8 = (unsigned char *)Ximage->data + i * bytes_per_line;
522  unsigned short *dst_16 = (unsigned short *)dst_8;
523  for (unsigned int j = (unsigned int)iP.get_j(); j < (unsigned int)(iP.get_j() + w); j++) {
524  *(dst_16 + j) = (unsigned short)colortable[I[i][j]];
525  }
526  }
527 
528  XPutImage(display, pixmap, context, Ximage, (int)iP.get_u(), (int)iP.get_v(), (int)iP.get_u(), (int)iP.get_v(),
529  w, h);
530  }
531  else {
532  int i_min = std::max<int>((int)ceil(iP.get_i() / scale), 0);
533  int j_min = std::max<int>((int)ceil(iP.get_j() / scale), 0);
534  int i_max = std::min<int>((int)ceil((iP.get_i() + h) / scale), (int)height);
535  int j_max = std::min<int>((int)ceil((iP.get_j() + w) / scale), (int)width);
536 
537  unsigned int i_min_ = (unsigned int)i_min;
538  unsigned int i_max_ = (unsigned int)i_max;
539  unsigned int j_min_ = (unsigned int)j_min;
540  unsigned int j_max_ = (unsigned int)j_max;
541 
542  for (unsigned int i = i_min_; i < i_max_; i++) {
543  unsigned char *dst_8 = (unsigned char *)Ximage->data + i * bytes_per_line;
544  unsigned short *dst_16 = (unsigned short *)dst_8;
545  for (unsigned int j = j_min_; j < j_max_; j++) {
546  *(dst_16 + j) = (unsigned short)colortable[I[i * scale][j * scale]];
547  }
548  }
549 
550  XPutImage(display, pixmap, context, Ximage, j_min, i_min, j_min, i_min, j_max_ - j_min_, i_max_ - i_min_);
551  }
552 
553  XSetWindowBackgroundPixmap(display, window, pixmap);
554  break;
555  }
556 
557  case 24:
558  default: {
559  if (scale == 1) {
560  unsigned int iwidth = I.getWidth();
561  unsigned char *src_8 = I.bitmap + (int)(iP.get_i() * iwidth + iP.get_j());
562  unsigned char *dst_32 = (unsigned char *)Ximage->data + (int)(iP.get_i() * 4 * width + iP.get_j() * 4);
563 
564  if (XImageByteOrder(display) == 1) {
565  // big endian
566  unsigned int i = 0;
567  while (i < h) {
568  unsigned int j = 0;
569  while (j < w) {
570  unsigned char val = *(src_8 + j);
571  *(dst_32 + 4 * j) = vpRGBa::alpha_default;
572  *(dst_32 + 4 * j + 1) = val;
573  *(dst_32 + 4 * j + 2) = val;
574  *(dst_32 + 4 * j + 3) = val;
575  j++;
576  }
577  src_8 = src_8 + iwidth;
578  dst_32 = dst_32 + 4 * width;
579  i++;
580  }
581  }
582  else {
583  // little endian
584  unsigned int i = 0;
585  while (i < h) {
586  unsigned int j = 0;
587  while (j < w) {
588  unsigned char val = *(src_8 + j);
589  *(dst_32 + 4 * j) = val;
590  *(dst_32 + 4 * j + 1) = val;
591  *(dst_32 + 4 * j + 2) = val;
592  *(dst_32 + 4 * j + 3) = vpRGBa::alpha_default;
593  j++;
594  }
595  src_8 = src_8 + iwidth;
596  dst_32 = dst_32 + 4 * width;
597  i++;
598  }
599  }
600 
601  XPutImage(display, pixmap, context, Ximage, (int)iP.get_u(), (int)iP.get_v(), (int)iP.get_u(), (int)iP.get_v(),
602  w, h);
603  }
604  else {
605  int i_min = std::max<int>((int)ceil(iP.get_i() / scale), 0);
606  int j_min = std::max<int>((int)ceil(iP.get_j() / scale), 0);
607  int i_max = std::min<int>((int)ceil((iP.get_i() + h) / scale), (int)height);
608  int j_max = std::min<int>((int)ceil((iP.get_j() + w) / scale), (int)width);
609 
610  unsigned int i_min_ = (unsigned int)i_min;
611  unsigned int i_max_ = (unsigned int)i_max;
612  unsigned int j_min_ = (unsigned int)j_min;
613  unsigned int j_max_ = (unsigned int)j_max;
614 
615  if (XImageByteOrder(display) == 1) {
616  // big endian
617  for (unsigned int i = i_min_; i < i_max_; i++) {
618  unsigned char *dst_32 = (unsigned char *)Ximage->data + (int)(i * 4 * width + j_min_ * 4);
619  for (unsigned int j = j_min_; j < j_max_; j++) {
620  unsigned char val = I[i * scale][j * scale];
621  *(dst_32++) = vpRGBa::alpha_default;
622  *(dst_32++) = val;
623  *(dst_32++) = val;
624  *(dst_32++) = val;
625  }
626  }
627  }
628  else {
629  // little endian
630  for (unsigned int i = i_min_; i < i_max_; i++) {
631  unsigned char *dst_32 = (unsigned char *)Ximage->data + (int)(i * 4 * width + j_min_ * 4);
632  for (unsigned int j = j_min_; j < j_max_; j++) {
633  unsigned char val = I[i * scale][j * scale];
634  *(dst_32++) = val;
635  *(dst_32++) = val;
636  *(dst_32++) = val;
637  *(dst_32++) = vpRGBa::alpha_default;
638  }
639  }
640  }
641 
642  XPutImage(display, pixmap, context, Ximage, j_min, i_min, j_min, i_min, j_max_ - j_min_, i_max_ - i_min_);
643  }
644 
645  XSetWindowBackgroundPixmap(display, window, pixmap);
646  break;
647  }
648  }
649  }
650 
651  void displayImageROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int w, unsigned int h,
652  unsigned int scale, unsigned int width, unsigned int height)
653  {
654  switch (screen_depth) {
655  case 16: {
656  if (scale == 1) {
657  unsigned int bytes_per_line = (unsigned int)Ximage->bytes_per_line;
658  for (unsigned int i = (unsigned int)iP.get_i(); i < (unsigned int)(iP.get_i() + h); i++) {
659  unsigned char *dst_8 = (unsigned char *)Ximage->data + i * bytes_per_line;
660  unsigned short *dst_16 = (unsigned short *)dst_8;
661  for (unsigned int j = (unsigned int)iP.get_j(); j < (unsigned int)(iP.get_j() + w); j++) {
662  vpRGBa val = I[i][j];
663  unsigned int r = val.R;
664  unsigned int g = val.G;
665  unsigned int b = val.B;
666  *(dst_16 + j) =
667  (((r << 8) >> RShift) & RMask) | (((g << 8) >> GShift) & GMask) | (((b << 8) >> BShift) & BMask);
668  }
669  }
670  XPutImage(display, pixmap, context, Ximage, (int)iP.get_u(), (int)iP.get_v(), (int)iP.get_u(), (int)iP.get_v(),
671  w, h);
672  }
673  else {
674  unsigned int bytes_per_line = (unsigned int)Ximage->bytes_per_line;
675  int i_min = std::max<int>((int)ceil(iP.get_i() / scale), 0);
676  int j_min = std::max<int>((int)ceil(iP.get_j() / scale), 0);
677  int i_max = std::min<int>((int)ceil((iP.get_i() + h) / scale), (int)height);
678  int j_max = std::min<int>((int)ceil((iP.get_j() + w) / scale), (int)width);
679 
680  unsigned int i_min_ = (unsigned int)i_min;
681  unsigned int i_max_ = (unsigned int)i_max;
682  unsigned int j_min_ = (unsigned int)j_min;
683  unsigned int j_max_ = (unsigned int)j_max;
684 
685  for (unsigned int i = i_min_; i < i_max_; i++) {
686  unsigned char *dst_8 = (unsigned char *)Ximage->data + i * bytes_per_line;
687  unsigned short *dst_16 = (unsigned short *)dst_8;
688  for (unsigned int j = j_min_; j < j_max_; j++) {
689  vpRGBa val = I[i * scale][j * scale];
690  unsigned int r = val.R;
691  unsigned int g = val.G;
692  unsigned int b = val.B;
693  *(dst_16 + j) =
694  (((r << 8) >> RShift) & RMask) | (((g << 8) >> GShift) & GMask) | (((b << 8) >> BShift) & BMask);
695  }
696  }
697  XPutImage(display, pixmap, context, Ximage, j_min, i_min, j_min, i_min, j_max_ - j_min_, i_max_ - i_min_);
698  }
699 
700  XSetWindowBackgroundPixmap(display, window, pixmap);
701 
702  break;
703  }
704  case 24:
705  case 32: {
706  /*
707  * 32-bit source, 24/32-bit destination
708  */
709 
710  if (scale == 1) {
711  unsigned char *dst_32 = (unsigned char *)Ximage->data;
712  vpRGBa *src_32 = I.bitmap;
713 
714  unsigned int iwidth = I.getWidth();
715 
716  src_32 = src_32 + (int)(iP.get_i() * iwidth + iP.get_j());
717  dst_32 = dst_32 + (int)(iP.get_i() * 4 * width + iP.get_j() * 4);
718 
719  unsigned int i = 0;
720 
721  if (XImageByteOrder(display) == 1) {
722  // big endian
723  while (i < h) {
724  unsigned int j = 0;
725  while (j < w) {
726  *(dst_32 + 4 * j) = (src_32 + j)->A;
727  *(dst_32 + 4 * j + 1) = (src_32 + j)->R;
728  *(dst_32 + 4 * j + 2) = (src_32 + j)->G;
729  *(dst_32 + 4 * j + 3) = (src_32 + j)->B;
730 
731  j++;
732  }
733  src_32 = src_32 + iwidth;
734  dst_32 = dst_32 + 4 * width;
735  i++;
736  }
737 
738  }
739  else {
740  // little endian
741  while (i < h) {
742  unsigned int j = 0;
743  while (j < w) {
744  *(dst_32 + 4 * j) = (src_32 + j)->B;
745  *(dst_32 + 4 * j + 1) = (src_32 + j)->G;
746  *(dst_32 + 4 * j + 2) = (src_32 + j)->R;
747  *(dst_32 + 4 * j + 3) = (src_32 + j)->A;
748 
749  j++;
750  }
751  src_32 = src_32 + iwidth;
752  dst_32 = dst_32 + 4 * width;
753  i++;
754  }
755  }
756 
757  XPutImage(display, pixmap, context, Ximage, (int)iP.get_u(), (int)iP.get_v(), (int)iP.get_u(), (int)iP.get_v(),
758  w, h);
759  }
760  else {
761  int i_min = std::max<int>((int)ceil(iP.get_i() / scale), 0);
762  int j_min = std::max<int>((int)ceil(iP.get_j() / scale), 0);
763  int i_max = std::min<int>((int)ceil((iP.get_i() + h) / scale), (int)height);
764  int j_max = std::min<int>((int)ceil((iP.get_j() + w) / scale), (int)width);
765 
766  unsigned int i_min_ = (unsigned int)i_min;
767  unsigned int i_max_ = (unsigned int)i_max;
768  unsigned int j_min_ = (unsigned int)j_min;
769  unsigned int j_max_ = (unsigned int)j_max;
770 
771  if (XImageByteOrder(display) == 1) {
772  // big endian
773  for (unsigned int i = i_min_; i < i_max_; i++) {
774  unsigned char *dst_32 = (unsigned char *)Ximage->data + (int)(i * 4 * width + j_min_ * 4);
775  for (unsigned int j = j_min_; j < j_max_; j++) {
776  vpRGBa val = I[i * scale][j * scale];
777  *(dst_32++) = val.A;
778  *(dst_32++) = val.R;
779  *(dst_32++) = val.G;
780  *(dst_32++) = val.B;
781  }
782  }
783  }
784  else {
785  // little endian
786  for (unsigned int i = i_min_; i < i_max_; i++) {
787  unsigned char *dst_32 = (unsigned char *)Ximage->data + (int)(i * 4 * width + j_min_ * 4);
788  for (unsigned int j = j_min_; j < j_max_; j++) {
789  vpRGBa val = I[i * scale][j * scale];
790  *(dst_32++) = val.B;
791  *(dst_32++) = val.G;
792  *(dst_32++) = val.R;
793  *(dst_32++) = val.A;
794  }
795  }
796  }
797  XPutImage(display, pixmap, context, Ximage, j_min, i_min, j_min, i_min, j_max_ - j_min_, i_max_ - i_min_);
798  }
799 
800  XSetWindowBackgroundPixmap(display, window, pixmap);
801  break;
802  }
803  default:
805  "Unsupported depth (%d bpp) for color display", screen_depth));
806  }
807  }
808 
809  void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness,
810  unsigned int scale)
811  {
812  if (color.id < vpColor::id_unknown)
813  XSetForeground(display, context, x_color[color.id]);
814  else {
815  xcolor.pad = 0;
816  xcolor.red = 256 * color.R;
817  xcolor.green = 256 * color.G;
818  xcolor.blue = 256 * color.B;
819  XAllocColor(display, lut, &xcolor);
820  XSetForeground(display, context, xcolor.pixel);
821  }
822 
823  XSetLineAttributes(display, context, thickness, LineSolid, CapButt, JoinBevel);
824 
825  XDrawLine(display, pixmap, context, vpMath::round(ip1.get_u() / scale), vpMath::round(ip1.get_v() / scale),
826  vpMath::round(ip2.get_u() / scale), vpMath::round(ip2.get_v() / scale));
827  }
828 
829  void displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness, unsigned int scale)
830  {
831  if (color.id < vpColor::id_unknown)
832  XSetForeground(display, context, x_color[color.id]);
833  else {
834  xcolor.pad = 0;
835  xcolor.red = 256 * color.R;
836  xcolor.green = 256 * color.G;
837  xcolor.blue = 256 * color.B;
838  XAllocColor(display, lut, &xcolor);
839  XSetForeground(display, context, xcolor.pixel);
840  }
841 
842  if (thickness == 1) {
843  XDrawPoint(display, pixmap, context, vpMath::round(ip.get_u() / scale), vpMath::round(ip.get_v() / scale));
844  }
845  else {
846  XFillRectangle(display, pixmap, context, vpMath::round(ip.get_u() / scale), vpMath::round(ip.get_v() / scale),
847  thickness, thickness);
848  }
849  }
850 
851  void displayRectangle(const vpImagePoint &topLeft, unsigned int w, unsigned int h, const vpColor &color, bool fill,
852  unsigned int thickness, unsigned int scale)
853  {
854  if (color.id < vpColor::id_unknown)
855  XSetForeground(display, context, x_color[color.id]);
856  else {
857  xcolor.pad = 0;
858  xcolor.red = 256 * color.R;
859  xcolor.green = 256 * color.G;
860  xcolor.blue = 256 * color.B;
861  XAllocColor(display, lut, &xcolor);
862  XSetForeground(display, context, xcolor.pixel);
863  }
864  XSetLineAttributes(display, context, thickness, LineSolid, CapButt, JoinBevel);
865  if (fill == false) {
866  XDrawRectangle(display, pixmap, context, vpMath::round(topLeft.get_u() / scale),
867  vpMath::round(topLeft.get_v() / scale), w / scale, h / scale);
868  }
869  else {
870  XFillRectangle(display, pixmap, context, vpMath::round(topLeft.get_u() / scale),
871  vpMath::round(topLeft.get_v() / scale), w / scale, h / scale);
872  }
873  }
874 
875  void flushDisplay()
876  {
877  XClearWindow(display, window);
878  XFlush(display);
879  }
880 
881  void flushDisplayROI(const vpImagePoint &iP, unsigned int w, unsigned int h, unsigned int scale)
882  {
883  XClearArea(display, window, (int)(iP.get_u() / scale), (int)(iP.get_v() / scale), w / scale, h / scale, 0);
884  XFlush(display);
885  }
886 
887  bool getClick(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking, unsigned int scale)
888  {
889  bool ret = false;
890  Window rootwin, childwin;
891  int root_x, root_y, win_x, win_y;
892  unsigned int modifier;
893 
894  // Event testing
895  if (blocking) {
896  XCheckMaskEvent(display, ButtonPressMask, &event);
897  XCheckMaskEvent(display, ButtonReleaseMask, &event);
898  XMaskEvent(display, ButtonPressMask, &event);
899  ret = true;
900  }
901  else {
902  ret = XCheckMaskEvent(display, ButtonPressMask, &event);
903  }
904 
905  if (ret) {
906  // Get mouse position
907  if (XQueryPointer(display, window, &rootwin, &childwin, &root_x, &root_y, &win_x, &win_y, &modifier)) {
908  ip.set_u((double)event.xbutton.x * scale);
909  ip.set_v((double)event.xbutton.y * scale);
910  switch (event.xbutton.button) {
911  case Button1:
912  button = vpMouseButton::button1;
913  break;
914  case Button2:
915  button = vpMouseButton::button2;
916  break;
917  case Button3:
918  button = vpMouseButton::button3;
919  break;
920  }
921  }
922  }
923 
924  return ret;
925  }
926 
927  bool getClickUp(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking, unsigned int scale)
928  {
929  bool ret = false;
930  Window rootwin, childwin;
931  int root_x, root_y, win_x, win_y;
932  unsigned int modifier;
933 
934  // Event testing
935  if (blocking) {
936  XCheckMaskEvent(display, ButtonPressMask, &event);
937  XCheckMaskEvent(display, ButtonReleaseMask, &event);
938  XMaskEvent(display, ButtonReleaseMask, &event);
939  ret = true;
940  }
941  else {
942  ret = XCheckMaskEvent(display, ButtonReleaseMask, &event);
943  }
944 
945  if (ret) {
946  /* Recuperation de la coordonnee du pixel clique. */
947  if (XQueryPointer(display, window, &rootwin, &childwin, &root_x, &root_y, &win_x, &win_y, &modifier)) {
948  ip.set_u((double)event.xbutton.x * scale);
949  ip.set_v((double)event.xbutton.y * scale);
950  switch (event.xbutton.button) {
951  case Button1:
952  button = vpMouseButton::button1;
953  break;
954  case Button2:
955  button = vpMouseButton::button2;
956  break;
957  case Button3:
958  button = vpMouseButton::button3;
959  break;
960  }
961  }
962  }
963 
964  return ret;
965  }
966 
967  void getImage(vpImage<vpRGBa> &I, unsigned int width, unsigned int height)
968  {
969  XImage *xi;
970 
971  XCopyArea(display, window, pixmap, context, 0, 0, width, height, 0, 0);
972 
973  xi = XGetImage(display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
974 
975  I.resize(height, width);
976 
977  unsigned char *src_32 = nullptr;
978  src_32 = (unsigned char *)xi->data;
979 
980  if (screen_depth == 16) {
981  for (unsigned int i = 0; i < I.getHeight(); i++) {
982  size_t i_ = i * width;
983  for (unsigned int j = 0; j < height; j++) {
984  size_t ij_ = i_ + j;
985  unsigned long pixel = XGetPixel(xi, (int)j, (int)i);
986  I.bitmap[ij_].R = (((pixel & RMask) << RShift) >> 8);
987  I.bitmap[ij_].G = (((pixel & GMask) << GShift) >> 8);
988  I.bitmap[ij_].B = (((pixel & BMask) << BShift) >> 8);
989  // On OSX the bottom/right corner (around the resizing icon) has
990  // alpha component with different values than 255. That's why we
991  // force alpha to vpRGBa::alpha_default
992  I.bitmap[ij_].A = vpRGBa::alpha_default;
993  }
994  }
995 
996  }
997  else {
998  if (XImageByteOrder(display) == 1) {
999  // big endian
1000  for (unsigned int i = 0; i < width * height; i++) {
1001  // On OSX the bottom/right corner (around the resizing icon) has
1002  // alpha component with different values than 255. That's why we
1003  // force alpha to vpRGBa::alpha_default
1004  I.bitmap[i].A = vpRGBa::alpha_default; // src_32[i*4] ;
1005  I.bitmap[i].R = src_32[i * 4 + 1];
1006  I.bitmap[i].G = src_32[i * 4 + 2];
1007  I.bitmap[i].B = src_32[i * 4 + 3];
1008  }
1009  }
1010  else {
1011  // little endian
1012  for (unsigned int i = 0; i < width * height; i++) {
1013  I.bitmap[i].B = src_32[i * 4];
1014  I.bitmap[i].G = src_32[i * 4 + 1];
1015  I.bitmap[i].R = src_32[i * 4 + 2];
1016  // On OSX the bottom/right corner (around the resizing icon) has
1017  // alpha component with different values than 255. That's why we
1018  // force alpha to vpRGBa::alpha_default
1019  I.bitmap[i].A = vpRGBa::alpha_default; // src_32[i*4 + 3];
1020  }
1021  }
1022  }
1023  XDestroyImage(xi);
1024  }
1025 
1026  bool getKeyboardEvent(bool blocking)
1027  {
1028  bool ret = false;
1029 
1030  // Event testing
1031  if (blocking) {
1032  XMaskEvent(display, KeyPressMask, &event);
1033  ret = true;
1034  }
1035  else {
1036  ret = XCheckMaskEvent(display, KeyPressMask, &event);
1037  }
1038 
1039  return ret;
1040  }
1041 
1042  bool getKeyboardEvent(std::string &key, bool blocking)
1043  {
1044  bool ret = false;
1045  KeySym keysym;
1046  // int count;
1047  XComposeStatus compose_status;
1048  char buffer;
1049 
1050  // Event testing
1051  if (blocking) {
1052  XMaskEvent(display, KeyPressMask, &event);
1053  /* count = */ XLookupString((XKeyEvent *)&event, &buffer, 1, &keysym, &compose_status);
1054  key = buffer;
1055  ret = true;
1056  }
1057  else {
1058  ret = XCheckMaskEvent(display, KeyPressMask, &event);
1059  if (ret) {
1060  /* count = */ XLookupString((XKeyEvent *)&event, &buffer, 1, &keysym, &compose_status);
1061  key = buffer;
1062  }
1063  }
1064 
1065  return ret;
1066  }
1067 
1071  int getMsb(unsigned int u32val)
1072  {
1073  int i;
1074 
1075  for (i = 31; i >= 0; --i) {
1076  if (u32val & 0x80000000L)
1077  break;
1078  u32val <<= 1;
1079  }
1080  return i;
1081  }
1082 
1083  bool getPointerMotionEvent(vpImagePoint &ip, unsigned int scale)
1084  {
1085  bool ret = false;
1086 
1087  Window rootwin, childwin;
1088  int root_x, root_y, win_x, win_y;
1089  unsigned int modifier;
1090  // Event testing
1091  ret = XCheckMaskEvent(display, PointerMotionMask, &event);
1092 
1093  if (ret) {
1094  // Get mouse position
1095  if (XQueryPointer(display, window, &rootwin, &childwin, &root_x, &root_y, &win_x, &win_y, &modifier)) {
1096  ip.set_u((double)event.xbutton.x * scale);
1097  ip.set_v((double)event.xbutton.y * scale);
1098  }
1099  }
1100 
1101  return ret;
1102  }
1103 
1104  bool getPointerPosition(vpImagePoint &ip, unsigned int scale)
1105  {
1106  bool ret = false;
1107  Window rootwin, childwin;
1108  int root_x, root_y, win_x, win_y;
1109  unsigned int modifier;
1110  // Event testing
1111  ret = true;
1112 
1113  if (ret) {
1114  // Get mouse position
1115  if (XQueryPointer(display, window, &rootwin, &childwin, &root_x, &root_y, &win_x, &win_y, &modifier)) {
1116  ip.set_u((double)win_x * scale);
1117  ip.set_v((double)win_y * scale);
1118  }
1119  }
1120 
1121  return ret;
1122  }
1123 
1124  unsigned int getScreenDepth()
1125  {
1126  Display *display_;
1127  int screen_;
1128  unsigned int depth;
1129 
1130  if ((display_ = XOpenDisplay(nullptr)) == nullptr) {
1131  throw(vpDisplayException(vpDisplayException::connexionError, "Can't connect display on server %s.",
1132  XDisplayName(nullptr)));
1133  }
1134  screen_ = DefaultScreen(display_);
1135  depth = (unsigned int)DefaultDepth(display_, screen_);
1136 
1137  XCloseDisplay(display_);
1138 
1139  return (depth);
1140  }
1141 
1142  void getScreenSize(unsigned int &w, unsigned int &h)
1143  {
1144  Display *display_;
1145  int screen_;
1146 
1147  if ((display_ = XOpenDisplay(nullptr)) == nullptr) {
1148  throw(vpDisplayException(vpDisplayException::connexionError, "Can't connect display on server %s.",
1149  XDisplayName(nullptr)));
1150  }
1151  screen_ = DefaultScreen(display_);
1152  w = (unsigned int)DisplayWidth(display_, screen_);
1153  h = (unsigned int)DisplayHeight(display_, screen_);
1154 
1155  XCloseDisplay(display_);
1156  }
1157 
1158  void init(unsigned int win_width, unsigned int win_height, int win_x, int win_y, const std::string &win_title)
1159  {
1160  if (x_color == nullptr) {
1161  // id_unknown = number of predefined colors
1162  x_color = new unsigned long[vpColor::id_unknown];
1163  }
1164  // setup X11
1165  XSizeHints hints;
1166 
1167  // Positionnement de la fenetre dans l'ecran.
1168  if ((win_x < 0) || (win_y < 0)) {
1169  hints.flags = 0;
1170  }
1171  else {
1172  hints.flags = USPosition;
1173  hints.x = win_x;
1174  hints.y = win_y;
1175  }
1176 
1177  if ((display = XOpenDisplay(nullptr)) == nullptr) {
1178  vpERROR_TRACE("Can't connect display on server %s.\n", XDisplayName(nullptr));
1179  throw(vpDisplayException(vpDisplayException::connexionError, "Can't connect display on server."));
1180  }
1181 
1182  screen = DefaultScreen(display);
1183  lut = DefaultColormap(display, screen);
1184  screen_depth = (unsigned int)DefaultDepth(display, screen);
1185 
1186  vpTRACE("Screen depth: %d\n", screen_depth);
1187 
1188  if ((window = XCreateSimpleWindow(display, RootWindow(display, screen), win_x, win_y, win_width, win_height, 1,
1189  BlackPixel(display, screen), WhitePixel(display, screen))) == 0) {
1190  vpERROR_TRACE("Can't create window.");
1191  throw(vpDisplayException(vpDisplayException::cannotOpenWindowError, "Can't create window."));
1192  }
1193 
1194  //
1195  // Create color table for 8 and 16 bits screen
1196  //
1197  if (screen_depth == 8) {
1198  lut = XCreateColormap(display, window, DefaultVisual(display, screen), AllocAll);
1199  xcolor.flags = DoRed | DoGreen | DoBlue;
1200 
1201  for (unsigned int i = 0; i < 256; i++) {
1202  xcolor.pixel = i;
1203  xcolor.red = 256 * i;
1204  xcolor.green = 256 * i;
1205  xcolor.blue = 256 * i;
1206  XStoreColor(display, lut, &xcolor);
1207  }
1208 
1209  XSetWindowColormap(display, window, lut);
1210  XInstallColormap(display, lut);
1211  }
1212 
1213  else if (screen_depth == 16) {
1214  for (unsigned int i = 0; i < 256; i++) {
1215  xcolor.pad = 0;
1216  xcolor.red = xcolor.green = xcolor.blue = 256 * i;
1217  if (XAllocColor(display, lut, &xcolor) == 0) {
1218  vpERROR_TRACE("Can't allocate 256 colors. Only %d allocated.", i);
1219  throw(vpDisplayException(vpDisplayException::colorAllocError, "Can't allocate 256 colors."));
1220  }
1221  colortable[i] = xcolor.pixel;
1222  }
1223 
1224  XSetWindowColormap(display, window, lut);
1225  XInstallColormap(display, lut);
1226 
1227  Visual *visual = DefaultVisual(display, screen);
1228  RMask = visual->red_mask;
1229  GMask = visual->green_mask;
1230  BMask = visual->blue_mask;
1231 
1232  RShift = 15 - getMsb(RMask); /* these are right-shifts */
1233  GShift = 15 - getMsb(GMask);
1234  BShift = 15 - getMsb(BMask);
1235  }
1236 
1237  vpColor pcolor; // predefined colors
1238 
1239  //
1240  // Create colors for overlay
1241  //
1242  switch (screen_depth) {
1243 
1244  case 8:
1245  // Color BLACK: default set to 0
1246 
1247  // Color WHITE: default set to 255
1248 
1249  // Color LIGHT GRAY.
1250  x_color[vpColor::id_lightGray] = 254;
1251  xcolor.pixel = x_color[vpColor::id_lightGray];
1252  xcolor.red = 256 * 192;
1253  xcolor.green = 256 * 192;
1254  xcolor.blue = 256 * 192;
1255  XStoreColor(display, lut, &xcolor);
1256 
1257  // Color GRAY.
1258  x_color[vpColor::id_gray] = 253;
1259  xcolor.pixel = x_color[vpColor::id_gray];
1260  xcolor.red = 256 * 128;
1261  xcolor.green = 256 * 128;
1262  xcolor.blue = 256 * 128;
1263  XStoreColor(display, lut, &xcolor);
1264 
1265  // Color DARK GRAY.
1266  x_color[vpColor::id_darkGray] = 252;
1267  xcolor.pixel = x_color[vpColor::id_darkGray];
1268  xcolor.red = 256 * 64;
1269  xcolor.green = 256 * 64;
1270  xcolor.blue = 256 * 64;
1271  XStoreColor(display, lut, &xcolor);
1272 
1273  // Color LIGHT RED.
1274  x_color[vpColor::id_lightRed] = 251;
1275  xcolor.pixel = x_color[vpColor::id_lightRed];
1276  xcolor.red = 256 * 255;
1277  xcolor.green = 256 * 140;
1278  xcolor.blue = 256 * 140;
1279  XStoreColor(display, lut, &xcolor);
1280 
1281  // Color RED.
1282  x_color[vpColor::id_red] = 250;
1283  xcolor.pixel = x_color[vpColor::id_red];
1284  xcolor.red = 256 * 255;
1285  xcolor.green = 0;
1286  xcolor.blue = 0;
1287  XStoreColor(display, lut, &xcolor);
1288 
1289  // Color DARK RED.
1290  x_color[vpColor::id_darkRed] = 249;
1291  xcolor.pixel = x_color[vpColor::id_darkRed];
1292  xcolor.red = 256 * 128;
1293  xcolor.green = 0;
1294  xcolor.blue = 0;
1295  XStoreColor(display, lut, &xcolor);
1296 
1297  // Color LIGHT GREEN.
1298  x_color[vpColor::id_lightGreen] = 248;
1299  xcolor.pixel = x_color[vpColor::id_lightGreen];
1300  xcolor.red = 256 * 140;
1301  xcolor.green = 256 * 255;
1302  xcolor.blue = 256 * 140;
1303  XStoreColor(display, lut, &xcolor);
1304 
1305  // Color GREEN.
1306  x_color[vpColor::id_green] = 247;
1307  xcolor.pixel = x_color[vpColor::id_green];
1308  xcolor.red = 0;
1309  xcolor.green = 256 * 255;
1310  xcolor.blue = 0;
1311  XStoreColor(display, lut, &xcolor);
1312 
1313  // Color DARK GREEN.
1314  x_color[vpColor::id_darkGreen] = 246;
1315  xcolor.pixel = x_color[vpColor::id_darkGreen];
1316  xcolor.red = 0;
1317  xcolor.green = 256 * 128;
1318  xcolor.blue = 0;
1319  XStoreColor(display, lut, &xcolor);
1320 
1321  // Color LIGHT BLUE.
1322  x_color[vpColor::id_lightBlue] = 245;
1323  xcolor.pixel = x_color[vpColor::id_lightBlue];
1324  xcolor.red = 256 * 140;
1325  xcolor.green = 256 * 140;
1326  xcolor.blue = 256 * 255;
1327  XStoreColor(display, lut, &xcolor);
1328 
1329  // Color BLUE.
1330  x_color[vpColor::id_blue] = 244;
1331  xcolor.pixel = x_color[vpColor::id_blue];
1332  xcolor.red = 0;
1333  xcolor.green = 0;
1334  xcolor.blue = 256 * 255;
1335  XStoreColor(display, lut, &xcolor);
1336 
1337  // Color DARK BLUE.
1338  x_color[vpColor::id_darkBlue] = 243;
1339  xcolor.pixel = x_color[vpColor::id_darkBlue];
1340  xcolor.red = 0;
1341  xcolor.green = 0;
1342  xcolor.blue = 256 * 128;
1343  XStoreColor(display, lut, &xcolor);
1344 
1345  // Color YELLOW.
1346  x_color[vpColor::id_yellow] = 242;
1347  xcolor.pixel = x_color[vpColor::id_yellow];
1348  xcolor.red = 256 * 255;
1349  xcolor.green = 256 * 255;
1350  xcolor.blue = 0;
1351  XStoreColor(display, lut, &xcolor);
1352 
1353  // Color ORANGE.
1354  x_color[vpColor::id_orange] = 241;
1355  xcolor.pixel = x_color[vpColor::id_orange];
1356  xcolor.red = 256 * 255;
1357  xcolor.green = 256 * 165;
1358  xcolor.blue = 0;
1359  XStoreColor(display, lut, &xcolor);
1360 
1361  // Color CYAN.
1362  x_color[vpColor::id_cyan] = 240;
1363  xcolor.pixel = x_color[vpColor::id_cyan];
1364  xcolor.red = 0;
1365  xcolor.green = 256 * 255;
1366  xcolor.blue = 256 * 255;
1367  XStoreColor(display, lut, &xcolor);
1368 
1369  // Color PURPLE.
1370  x_color[vpColor::id_purple] = 239;
1371  xcolor.pixel = x_color[vpColor::id_purple];
1372  xcolor.red = 256 * 128;
1373  xcolor.green = 0;
1374  xcolor.blue = 256 * 128;
1375  XStoreColor(display, lut, &xcolor);
1376 
1377  break;
1378 
1379  case 16:
1380  case 24:
1381  case 32: {
1382  xcolor.flags = DoRed | DoGreen | DoBlue;
1383 
1384  // Couleur BLACK.
1385  pcolor = vpColor::black;
1386  xcolor.pad = 0;
1387  xcolor.red = 256 * pcolor.R;
1388  xcolor.green = 256 * pcolor.G;
1389  xcolor.blue = 256 * pcolor.B;
1390  XAllocColor(display, lut, &xcolor);
1391  x_color[vpColor::id_black] = xcolor.pixel;
1392 
1393  // Color WHITE.
1394  pcolor = vpColor::white;
1395  xcolor.pad = 0;
1396  xcolor.red = 256 * pcolor.R;
1397  xcolor.green = 256 * pcolor.G;
1398  xcolor.blue = 256 * pcolor.B;
1399  XAllocColor(display, lut, &xcolor);
1400  x_color[vpColor::id_white] = xcolor.pixel;
1401 
1402  // Color LIGHT GRAY.
1403  pcolor = vpColor::lightGray;
1404  xcolor.pad = 0;
1405  xcolor.red = 256 * pcolor.R;
1406  xcolor.green = 256 * pcolor.G;
1407  xcolor.blue = 256 * pcolor.B;
1408  XAllocColor(display, lut, &xcolor);
1409  x_color[vpColor::id_lightGray] = xcolor.pixel;
1410 
1411  // Color GRAY.
1412  pcolor = vpColor::gray;
1413  xcolor.pad = 0;
1414  xcolor.red = 256 * pcolor.R;
1415  xcolor.green = 256 * pcolor.G;
1416  xcolor.blue = 256 * pcolor.B;
1417  XAllocColor(display, lut, &xcolor);
1418  x_color[vpColor::id_gray] = xcolor.pixel;
1419 
1420  // Color DARK GRAY.
1421  pcolor = vpColor::darkGray;
1422  xcolor.pad = 0;
1423  xcolor.red = 256 * pcolor.R;
1424  xcolor.green = 256 * pcolor.G;
1425  xcolor.blue = 256 * pcolor.B;
1426  XAllocColor(display, lut, &xcolor);
1427  x_color[vpColor::id_darkGray] = xcolor.pixel;
1428 
1429  // Color LIGHT RED.
1430  pcolor = vpColor::lightRed;
1431  xcolor.pad = 0;
1432  xcolor.red = 256 * pcolor.R;
1433  xcolor.green = 256 * pcolor.G;
1434  xcolor.blue = 256 * pcolor.B;
1435  XAllocColor(display, lut, &xcolor);
1436  x_color[vpColor::id_lightRed] = xcolor.pixel;
1437 
1438  // Color RED.
1439  pcolor = vpColor::red;
1440  xcolor.pad = 0;
1441  xcolor.red = 256 * pcolor.R;
1442  xcolor.green = 256 * pcolor.G;
1443  xcolor.blue = 256 * pcolor.B;
1444  XAllocColor(display, lut, &xcolor);
1445  x_color[vpColor::id_red] = xcolor.pixel;
1446 
1447  // Color DARK RED.
1448  pcolor = vpColor::darkRed;
1449  xcolor.pad = 0;
1450  xcolor.red = 256 * pcolor.R;
1451  xcolor.green = 256 * pcolor.G;
1452  xcolor.blue = 256 * pcolor.B;
1453  XAllocColor(display, lut, &xcolor);
1454  x_color[vpColor::id_darkRed] = xcolor.pixel;
1455 
1456  // Color LIGHT GREEN.
1457  pcolor = vpColor::lightGreen;
1458  xcolor.pad = 0;
1459  xcolor.red = 256 * pcolor.R;
1460  xcolor.green = 256 * pcolor.G;
1461  xcolor.blue = 256 * pcolor.B;
1462  XAllocColor(display, lut, &xcolor);
1463  x_color[vpColor::id_lightGreen] = xcolor.pixel;
1464 
1465  // Color GREEN.
1466  pcolor = vpColor::green;
1467  xcolor.pad = 0;
1468  xcolor.red = 256 * pcolor.R;
1469  xcolor.green = 256 * pcolor.G;
1470  xcolor.blue = 256 * pcolor.B;
1471  XAllocColor(display, lut, &xcolor);
1472  x_color[vpColor::id_green] = xcolor.pixel;
1473 
1474  // Color DARK GREEN.
1475  pcolor = vpColor::darkGreen;
1476  xcolor.pad = 0;
1477  xcolor.red = 256 * pcolor.R;
1478  xcolor.green = 256 * pcolor.G;
1479  xcolor.blue = 256 * pcolor.B;
1480  XAllocColor(display, lut, &xcolor);
1481  x_color[vpColor::id_darkGreen] = xcolor.pixel;
1482 
1483  // Color LIGHT BLUE.
1484  pcolor = vpColor::lightBlue;
1485  xcolor.pad = 0;
1486  xcolor.red = 256 * pcolor.R;
1487  xcolor.green = 256 * pcolor.G;
1488  xcolor.blue = 256 * pcolor.B;
1489  XAllocColor(display, lut, &xcolor);
1490  x_color[vpColor::id_lightBlue] = xcolor.pixel;
1491 
1492  // Color BLUE.
1493  pcolor = vpColor::blue;
1494  xcolor.pad = 0;
1495  xcolor.red = 256 * pcolor.R;
1496  xcolor.green = 256 * pcolor.G;
1497  xcolor.blue = 256 * pcolor.B;
1498  XAllocColor(display, lut, &xcolor);
1499  x_color[vpColor::id_blue] = xcolor.pixel;
1500 
1501  // Color DARK BLUE.
1502  pcolor = vpColor::darkBlue;
1503  xcolor.pad = 0;
1504  xcolor.red = 256 * pcolor.R;
1505  xcolor.green = 256 * pcolor.G;
1506  xcolor.blue = 256 * pcolor.B;
1507  XAllocColor(display, lut, &xcolor);
1508  x_color[vpColor::id_darkBlue] = xcolor.pixel;
1509 
1510  // Color YELLOW.
1511  pcolor = vpColor::yellow;
1512  xcolor.pad = 0;
1513  xcolor.red = 256 * pcolor.R;
1514  xcolor.green = 256 * pcolor.G;
1515  xcolor.blue = 256 * pcolor.B;
1516  XAllocColor(display, lut, &xcolor);
1517  x_color[vpColor::id_yellow] = xcolor.pixel;
1518 
1519  // Color ORANGE.
1520  pcolor = vpColor::orange;
1521  xcolor.pad = 0;
1522  xcolor.red = 256 * pcolor.R;
1523  xcolor.green = 256 * pcolor.G;
1524  xcolor.blue = 256 * pcolor.B;
1525  XAllocColor(display, lut, &xcolor);
1526  x_color[vpColor::id_orange] = xcolor.pixel;
1527 
1528  // Color CYAN.
1529  pcolor = vpColor::cyan;
1530  xcolor.pad = 0;
1531  xcolor.red = 256 * pcolor.R;
1532  xcolor.green = 256 * pcolor.G;
1533  xcolor.blue = 256 * pcolor.B;
1534  XAllocColor(display, lut, &xcolor);
1535  x_color[vpColor::id_cyan] = xcolor.pixel;
1536 
1537  // Color PURPLE.
1538  pcolor = vpColor::purple;
1539  xcolor.pad = 0;
1540  xcolor.red = 256 * pcolor.R;
1541  xcolor.green = 256 * pcolor.G;
1542  xcolor.blue = 256 * pcolor.B;
1543  XAllocColor(display, lut, &xcolor);
1544  x_color[vpColor::id_purple] = xcolor.pixel;
1545  break;
1546  }
1547  }
1548 
1549  XSetStandardProperties(display, window, win_title.c_str(), win_title.c_str(), None, 0, 0, &hints);
1550  XMapWindow(display, window);
1551  // Selection des evenements.
1552  XSelectInput(display, window,
1553  ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
1554  StructureNotifyMask | PointerMotionMask);
1555 
1556  /* Creation du contexte graphique */
1557  values.plane_mask = AllPlanes;
1558  values.fill_style = FillSolid;
1559  values.foreground = WhitePixel(display, screen);
1560  values.background = BlackPixel(display, screen);
1561  context = XCreateGC(display, window, GCPlaneMask | GCFillStyle | GCForeground | GCBackground, &values);
1562 
1563  if (context == nullptr) {
1564  vpERROR_TRACE("Can't create graphics context.");
1565  throw(vpDisplayException(vpDisplayException::XWindowsError, "Can't create graphics context"));
1566  }
1567 
1568  // Pixmap creation.
1569  pixmap = XCreatePixmap(display, window, win_width, win_height, screen_depth);
1570 
1571  // Hangs when forward X11 is used to send the display to an other computer
1572  // do
1573  // XNextEvent ( display, &event );
1574  // while ( event.xany.type != Expose );
1575 
1576  {
1577  Ximage = XCreateImage(display, DefaultVisual(display, screen), screen_depth, ZPixmap, 0, nullptr, win_width,
1578  win_height, XBitmapPad(display), 0);
1579 
1580  Ximage->data = (char *)malloc(win_height * (unsigned int)Ximage->bytes_per_line);
1581  ximage_data_init = true;
1582  }
1583 
1584  XSync(display, true);
1585 
1586  XStoreName(display, window, win_title.c_str());
1587  }
1588 
1589  void setFont(const std::string &fontname)
1590  {
1591  try {
1592  Font stringfont;
1593  stringfont = XLoadFont(display, fontname.c_str()); //"-adobe-times-bold-r-normal--18*");
1594  XSetFont(display, context, stringfont);
1595  }
1596  catch (...) {
1598  }
1599  }
1600 
1601  void setTitle(const std::string &title) { XStoreName(display, window, title.c_str()); }
1602 
1603  void setWindowPosition(int win_x, int win_y) { XMoveWindow(display, window, win_x, win_y); }
1604 
1605 private:
1606  Display *display;
1607  Window window;
1608  XImage *Ximage;
1609  Colormap lut;
1610  GC context;
1611  int screen;
1612  XEvent event;
1613  Pixmap pixmap;
1614  unsigned long *x_color; // Array of predefined colors
1615  unsigned int screen_depth;
1616  unsigned short colortable[256];
1617  XColor xcolor;
1618  XGCValues values;
1619  bool ximage_data_init;
1620  unsigned int RMask, GMask, BMask;
1621  int RShift, GShift, BShift;
1622 };
1623 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
1624 
1645 {
1646  setScale(scaleType, I.getWidth(), I.getHeight());
1647 
1648  init(I);
1649 }
1650 
1672 vpDisplayX::vpDisplayX(vpImage<unsigned char> &I, int x, int y, const std::string &title, vpScaleType scaleType)
1673  : vpDisplay(), m_impl(new Impl())
1674 {
1675  setScale(scaleType, I.getWidth(), I.getHeight());
1676  init(I, x, y, title);
1677 }
1678 
1698 vpDisplayX::vpDisplayX(vpImage<vpRGBa> &I, vpScaleType scaleType) : vpDisplay(), m_impl(new Impl())
1699 {
1700  setScale(scaleType, I.getWidth(), I.getHeight());
1701  init(I);
1702 }
1703 
1725 vpDisplayX::vpDisplayX(vpImage<vpRGBa> &I, int x, int y, const std::string &title, vpScaleType scaleType)
1726  : vpDisplay(), m_impl(new Impl())
1727 {
1728  setScale(scaleType, I.getWidth(), I.getHeight());
1729  init(I, x, y, title);
1730 }
1731 
1753 vpDisplayX::vpDisplayX(int x, int y, const std::string &title) : vpDisplay(), m_impl(new Impl())
1754 {
1755  m_windowXPosition = x;
1756  m_windowYPosition = y;
1757 
1758  m_title = title;
1759 }
1760 
1780 vpDisplayX::vpDisplayX() : vpDisplay(), m_impl(new Impl()) { }
1781 
1786 {
1787  closeDisplay();
1788  delete m_impl;
1789 }
1790 
1798 void vpDisplayX::init(vpImage<unsigned char> &I, int win_x, int win_y, const std::string &win_title)
1799 {
1800  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
1801  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
1802  }
1803 
1804  if (win_x != -1)
1805  m_windowXPosition = win_x;
1806  if (win_y != -1)
1807  m_windowYPosition = win_y;
1808 
1809  if (!win_title.empty())
1810  m_title = win_title;
1811 
1814 
1815  I.display = this;
1817 }
1818 
1827 void vpDisplayX::init(vpImage<vpRGBa> &I, int win_x, int win_y, const std::string &win_title)
1828 {
1829  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
1830  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
1831  }
1832 
1833  if (win_x != -1)
1834  m_windowXPosition = win_x;
1835  if (win_y != -1)
1836  m_windowYPosition = win_y;
1837 
1838  if (!win_title.empty())
1839  m_title = win_title;
1840 
1843 
1844  I.display = this;
1846 }
1847 
1855 void vpDisplayX::init(unsigned int win_width, unsigned int win_height, int win_x, int win_y,
1856  const std::string &win_title)
1857 {
1858  setScale(m_scaleType, win_width, win_height);
1859 
1860  m_width = win_width / m_scale;
1861  m_height = win_height / m_scale;
1862 
1863  if (win_x != -1)
1864  m_windowXPosition = win_x;
1865  if (win_y != -1)
1866  m_windowYPosition = win_y;
1867 
1868  m_title = win_title;
1869 
1871 
1873 }
1874 
1889 void vpDisplayX::setFont(const std::string &fontname)
1890 {
1892  if (!fontname.empty()) {
1893  m_impl->setFont(fontname);
1894  }
1895  }
1896  else {
1897  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
1898  }
1899 }
1900 
1905 void vpDisplayX::setTitle(const std::string &title)
1906 {
1908  m_title = title;
1909  if (!title.empty())
1910  m_impl->setTitle(title);
1911  }
1912  else {
1913  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
1914  }
1915 }
1916 
1926 void vpDisplayX::setWindowPosition(int win_x, int win_y)
1927 {
1929  m_impl->setWindowPosition(win_x, win_y);
1930  }
1931  else {
1932  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
1933  }
1934 }
1935 
1948 {
1950  m_impl->displayImage(I, m_scale, m_width, m_height);
1951  }
1952  else {
1953  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
1954  }
1955 }
1956 
1969 {
1971  m_impl->displayImage(I, m_scale, m_width, m_height);
1972  }
1973  else {
1974  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
1975  }
1976 }
1977 
1989 void vpDisplayX::displayImage(const unsigned char *bitmap)
1990 {
1992  m_impl->displayImage(bitmap, m_width, m_height);
1993  }
1994  else {
1995  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
1996  }
1997 }
1998 
2014 void vpDisplayX::displayImageROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int w,
2015  unsigned int h)
2016 {
2018  m_impl->displayImageROI(I, iP, w, h, m_scale, m_width, m_height);
2019  }
2020  else {
2021  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2022  }
2023 }
2024 
2040 void vpDisplayX::displayImageROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int w, unsigned int h)
2041 {
2043  m_impl->displayImageROI(I, iP, w, h, m_scale, m_width, m_height);
2044  }
2045  else {
2046  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2047  }
2048 }
2049 
2058 {
2060  m_impl->closeDisplay();
2061 
2063  }
2064 }
2065 
2072 {
2074  m_impl->flushDisplay();
2075  }
2076  else {
2077  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2078  }
2079 }
2080 
2088 void vpDisplayX::flushDisplayROI(const vpImagePoint &iP, unsigned int w, unsigned int h)
2089 {
2091  m_impl->flushDisplayROI(iP, w, h, m_scale);
2092  }
2093  else {
2094  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2095  }
2096 }
2097 
2103 {
2105  m_impl->clearDisplay(color, m_width, m_height);
2106  }
2107  else {
2108  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2109  }
2110 }
2111 
2119 void vpDisplayX::displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int w,
2120  unsigned int h, unsigned int thickness)
2121 {
2123  double a = ip2.get_i() - ip1.get_i();
2124  double b = ip2.get_j() - ip1.get_j();
2125  double lg = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
2126 
2127  // if ( ( a==0 ) && ( b==0 ) )
2128  if ((std::fabs(a) <= std::numeric_limits<double>::epsilon()) &&
2129  (std::fabs(b) <= std::numeric_limits<double>::epsilon())) {
2130  // DisplayCrossLarge(i1,j1,3,col) ;
2131  }
2132  else {
2133  a /= lg;
2134  b /= lg;
2135 
2136  vpImagePoint ip3;
2137  ip3.set_i(ip2.get_i() - w * a);
2138  ip3.set_j(ip2.get_j() - w * b);
2139 
2140  vpImagePoint ip4;
2141  ip4.set_i(ip3.get_i() - b * h);
2142  ip4.set_j(ip3.get_j() + a * h);
2143 
2144  if (lg > 2 * vpImagePoint::distance(ip2, ip4))
2145  displayLine(ip2, ip4, color, thickness);
2146 
2147  ip4.set_i(ip3.get_i() + b * h);
2148  ip4.set_j(ip3.get_j() - a * h);
2149 
2150  if (lg > 2 * vpImagePoint::distance(ip2, ip4))
2151  displayLine(ip2, ip4, color, thickness);
2152 
2153  displayLine(ip1, ip2, color, thickness);
2154  }
2155  }
2156  else {
2157  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2158  }
2159 }
2160 
2172 void vpDisplayX::displayText(const vpImagePoint &ip, const std::string &text, const vpColor &color)
2173 {
2175  m_impl->displayText(ip, text, color, m_scale);
2176  }
2177  else {
2178  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2179  }
2180 }
2181 
2191 void vpDisplayX::displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
2192  unsigned int thickness)
2193 {
2195  if (thickness == 1)
2196  thickness = 0;
2197  m_impl->displayCircle(center, radius, color, fill, thickness, m_scale);
2198  }
2199  else {
2200  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2201  }
2202 }
2203 
2211 void vpDisplayX::displayCross(const vpImagePoint &ip, unsigned int cross_size, const vpColor &color,
2212  unsigned int thickness)
2213 {
2215  double i = ip.get_i();
2216  double j = ip.get_j();
2217  vpImagePoint ip1, ip2;
2218 
2219  ip1.set_i(i - cross_size / 2);
2220  ip1.set_j(j);
2221  ip2.set_i(i + cross_size / 2);
2222  ip2.set_j(j);
2223  displayLine(ip1, ip2, color, thickness);
2224 
2225  ip1.set_i(i);
2226  ip1.set_j(j - cross_size / 2);
2227  ip2.set_i(i);
2228  ip2.set_j(j + cross_size / 2);
2229 
2230  displayLine(ip1, ip2, color, thickness);
2231  }
2232  else {
2233  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2234  }
2235 }
2242 void vpDisplayX::displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
2243  unsigned int thickness)
2244 {
2246  if (thickness == 1)
2247  thickness = 0;
2248 
2249  m_impl->displayDotLine(ip1, ip2, color, thickness, m_scale);
2250  }
2251  else {
2252  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2253  }
2254 }
2255 
2262 void vpDisplayX::displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
2263  unsigned int thickness)
2264 {
2266  if (thickness == 1)
2267  thickness = 0;
2268  m_impl->displayLine(ip1, ip2, color, thickness, m_scale);
2269  }
2270  else {
2271  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2272  }
2273 }
2274 
2281 void vpDisplayX::displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness)
2282 {
2284  m_impl->displayPoint(ip, color, thickness, m_scale);
2285  }
2286  else {
2287  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2288  }
2289 }
2290 
2304 void vpDisplayX::displayRectangle(const vpImagePoint &topLeft, unsigned int w, unsigned int h, const vpColor &color,
2305  bool fill, unsigned int thickness)
2306 {
2308  if (thickness == 1)
2309  thickness = 0;
2310 
2311  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
2312  }
2313  else {
2314  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2315  }
2316 }
2317 
2330 void vpDisplayX::displayRectangle(const vpImagePoint &topLeft, const vpImagePoint &bottomRight, const vpColor &color,
2331  bool fill, unsigned int thickness)
2332 {
2334  if (thickness == 1)
2335  thickness = 0;
2336 
2337  unsigned int w = static_cast<unsigned int>(vpMath::round(bottomRight.get_u() - topLeft.get_u()));
2338  unsigned int h = static_cast<unsigned int>(vpMath::round(bottomRight.get_v() - topLeft.get_v()));
2339 
2340  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
2341  }
2342  else {
2343  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2344  }
2345 }
2346 
2359 void vpDisplayX::displayRectangle(const vpRect &rectangle, const vpColor &color, bool fill, unsigned int thickness)
2360 {
2362  if (thickness == 1)
2363  thickness = 0;
2364  vpImagePoint topLeft = rectangle.getTopLeft();
2365  unsigned int w = static_cast<unsigned int>(vpMath::round(rectangle.getWidth()));
2366  unsigned int h = static_cast<unsigned int>(vpMath::round(rectangle.getHeight()));
2367  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
2368  }
2369  else {
2370  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2371  }
2372 }
2373 
2389 bool vpDisplayX::getClick(bool blocking)
2390 {
2391  bool ret = false;
2392 
2394  vpImagePoint ip;
2396  ret = m_impl->getClick(ip, button, blocking, m_scale);
2397  }
2398  else {
2399  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2400  }
2401  return ret;
2402 }
2403 
2419 bool vpDisplayX::getClick(vpImagePoint &ip, bool blocking)
2420 {
2421  bool ret = false;
2422 
2425  ret = m_impl->getClick(ip, button, blocking, m_scale);
2426  }
2427  else {
2428  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2429  }
2430  return ret;
2431 }
2432 
2453 {
2454  bool ret = false;
2455 
2457  ret = m_impl->getClick(ip, button, blocking, m_scale);
2458  }
2459  else {
2460  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2461  }
2462  return ret;
2463 }
2464 
2489 {
2490  bool ret = false;
2491 
2493  ret = m_impl->getClickUp(ip, button, blocking, m_scale);
2494  }
2495  else {
2496  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2497  }
2498  return ret;
2499 }
2500 
2501 /*
2502  Gets the displayed image (including the overlay plane)
2503  and returns an RGBa image. If a scale factor is set using setScale(), the
2504  size of the image is the size of the downscaled image.
2505 
2506  \param I : Image to get.
2507 */
2509 {
2511  m_impl->getImage(I, m_width, m_height);
2512  }
2513  else {
2514  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2515  }
2516 }
2517 
2521 unsigned int vpDisplayX::getScreenDepth() { return m_impl->getScreenDepth(); }
2522 
2527 void vpDisplayX::getScreenSize(unsigned int &w, unsigned int &h) { m_impl->getScreenSize(w, h); }
2528 
2533 {
2534  unsigned int width, height;
2535  getScreenSize(width, height);
2536  return width;
2537 }
2538 
2543 {
2544  unsigned int width, height;
2545  getScreenSize(width, height);
2546  return height;
2547 }
2548 
2569 bool vpDisplayX::getKeyboardEvent(bool blocking)
2570 {
2571  bool ret = false;
2572 
2574  ret = m_impl->getKeyboardEvent(blocking);
2575  }
2576  else {
2577  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2578  }
2579  return ret;
2580 }
2581 
2605 bool vpDisplayX::getKeyboardEvent(std::string &key, bool blocking)
2606 {
2607  bool ret = false;
2609  ret = m_impl->getKeyboardEvent(key, blocking);
2610  }
2611  else {
2612  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2613  }
2614  return ret;
2615 }
2629 {
2630 
2631  bool ret = false;
2633  ret = m_impl->getPointerMotionEvent(ip, m_scale);
2634  }
2635  else {
2636  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2637  }
2638  return ret;
2639 }
2640 
2652 {
2653  bool ret = false;
2655  ret = m_impl->getPointerPosition(ip, m_scale);
2656  }
2657  else {
2658  throw(vpDisplayException(vpDisplayException::notInitializedError, "X not initialized"));
2659  }
2660  return ret;
2661 }
2662 
2663 #elif !defined(VISP_BUILD_SHARED_LIBS)
2664 // Work around to avoid warning: libvisp_core.a(vpDisplayX.cpp.o) has no symbols
2665 void dummy_vpDisplayX() { };
2666 #endif
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:152
static const vpColor white
Definition: vpColor.h:206
vpColorIdentifier id
Definition: vpColor.h:200
static const vpColor red
Definition: vpColor.h:211
static const vpColor darkGray
Definition: vpColor.h:209
static const vpColor black
Definition: vpColor.h:205
static const vpColor cyan
Definition: vpColor.h:220
static const vpColor orange
Definition: vpColor.h:221
static const vpColor darkRed
Definition: vpColor.h:212
static const vpColor blue
Definition: vpColor.h:217
static const vpColor lightGray
Definition: vpColor.h:207
static const vpColor lightBlue
Definition: vpColor.h:216
static const vpColor darkGreen
Definition: vpColor.h:215
static const vpColor darkBlue
Definition: vpColor.h:218
static const vpColor purple
Definition: vpColor.h:222
static const vpColor lightGreen
Definition: vpColor.h:213
static const vpColor yellow
Definition: vpColor.h:219
@ id_lightBlue
Definition: vpColor.h:178
@ id_yellow
Definition: vpColor.h:184
@ id_darkGray
Definition: vpColor.h:164
@ id_green
Definition: vpColor.h:174
@ id_darkRed
Definition: vpColor.h:170
@ id_lightGray
Definition: vpColor.h:160
@ id_red
Definition: vpColor.h:168
@ id_lightRed
Definition: vpColor.h:166
@ id_white
Definition: vpColor.h:158
@ id_black
Definition: vpColor.h:156
@ id_blue
Definition: vpColor.h:180
@ id_darkGreen
Definition: vpColor.h:176
@ id_gray
Definition: vpColor.h:162
@ id_lightGreen
Definition: vpColor.h:172
@ id_purple
Definition: vpColor.h:190
@ id_orange
Definition: vpColor.h:188
@ id_cyan
Definition: vpColor.h:186
@ id_darkBlue
Definition: vpColor.h:182
@ id_unknown
Definition: vpColor.h:193
static const vpColor lightRed
Definition: vpColor.h:210
static const vpColor green
Definition: vpColor.h:214
static const vpColor gray
Definition: vpColor.h:208
Error that can be emitted by the vpDisplay class and its derivatives.
@ connexionError
Connection error.
@ colorAllocError
Color allocation error.
@ cannotOpenWindowError
Unable to open display window.
@ notInitializedError
Display not initialized.
@ XWindowsError
XWindow error.
@ depthNotSupportedError
Color depth not supported.
void displayImage(const vpImage< unsigned char > &I) vp_override
unsigned int getScreenDepth()
bool getClick(bool blocking=true) vp_override
void setTitle(const std::string &title) vp_override
void setWindowPosition(int win_x, int win_y) vp_override
bool getClickUp(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking=true) vp_override
void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1) vp_override
void displayText(const vpImagePoint &ip, const std::string &text, const vpColor &color=vpColor::green) vp_override
bool getPointerPosition(vpImagePoint &ip) vp_override
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) vp_override
void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1) vp_override
void displayImageROI(const vpImage< unsigned char > &I, const vpImagePoint &iP, unsigned int width, unsigned int height) vp_override
void clearDisplay(const vpColor &color=vpColor::white) vp_override
void flushDisplayROI(const vpImagePoint &iP, unsigned int width, unsigned int height) vp_override
void getImage(vpImage< vpRGBa > &I) vp_override
Get the window pixmap and put it in vpRGBa image.
void getScreenSize(unsigned int &width, unsigned int &height) vp_override
bool getKeyboardEvent(bool blocking=true) vp_override
bool getPointerMotionEvent(vpImagePoint &ip) vp_override
void displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1) vp_override
void setFont(const std::string &font) vp_override
void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1) vp_override
void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1) vp_override
void init(vpImage< unsigned char > &I, int win_x=-1, int win_y=-1, const std::string &win_title="") vp_override
unsigned int getScreenWidth() vp_override
void displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1) vp_override
void closeDisplay() vp_override
unsigned int getScreenHeight() vp_override
void flushDisplay() vp_override
virtual ~vpDisplayX() vp_override
Class that defines generic functionalities for display.
Definition: vpDisplay.h:173
unsigned int m_height
Definition: vpDisplay.h:212
vpScaleType m_scaleType
Definition: vpDisplay.h:215
unsigned int m_width
Definition: vpDisplay.h:211
static void display(const vpImage< unsigned char > &I)
int m_windowXPosition
display position
Definition: vpDisplay.h:208
std::string m_title
Definition: vpDisplay.h:213
int m_windowYPosition
display position
Definition: vpDisplay.h:210
unsigned int m_scale
Definition: vpDisplay.h:214
bool m_displayHasBeenInitialized
display has been initialized
Definition: vpDisplay.h:206
void setScale(vpScaleType scaleType, unsigned int width, unsigned int height)
Definition: vpDisplay.cpp:256
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
void set_j(double jj)
Definition: vpImagePoint.h:304
double get_j() const
Definition: vpImagePoint.h:125
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
void set_i(double ii)
Definition: vpImagePoint.h:293
double get_u() const
Definition: vpImagePoint.h:136
void set_u(double u)
Definition: vpImagePoint.h:330
void set_v(double v)
Definition: vpImagePoint.h:341
double get_i() const
Definition: vpImagePoint.h:114
double get_v() const
Definition: vpImagePoint.h:147
unsigned int getWidth() const
Definition: vpImage.h:245
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:783
Type * bitmap
points toward the bitmap
Definition: vpImage.h:139
unsigned int getHeight() const
Definition: vpImage.h:184
vpDisplay * display
Definition: vpImage.h:140
static double sqr(double x)
Definition: vpMath.h:201
static int round(double x)
Definition: vpMath.h:403
Definition: vpRGBa.h:61
unsigned char B
Blue component.
Definition: vpRGBa.h:139
unsigned char R
Red component.
Definition: vpRGBa.h:137
unsigned char G
Green component.
Definition: vpRGBa.h:138
@ alpha_default
Definition: vpRGBa.h:63
unsigned char A
Additionnal component.
Definition: vpRGBa.h:140
Defines a rectangle in the plane.
Definition: vpRect.h:76
double getWidth() const
Definition: vpRect.h:224
vpImagePoint getTopLeft() const
Definition: vpRect.h:196
double getHeight() const
Definition: vpRect.h:163
#define vpTRACE
Definition: vpDebug.h:405
#define vpERROR_TRACE
Definition: vpDebug.h:382