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  * Simulator based on Coin3d.
33  *
34  * Authors:
35  * Eric Marchand
36  * Anthony Saunier
37  *
38  *****************************************************************************/
39 /*!
40   \file vpSimulator.cpp
41   \brief Implementation of a simulator based on Coin3d (www.coin3d.org).
42   The simulator uses the vpViewer class.
43 */
44 
45 #include <visp3/core/vpConfig.h>
46 
47 #ifdef VISP_HAVE_COIN3D_AND_GUI
48 
49 #include <visp3/ar/vpSimulator.h>
50 #include <visp3/core/vpTime.h>
51 
52 #include <visp3/core/vpImage.h>
53 
54 #ifdef VISP_HAVE_MODULE_IO
55 #include <visp3/io/vpImageIo.h>
56 #endif
57 
58 /* Objets OIV. */
59 #include <Inventor/nodes/SoCone.h>           /* Objet cone.                            */
60 #include <Inventor/nodes/SoCoordinate3.h>    /* Liste de points.                */
61 #include <Inventor/nodes/SoCylinder.h>       /* Objet cylindre.                    */
62 #include <Inventor/nodes/SoIndexedFaceSet.h> /* Liste de face.               */
63 #include <Inventor/nodes/SoPointLight.h>     /* Objet lumiere ponctuelle.        */
64 #include <Inventor/nodes/SoRotationXYZ.h>    /* Transfo rotation simple.       */
65 #include <Inventor/nodes/SoScale.h>          /* Trasnfo mise a l'echelle.             */
66 #include <Inventor/nodes/SoTranslation.h>    /* Trasnfo translation.            */
67 
68 #include <Inventor/actions/SoWriteAction.h>
69 #include <Inventor/nodes/SoDirectionalLight.h> /* Objet lumiere directionnelle*/
70 #include <Inventor/nodes/SoDrawStyle.h>        /* Style de rendu.                  */
71 #include <Inventor/nodes/SoEnvironment.h>      /* Eclairage ambiant.              */
72 #include <Inventor/nodes/SoGroup.h>            /* Groupement de noeuds (sans separation)*/
73 #include <Inventor/nodes/SoMaterial.h>         /* Matiere (couleur) des objets.     */
74 
75 // Positions of all of the vertices:
76 //
77 static float pyramidVertexes[5][3] = {{0.33f, 0.33f, 0.f},
78                                       {-0.33f, 0.33f, 0.f},
79                                       {-0.33f, -0.33f, 0.f},
80                                       {0.33f, -0.33f, 0.f},
81 
82                                       {0.f, 0.f, -1.0f}};
83 
84 static int32_t pyramidFaces[] = {
85     0,
86     1,
87     2,
88     3,
89     SO_END_FACE_INDEX, // top face
90 
91     0,
92     1,
93     4,
94     SO_END_FACE_INDEX, // 4 faces about top
95     1,
96     2,
97     4,
98     SO_END_FACE_INDEX,
99     2,
100     3,
101     4,
102     SO_END_FACE_INDEX,
103     3,
104     0,
105     4,
106     SO_END_FACE_INDEX,
107 };
108 
109 // Routine to create a scene graph representing a dodecahedron
makePyramide()110 SoSeparator *makePyramide()
111 {
112   SoSeparator *result = new SoSeparator;
113   result->ref();
114 
115   // Define coordinates for vertices
116   SoCoordinate3 *myCoords = new SoCoordinate3;
117   myCoords->point.setValues(0, 5, pyramidVertexes);
118   result->addChild(myCoords);
119 
120   // Define the IndexedFaceSet, with indices into the vertices:
121   SoIndexedFaceSet *myFaceSet = new SoIndexedFaceSet;
122   myFaceSet->coordIndex.setValues(0, 21, (const int32_t *)pyramidFaces);
123   result->addChild(myFaceSet);
124 
125   result->unrefNoDelete();
126   return result;
127 }
128 
129 /* Cree une fleche composee d'un cylindre et d'un cone.
130  * La fleche a une hauteur total de <longueur>, dont
131  * <proportionFleche>% pour la fleche. Le rayon du cylindre
132  * est <radius>, et celui de la fleche <radius> * 5.
133  * La fleche est oriente selon l'axe Y.
134  */
createArrow(float longueur,float proportionFleche,float radius)135 static SoSeparator *createArrow(float longueur, float proportionFleche, float radius)
136 {
137   SoSeparator *fleche = new SoSeparator;
138   fleche->ref();
139 
140   SoTranslation *poseCylindre = new SoTranslation;
141   SoCylinder *line = new SoCylinder;
142   SoTranslation *posePointe = new SoTranslation;
143   SoCone *pointe = new SoCone;
144 
145   float l_cylindre = longueur * (1 - proportionFleche);
146   float l_cone = longueur * proportionFleche;
147   float radius_cylindre = radius;
148   float radius_cone = radius * 5;
149 
150   line->radius.setValue(radius_cylindre);
151   line->height.setValue(l_cylindre);
152 
153   poseCylindre->translation.setValue(0, l_cylindre / 2, 0);
154   posePointe->translation.setValue(0.0, l_cylindre / 2 + l_cone / 2, 0);
155 
156   pointe->bottomRadius.setValue(radius_cone);
157   pointe->height.setValue(l_cone);
158 
159   fleche->addChild(poseCylindre);
160   fleche->addChild(line);
161   fleche->addChild(posePointe);
162   fleche->addChild(pointe);
163 
164   return fleche;
165 }
166 
167 /*
168   Cree un objet repere dans un noeud separator, et le renvoie.
169   \return          : code d'erreur, SIMU_CODE_OK si tout s'est bien passe.
170 */
171 #define LONGUEUR_FLECHE 1.0f
172 #define RAYON_FLECHE 0.002f
173 #define PROPORTION_FLECHE 0.1f
174 
createFrame(float longueurFleche=LONGUEUR_FLECHE,float proportionFleche=PROPORTION_FLECHE,float radiusFleche=RAYON_FLECHE)175 SoSeparator *createFrame(float longueurFleche = LONGUEUR_FLECHE, float proportionFleche = PROPORTION_FLECHE,
176                          float radiusFleche = RAYON_FLECHE)
177 {
178   vpDEBUG_TRACE(15, "# Entree.");
179 
180   SoSeparator *frame = new SoSeparator;
181   frame->ref();
182 
183   SoRotationXYZ *rotationY_X = new SoRotationXYZ;
184   rotationY_X->axis = SoRotationXYZ::Z;
185   rotationY_X->angle.setValue((float)(-M_PI / 2));
186 
187   SoRotationXYZ *rotationX_Y = new SoRotationXYZ;
188   rotationX_Y->axis = SoRotationXYZ::Z;
189   rotationX_Y->angle.setValue((float)(M_PI / 2));
190 
191   SoRotationXYZ *rotationY_Z = new SoRotationXYZ;
192   rotationY_Z->axis = SoRotationXYZ::X;
193   rotationY_Z->angle.setValue((float)(M_PI / 2));
194 
195   SoMaterial *rouge = new SoMaterial;
196   rouge->diffuseColor.setValue(1.0, 0.0, 0.0);
197   rouge->emissiveColor.setValue(0.5, 0.0, 0.0);
198 
199   SoMaterial *vert = new SoMaterial;
200   vert->diffuseColor.setValue(0.0, 1.0, 0.0);
201   vert->emissiveColor.setValue(0.0, 0.5, 0.0);
202 
203   SoMaterial *bleu = new SoMaterial;
204   bleu->diffuseColor.setValue(0.0, 0.0, 1.0);
205   bleu->emissiveColor.setValue(0.0, 0.0, 0.5);
206 
207   SoSeparator *fleche = createArrow(longueurFleche, proportionFleche, radiusFleche);
208 
209   frame->addChild(rouge);
210   frame->addChild(rotationY_X);
211   frame->addChild(fleche);
212   frame->addChild(vert);
213   frame->addChild(rotationX_Y);
214   frame->addChild(fleche);
215   frame->addChild(bleu);
216   frame->addChild(rotationY_Z);
217   frame->addChild(fleche);
218 
219   frame->unrefNoDelete();
220 
221   vpDEBUG_TRACE(15, "# Sortie.");
222   return frame;
223 }
224 
createCameraObject(float zoomFactor=1.0)225 SoSeparator *createCameraObject(float zoomFactor = 1.0)
226 {
227   vpDEBUG_TRACE(15, "# Entree.");
228 
229   SoSeparator *cam = new SoSeparator;
230   cam->ref();
231 
232   SoMaterial *myMaterial = new SoMaterial;
233   myMaterial->diffuseColor.setValue(1.0, 0.0, 0.0);
234   myMaterial->emissiveColor.setValue(0.5, 0.0, 0.0);
235 
236   SoScale *taille = new SoScale;
237   {
238     float zoom = 0.1f * zoomFactor;
239     taille->scaleFactor.setValue(zoom, zoom, zoom);
240   }
241 
242   SoMaterial *couleurBlanc = new SoMaterial;
243   couleurBlanc->diffuseColor.setValue(1.0, 1.0, 1.0);
244   couleurBlanc->emissiveColor.setValue(1.0, 1.0, 1.0);
245   SoDrawStyle *filDeFer = new SoDrawStyle;
246   filDeFer->style.setValue(SoDrawStyle::LINES);
247   filDeFer->lineWidth.setValue(1);
248 
249   SoSeparator *cone = new SoSeparator;
250   cone->ref();
251   cone->addChild(makePyramide());
252   cone->addChild(couleurBlanc);
253   cone->addChild(filDeFer);
254   cone->addChild(makePyramide());
255   cone->unrefNoDelete();
256 
257   cam->addChild(myMaterial);
258   cam->addChild(taille);
259   cam->addChild(cone);
260   cam->addChild(createFrame(2.0f, 0.1f, 0.01f));
261 
262   //  cam->unref() ;
263   vpDEBUG_TRACE(15, "# Sortie.");
264   return cam;
265 }
266 
267 //--------------------------------------------------------------
init()268 void vpSimulator::init()
269 {
270   internal_width = 200;
271   internal_height = 200;
272   external_width = 200;
273   external_height = 200;
274 
275   mainWindowInitialized = false;
276   internalView = NULL;
277   externalView = NULL;
278   image_background = NULL;
279 
280   zoomFactor = 1;
281   cameraPositionInitialized = false;
282 
283   // write image process
284   realtime = NULL;
285   offScreenRenderer = NULL;
286   bufferView = NULL;
287   get = 1;
288   typeImage = grayImage;
289   mainThread = NULL;
290   scene = NULL;
291   internalRoot = NULL;
292   externalRoot = NULL;
293   internalCamera = NULL;
294   externalCamera = NULL;
295   internalCameraPosition = NULL;
296   extrenalCameraPosition = NULL;
297   internalCameraObject = NULL;
298 #if defined(VISP_HAVE_SOWIN)
299 // mainWindow = ?;
300 #elif defined(VISP_HAVE_SOQT)
301   mainWindow = NULL;
302 #elif defined(VISP_HAVE_SOXT)
303 // mainWindow = ?;
304 #endif
305 }
kill()306 void vpSimulator::kill()
307 {
308   if (internalView != NULL) {
309     delete internalView;
310     internalView = NULL;
311   }
312   if (externalView != NULL) {
313     delete externalView;
314     externalView = NULL;
315   }
316   if (bufferView != NULL) {
317     delete[] bufferView;
318     bufferView = NULL;
319   }
320   if (image_background != NULL) {
321     free(image_background);
322     image_background = NULL;
323   }
324 }
325 
vpSimulator()326 vpSimulator::vpSimulator()
327   :
328 #if defined(VISP_HAVE_SOWIN)
329     mainWindow(),
330 #elif defined(VISP_HAVE_SOQT)
331     mainWindow(NULL),
332 #elif defined(VISP_HAVE_SOXT)
333     mainWindow(),
334 #endif
335     mainWindowInitialized(false), typeImage(vpSimulator::grayImage), image_background(NULL), internalView(NULL),
336     externalView(NULL), mainThread(NULL), internal_width(0), internal_height(0), external_width(0), external_height(0),
337     scene(NULL), internalRoot(NULL), externalRoot(NULL), internalCamera(NULL), externalCamera(NULL),
338     internalCameraPosition(NULL), extrenalCameraPosition(NULL), internalCameraObject(NULL), zoomFactor(0.),
339     cameraPositionInitialized(false), cMf(), internalCameraParameters(), externalCameraParameters(), realtime(NULL),
340     offScreenRenderer(NULL), bufferView(NULL), get(0)
341 {
342   vpSimulator::init();
343 }
344 
~vpSimulator()345 vpSimulator::~vpSimulator() { vpSimulator::kill(); }
346 
initSoApplication()347 void vpSimulator::initSoApplication()
348 {
349   mainWindow = vpViewer::init("");
350   mainWindowInitialized = true;
351 }
352 
initSceneGraph()353 void vpSimulator::initSceneGraph()
354 {
355   this->scene = new SoSeparator;
356   this->internalRoot = new SoSeparator;
357   this->externalRoot = new SoSeparator;
358 
359   this->scene->ref();
360   this->internalRoot->ref();
361   this->externalRoot->ref();
362 
363   // define the camera SoPerspectiveCamera
364   this->internalCamera = new SoPerspectiveCamera;
365   this->externalCamera = new SoPerspectiveCamera;
366 
367   this->internalCameraPosition = new SoTransform;
368   this->internalCameraObject = createCameraObject(zoomFactor);
369 
370   internalCamera->farDistance.setValue(100);
371   internalCamera->nearDistance.setValue(0.0001f);
372 
373   // link between camera and internal root
374   this->internalRoot->addChild(this->internalCamera);
375   this->internalRoot->addChild(this->scene);
376 
377   this->externalRoot->addChild(this->externalCamera);
378   this->externalRoot->addChild(this->scene);
379 
380   SoSeparator *camera = new SoSeparator;
381   camera->ref();
382   camera->addChild(this->internalCameraPosition);
383   camera->addChild(this->internalCameraObject);
384   this->externalRoot->addChild(camera);
385 
386   // this->externalRoot->addChild (internalCameraPosition);
387   //  this->externalRoot->addChild (internalCameraObject);
388   SoCube *cube = new SoCube;
389   cube->width = 0.01f;
390   cube->depth = 0.01f;
391   cube->height = 0.01f;
392 
393   this->externalRoot->addChild(cube);
394 
395   if (realtime == NULL) {
396 
397     SoDB::enableRealTimeSensor(FALSE);
398     SoSceneManager::enableRealTimeUpdate(FALSE);
399     realtime = (SbTime *)SoDB::getGlobalField("realTime");
400     realtime->setValue(0.0);
401   }
402 }
403 
404 /*!
405   \brief Define the zoom factor used to define the size of the objects (frame,
406   camera, ...)
407 
408   \param zoom: zoom factor of the objects. By default, 1.
409 */
setZoomFactor(float zoom)410 void vpSimulator::setZoomFactor(float zoom)
411 {
412   zoomFactor = zoom;
413   static bool firstTime = true;
414   if (firstTime) {
415     SoScale *taille = new SoScale;
416     taille->scaleFactor.setValue(zoomFactor, zoomFactor, zoomFactor);
417     this->scene->addChild(taille);
418     firstTime = false;
419   } else {
420     SoScale *taille = (SoScale *)this->scene->getChild(0);
421     taille->scaleFactor.setValue(zoomFactor, zoomFactor, zoomFactor);
422   }
423 }
424 
425 /*!
426   \brief Change the zoom factor associated to the child given by index.
427   In order to create multiple zoom factor for multiple object to display,
428   objects loaded the load() function, you have to know the index of the scale
429   object associated to.
430 
431   Usually, if you define the main zoom factor (for example for the frames) and
432   then load two differents objects, You can change the zoom factor of all the
433   objects using: changeZoomFactor(newZoom, 0)
434 
435   If you want to change the zoom factor of the first object, use
436   changeZoomFactor(newZoom, 1)
437 
438   And for the second object, use changeZoomFactor(newZoom, 3)
439 
440   \param zoomFactor : the new zoom use to specify the apparent size of the
441   object \param index : the index of the Scale object to modify (see comments)
442 */
changeZoomFactor(float zoomFactor,int index)443 void vpSimulator::changeZoomFactor(float zoomFactor, int index)
444 {
445   SoScale *taille = (SoScale *)this->scene->getChild(index);
446   taille->scaleFactor.setValue(zoomFactor, zoomFactor, zoomFactor);
447   //  this->setZoomFactor(zoomFactor);
448 }
449 
initInternalViewer(unsigned int width,unsigned int height)450 void vpSimulator::initInternalViewer(unsigned int width, unsigned int height)
451 {
452   internal_width = width;
453   internal_height = height;
454 
455   if (mainWindowInitialized == false) {
456     initSoApplication();
457     initSceneGraph();
458   }
459 
460   internalView = new vpViewer(mainWindow, this, vpViewer::internalView);
461 
462   // set the scene to render from this view
463   internalView->setSceneGraph(internalRoot);
464 
465   // set the title
466   internalView->setTitle("Internal camera view");
467 
468   // If the view mode is on, user events will be caught and used to influence
469   // the camera position / orientation. in this viewer we do not want that,
470   // we set it to false
471   internalView->setViewing(false);
472 
473   // Turn the viewer decorations
474   internalView->setDecoration(false);
475 
476   internalView->resize((int)width, (int)height, true);
477 
478   // open the window
479   internalView->show();
480 
481   bufferView = new unsigned char[3 * width * height];
482 }
483 
initExternalViewer(unsigned int width,unsigned int height)484 void vpSimulator::initExternalViewer(unsigned int width, unsigned int height)
485 {
486 
487   external_width = width;
488   external_height = height;
489 
490   if (mainWindowInitialized == false) {
491     initSoApplication();
492     initSceneGraph();
493   }
494 
495   externalView = new vpViewer(mainWindow, this, vpViewer::externalView);
496 
497   // set the scene to render this view
498   externalView->setSceneGraph(externalRoot);
499 
500   // set the title
501   externalView->setTitle("External View");
502   externalView->resize((int)width, (int)height, false);
503   // the goal here is to see all the scene and not to determine
504   // a manual viewpoint
505   externalView->viewAll();
506 
507   // open the window
508   externalView->show();
509 }
510 
setInternalCameraParameters(vpCameraParameters & _cam)511 void vpSimulator::setInternalCameraParameters(vpCameraParameters &_cam)
512 {
513   internalCameraParameters = _cam;
514 
515   float px = (float)_cam.get_px();
516   float py = (float)_cam.get_py();
517   float v = internal_height / (2.f * py);
518 
519   internalCamera->ref();
520   internalCamera->heightAngle = 2 * atan(v);
521   internalCamera->aspectRatio = (internal_width / internal_height) * (px / py);
522   internalCamera->nearDistance = 0.001f;
523 
524   internalCamera->farDistance = 1000;
525   internalCamera->unrefNoDelete();
526 }
527 
setExternalCameraParameters(vpCameraParameters & _cam)528 void vpSimulator::setExternalCameraParameters(vpCameraParameters &_cam)
529 {
530   //   SoPerspectiveCamera *camera ;
531   //   camera  = (SoPerspectiveCamera *)this->externalView->getCamera() ;
532   externalCameraParameters = _cam;
533 
534   float px = (float)_cam.get_px();
535   float py = (float)_cam.get_py();
536   float v = external_height / (2 * py);
537 
538   externalCamera->ref();
539   externalCamera->heightAngle = 2 * atan(v);
540   externalCamera->aspectRatio = (external_width / external_height) * (px / py);
541   externalCamera->nearDistance = 0.001f;
542   externalCamera->farDistance = 1000;
543   externalCamera->unrefNoDelete();
544 }
545 
getExternalCameraPosition(vpHomogeneousMatrix & cMf)546 void vpSimulator::getExternalCameraPosition(vpHomogeneousMatrix &cMf)
547 {
548   /*  SoCamera *camera ;
549     camera  = this->externalView->getCamera() ;*/
550   SoSFVec3f position = externalCamera->position;
551 
552   // get the rotation
553   SoSFRotation orientation = externalCamera->orientation;
554   SbVec3f axis;
555   float angle;
556   orientation.getValue(axis, angle);
557   SbRotation rotation(axis, angle);
558 
559   // get the translation
560   SbVec3f t;
561   t = position.getValue();
562 
563   SbMatrix matrix;
564   matrix.setRotate(rotation);
565 
566   vpHomogeneousMatrix fMc;
567   SbMatrix rotX;
568   rotX.setRotate(SbRotation(SbVec3f(1.0f, 0.0f, 0.0f), (float)M_PI));
569   matrix.multLeft(rotX);
570   for (unsigned int i = 0; i < 4; i++)
571     for (unsigned int j = 0; j < 4; j++)
572       fMc[j][i] = matrix[(int)i][(int)j];
573   fMc[0][3] = t[0];
574   fMc[1][3] = t[1];
575   fMc[2][3] = t[2];
576 
577   cMf = fMc.inverse();
578 }
579 
setCameraPosition(vpHomogeneousMatrix & _cMf)580 void vpSimulator::setCameraPosition(vpHomogeneousMatrix &_cMf)
581 {
582   cameraPositionInitialized = true;
583   cMf = _cMf;
584 }
moveInternalCamera(vpHomogeneousMatrix & cMf)585 void vpSimulator::moveInternalCamera(vpHomogeneousMatrix &cMf)
586 {
587 
588   SbMatrix matrix;
589   SbRotation rotCam;
590   SbMatrix rotX;
591   rotX.setRotate(SbRotation(SbVec3f(1.0f, 0.0f, 0.0f), (float)M_PI));
592   for (unsigned int i = 0; i < 4; i++)
593     for (unsigned int j = 0; j < 4; j++)
594       matrix[(int)j][(int)i] = (float)cMf[i][j];
595 
596   matrix = matrix.inverse();
597   matrix.multLeft(rotX);
598   rotCam.setValue(matrix);
599 
600   internalCamera->ref();
601   internalCamera->orientation.setValue(rotCam);
602   internalCamera->position.setValue(matrix[3][0], matrix[3][1], matrix[3][2]);
603   internalCamera->unref();
604 
605   rotX.setRotate(SbRotation(SbVec3f(-1.0f, 0.0f, 0.0f), (float)M_PI));
606   matrix.multLeft(rotX);
607   rotCam.setValue(matrix);
608   internalCameraPosition->ref();
609   internalCameraPosition->rotation.setValue(rotCam);
610   internalCameraPosition->translation.setValue(matrix[3][0], matrix[3][1], matrix[3][2]);
611   internalCameraPosition->unref();
612 }
613 
614 /*!  this function MUST NOT be called from a thread where the vpSimulator and
615   its mainloop are not
616 */
redraw()617 void vpSimulator::redraw()
618 {
619 
620   //  if (this->cameraPositionInitialized==true)
621   {
622     if (this->externalView != NULL) {
623       this->externalView->render(); // call actualRedraw()
624       //      vpHomogeneousMatrix c ;
625       //      getExternalCameraPosition(c) ;
626     }
627     if (this->internalView != NULL) {
628       this->moveInternalCamera(this->cMf);
629       this->internalView->render(); // call actualRedraw()
630     }
631   }
632 }
633 
634 // This function is called 20 times each second.
timerSensorCallback(void * data,SoSensor *)635 static void timerSensorCallback(void *data, SoSensor *)
636 {
637   vpSimulator *simulator = (vpSimulator *)data;
638 
639   simulator->redraw();
640 }
641 
mainLoop()642 void vpSimulator::mainLoop()
643 {
644   if (mainWindowInitialized == false) {
645     vpERROR_TRACE("main window is not opened ");
646   }
647 
648   vpTime::wait(1000);
649 
650   // Timer sensor
651   SoTimerSensor *timer = new SoTimerSensor(timerSensorCallback, (void *)this);
652   timer->setInterval(0.01);
653   timer->schedule();
654   vpViewer::mainLoop();
655 }
656 
657 //-----------------------------------------------------------------
658 // scene stuff
659 //-----------------------------------------------------------------
660 
661 //! loading the virtual scene
load(const char * file_name)662 void vpSimulator::load(const char *file_name)
663 {
664 
665   SoInput input;
666   if (!input.openFile(file_name)) {
667     vpERROR_TRACE("Erreur cannot open file %s", file_name);
668   }
669 
670   SoSeparator *newscene = SoDB::readAll(&input);
671   newscene->ref();
672   if (newscene == NULL) {
673     vpERROR_TRACE("Error while reading %s", file_name);
674   }
675 
676   SoScale *taille = new SoScale;
677   taille->scaleFactor.setValue(zoomFactor, zoomFactor, zoomFactor);
678 
679   //  newscene->addChild(taille);
680 
681   //  std::cout << "this->scene->getNumChildren() = " <<
682   //  this->scene->getNumChildren() << std::endl;
683 
684   this->scene->addChild(taille);
685   this->scene->addChild(newscene);
686   newscene->unref();
687 }
688 
save(const char * name,bool binary)689 void vpSimulator::save(const char *name, bool binary)
690 {
691   // get a pointer to the object "name"
692   SoOutput output;
693   output.openFile(name);
694 
695   if (binary == true)
696     output.setBinary(TRUE);
697 
698   SoWriteAction writeAction(&output);
699   writeAction.apply(scene);
700   output.closeFile();
701 }
702 
703 /*!
704   Add the representation of a frame.
705   \param fMo : desired position of the frame
706   \param zoom : Zoom factor.
707 */
addFrame(const vpHomogeneousMatrix & fMo,float zoom)708 void vpSimulator::addFrame(const vpHomogeneousMatrix &fMo, float zoom)
709 {
710 
711   SoScale *taille = new SoScale;
712   taille->scaleFactor.setValue(zoom, zoom, zoom);
713 
714   SoSeparator *frame = new SoSeparator;
715   frame->ref();
716   frame->addChild(taille);
717   frame->addChild(createFrame(LONGUEUR_FLECHE * zoom, PROPORTION_FLECHE * zoom, RAYON_FLECHE * zoom));
718   this->addObject(frame, fMo, externalRoot);
719   // frame->unref();
720 }
721 
722 /*!
723   \brief Add the representation of the absolute frame
724 
725   \param zoom : Zoom factor.
726 */
addAbsoluteFrame(float zoom)727 void vpSimulator::addAbsoluteFrame(float zoom)
728 {
729   scene->addChild(createFrame(LONGUEUR_FLECHE * zoom, PROPORTION_FLECHE * zoom, RAYON_FLECHE * zoom));
730 }
731 
732 /*!
733   \brief Add a new object in the scene graph
734   \param iv_filename : name of.iv file to load
735   \param fMo       : position of the object wrt the reference frame
736 */
load(const char * iv_filename,const vpHomogeneousMatrix & fMo)737 void vpSimulator::load(const char *iv_filename, const vpHomogeneousMatrix &fMo)
738 {
739 
740   SoInput in;
741   SoSeparator *newObject;
742 
743   if (!in.openFile(iv_filename)) {
744     vpERROR_TRACE("Erreur lors de la lecture du fichier %s.", iv_filename);
745   }
746 
747   newObject = SoDB::readAll(&in);
748   if (NULL == newObject) {
749     vpERROR_TRACE("Problem reading data for file <%s>.", iv_filename);
750   }
751 
752   try {
753     this->addObject(newObject, fMo);
754   } catch (...) {
755     vpERROR_TRACE("Error adding object from file <%s> ", iv_filename);
756     throw;
757   }
758 }
759 
760 /*!
761   \brief Add a new object in the scene graph
762   \param newObject : pointer toward the new object
763   \param fMo       : position of the object wrt the reference frame
764 */
addObject(SoSeparator * newObject,const vpHomogeneousMatrix & fMo)765 void vpSimulator::addObject(SoSeparator *newObject, const vpHomogeneousMatrix &fMo)
766 {
767   try {
768     this->addObject(newObject, fMo, scene);
769   } catch (...) {
770     vpERROR_TRACE("Error adding object in scene graph ");
771     throw;
772   }
773 }
774 
775 /*!
776   \brief Add an object in a sub scene graph
777   \param object : pointer toward the new object
778   \param fMo    : position of the object wrt the reference frame
779   \param root : pointer toward the subscene graph
780 */
781 
addObject(SoSeparator * object,const vpHomogeneousMatrix & fMo,SoSeparator * root)782 void vpSimulator::addObject(SoSeparator *object, const vpHomogeneousMatrix &fMo, SoSeparator *root)
783 {
784 
785   bool identity = true;
786   for (unsigned int i = 0; i < 4; i++) {
787     for (unsigned int j = 0; j < 4; j++) {
788       if (i == j) {
789         if (fabs(fMo[i][j] - 1) > 1e-6)
790           identity = false;
791       } else {
792         if (fabs(fMo[i][j]) > 1e-6)
793           identity = false;
794       }
795     }
796   }
797 
798   if (identity == true) {
799     root->addChild(object);
800   } else {
801     SbMatrix matrix;
802     SbRotation rotation;
803     for (unsigned int i = 0; i < 4; i++)
804       for (unsigned int j = 0; j < 4; j++)
805         matrix[(int)j][(int)i] = (float)fMo[i][j];
806 
807     //  matrix= matrix.inverse();
808     rotation.setValue(matrix);
809 
810     SoTransform *displacement = new SoTransform;
811     SoSeparator *newNode = new SoSeparator;
812 
813     displacement->rotation.setValue(rotation);
814     displacement->translation.setValue(matrix[3][0], matrix[3][1], matrix[3][2]);
815 
816     root->addChild(newNode);
817     newNode->addChild(displacement);
818     newNode->addChild(object);
819   }
820 }
821 
822 //! init the main program thread
initApplication(void * (* start_routine)(void *))823 void vpSimulator::initApplication(void *(*start_routine)(void *))
824 {
825   // pthread_create (&mainThread, NULL, start_routine, (void *)this);
826   mainThread = SbThread::create(start_routine, (void *)this);
827 }
828 
829 /*!
830   Set the function used for the simulation loop and the data to pass to this
831   function. As the data are represented using a generic pointer, care should
832   be taken to ensure there is no memory corruption.
833 
834   \param start_routine : A pointer to the function used as a main simulation
835   loop for the simulation.
836   \param data : The data to pass to the main loop.
837 */
initApplication(void * (* start_routine)(void *),void * data)838 void vpSimulator::initApplication(void *(*start_routine)(void *), void *data)
839 {
840   mainThread = SbThread::create(start_routine, (void *)data);
841 }
842 
843 //! performed some initialization in the main program thread
844 //! should be locate at the beginning of the main program
initMainApplication()845 void vpSimulator::initMainApplication()
846 {
847   // pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL );
848   // pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
849   vpTime::wait(1000);
850 }
851 //! performed some thread destruction in the main program thread
852 //! should be locate at the end of the main program
closeMainApplication()853 void vpSimulator::closeMainApplication()
854 {
855   vpViewer::exitMainLoop();
856   // pthread_exit (NULL);
857 }
858 
859 /* Initialise le SoOffScreenRenderer si necessaire, puis realise le rendu.
860  * Quand la fonction rend la main, le buffer est pret et n'a plus qu'a etre
861  * enregistre ou passe a l'utilisateur.
862  * INPUT:
863  *   - vueInterne est vrai ssi il faut rendre la vue interne, faux ssi
864  * il faut rendre la vue externe.
865  * OUTPUT:
866  *   - width : largeur de l'image dans le buffer.
867  *   - height : hauteur de l'image dans le buffer.
868  */
offScreenRendering(vpSimulatorViewType view,int * width,int * height)869 void vpSimulator::offScreenRendering(vpSimulatorViewType view, int *width, int *height)
870 {
871 
872   SbVec2s size(320, 200);
873   SoNode *thisroot;
874 
875   {
876     if (view == vpSimulator::INTERNAL) {
877       size = this->internalView->getViewportRegion().getWindowSize();
878       thisroot = this->internalView->getSceneManager()->getSceneGraph();
879     } else {
880       size = this->externalView->getViewportRegion().getWindowSize();
881       thisroot = this->externalView->getSceneManager()->getSceneGraph();
882     }
883   }
884   SbViewportRegion myViewPort(size);
885 
886   // Creation du rendu si necessaire.
887   if (NULL == this->offScreenRenderer) {
888     // Init du SoOffscreenRenderer
889     this->offScreenRenderer = new SoOffscreenRenderer(myViewPort);
890   } else {
891     // Redefini le view port
892     this->offScreenRenderer->setViewportRegion(myViewPort);
893   }
894 
895   // Rendu offscreen
896   if (!this->offScreenRenderer->render(thisroot)) {
897     vpERROR_TRACE("La scene n'a pas pu etre rendue offscreen.");
898     delete this->offScreenRenderer;
899     this->offScreenRenderer = NULL;
900   } else {
901 
902     /*
903       if (view==vpSimulator::INTERNAL)
904       {
905       //Recopie du buffer contenant l'image, dans bufferView
906       int length = 3*size [0]*size[1];
907       delete [] bufferView;
908       bufferView = new unsigned char [length];
909       for(int i=0; i<length; i++)
910       {
911       bufferView[i] = this ->offScreenRenderer->getBuffer()[i];
912       }
913       }*/
914   }
915 
916   //  exit(1) ;
917   if (NULL != width) {
918     *width = size[0];
919   }
920   if (NULL != height) {
921     *height = size[1];
922   }
923 }
924 
925 /* Enregistre l'image de vue interne ou externe dans un fichier RGB.
926  * Effectue le rendu dans un buffer plutot qu'a l'ecran, puis sauvegarde
927  * ce buffer au format PS (copie directe).
928  * INPUT
929  *   - fileName: nom du fichier dans lequel placer le resultat.
930  * OUTPUT
931  *   - RETURN : Code d'erreur CODE_OK si tout s'est bien passe.
932  */
933 
934 #ifdef VISP_HAVE_MODULE_IO
write(const char * fileName)935 void vpSimulator::write(const char *fileName)
936 {
937 
938   while (get == 0) {
939     vpTRACE("%d ", get);
940   }
941   get = 2;
942   /*  FILE *fp = fopen(fileName, "w");
943       fprintf(fp,"P6 \n %d %d \n 255",internal_width,internal_height) ;
944       fwrite(bufferView, sizeof(unsigned char),
945      internal_width*internal_height*3, fp) ;*/
946   vpImage<vpRGBa> I(internal_height, internal_width);
947 
948   for (unsigned int i = 0; i < internal_height; i++)
949     for (unsigned int j = 0; j < internal_width; j++) {
950       unsigned char r, g, b;
951       unsigned int index = 3 * ((internal_height - i - 1) * internal_width + j);
952       r = *(bufferView + index);
953       g = *(bufferView + index + 1);
954       b = *(bufferView + index + 2);
955       I[i][j].R = r;
956       I[i][j].G = g;
957       I[i][j].B = b;
958     }
959   vpImageIo::write(I, fileName);
960   // fclose (fp);
961   get = 1;
962 }
963 #endif
964 
getSizeInternalView(int & width,int & height)965 void vpSimulator::getSizeInternalView(int &width, int &height)
966 {
967   SbVec2s size = this->internalView->getViewportRegion().getWindowSize();
968   width = size[0];
969   height = size[1];
970 }
971 
972 /*!
973   Make a copy of the current internal view
974   \param I : destination image
975  */
976 
getInternalImage(vpImage<vpRGBa> & I)977 void vpSimulator::getInternalImage(vpImage<vpRGBa> &I)
978 {
979   // while (get==0) {;}
980   get = 2;
981   I.resize(internal_height, internal_width);
982   vpImageConvert::RGBToRGBa(bufferView, (unsigned char *)I.bitmap, internal_width, internal_height, true);
983   get = 1;
984 }
985 
986 /*!
987   Make a copy of the current internal view
988   \param I : destination image
989  */
getInternalImage(vpImage<unsigned char> & I)990 void vpSimulator::getInternalImage(vpImage<unsigned char> &I)
991 {
992   // while (get==0) {;}
993   get = 2;
994   I.resize(internal_height, internal_width);
995   vpImageConvert::RGBToGrey(bufferView, I.bitmap, internal_width, internal_height, true);
996   get = 1;
997 }
998 
999 #elif !defined(VISP_BUILD_SHARED_LIBS)
1000 // Work arround to avoid warning: libvisp_ar.a(vpSimulator.cpp.o) has no
1001 // symbols
dummy_vpSimulator()1002 void dummy_vpSimulator(){};
1003 #endif
1004