1 /*--------------------------------------------------------------------------*/
2 /* ALBERTA:  an Adaptive multi Level finite element toolbox using           */
3 /*           Bisectioning refinement and Error control by Residual          */
4 /*           Techniques for scientific Applications                         */
5 /*                                                                          */
6 /* file: dxtools.c                                                          */
7 /*                                                                          */
8 /*                                                                          */
9 /* description: interface to IBM Data Explorer                              */
10 /*                                                                          */
11 /*--------------------------------------------------------------------------*/
12 /*                                                                          */
13 /*  authors:   Oliver Kriessl                                               */
14 /*             Institut fuer Mathematik                                     */
15 /*             Universitaet Augsburg                                        */
16 /*             Universitaetsstr. 14                                         */
17 /*             D-86159 Augsburg, Germany                                    */
18 /*                                                                          */
19 /*             Daniel Koester                                               */
20 /*             Institut fuer Mathematik                                     */
21 /*             Universitaet Augsburg                                        */
22 /*             Universitaetsstr. 14                                         */
23 /*             D-86159 Augsburg, Germany                                    */
24 /*                                                                          */
25 /*  http://www.mathematik.uni-freiburg.de/IAM/ALBERTA                       */
26 /*                                                                          */
27 /*  (c) by A. Schmidt and K.G. Siebert (1996-2005)                          */
28 /*  (c) by D. Koester and O.Kriessl    (2001-2005)                          */
29 /*                                                                          */
30 /* WARNING: The DX library is not thread-safe. We need to make              */
31 /* certain that the second thread started in open_dxtools_window() never    */
32 /* accesses DX functions concurrently with the main thread.                 */
33 /*                                                                          */
34 /*--------------------------------------------------------------------------*/
35 
36 #ifdef HAVE_CONFIG_H
37 # include "config.h" /* this is really needed here */
38 #endif
39 
40 #include "alberta_intern.h"
41 #include "alberta.h"
42 
43 #include <unistd.h>
44 #include <errno.h>
45 #include <Xm/Xm.h>
46 #include <Xm/Form.h>
47 #include <Xm/DrawingA.h>
48 #include <pthread.h>
49 
50 #define Screen dxScreen
51 #define String dxString
52 #define Object dxObject
53 
54 #undef PACKAGE
55 #undef PACKAGE_BUGREPORT
56 #undef PACKAGE_NAME
57 #undef PACKAGE_STRING
58 #undef PACKAGE_TARNAME
59 #undef PACKAGE_VERSION
60 #undef VERSION
61 
62 #include <dxconfig.h>
63 #include <dx/dx.h>
64 #undef String
65 #undef Screen
66 #undef Object
67 
68 /*--------------------------------------------------------------------------*/
69 /* Type definitions used for the dxtools.                                   */
70 /*--------------------------------------------------------------------------*/
71 
72 typedef enum {DXTOOLS_NONE, DXTOOLS_MESH, DXTOOLS_FEVECTOR} DXOBJECT_TYPE;
73 
74 #define DXTOOLS_MAX_WINDOWS 20
75 #define DXTOOLS_KEY_HELP               'h'
76 #define DXTOOLS_KEY_QUIT               'q'
77 #define DXTOOLS_KEY_BLOCK              'b'
78 #define DXTOOLS_KEY_PROJECTION         'p'
79 #define DXTOOLS_KEY_HARDWARE           'f'
80 #define DXTOOLS_KEY_LEGEND             'l'
81 #define DXTOOLS_KEY_VIDEO              'v'
82 #define DXTOOLS_KEY_RESET              'r'
83 #define DXTOOLS_KEY_WRITE              'w'
84 #define DXTOOLS_KEY_AXES               'a'
85 #define DXTOOLS_KEY_BOX                'k'
86 #define DXTOOLS_KEY_CUTPLANE           'c'
87 #define DXTOOLS_KEY_CUTPLANE_PLUS      '+'
88 #define DXTOOLS_KEY_CUTPLANE_MINUS     '-'
89 #define DXTOOLS_KEY_CUTPLANE_PPLUS     '>'
90 #define DXTOOLS_KEY_CUTPLANE_MMINUS    '<'
91 #define DXTOOLS_KEY_CUTPLANE_X         'x'
92 #define DXTOOLS_KEY_CUTPLANE_Y         'y'
93 #define DXTOOLS_KEY_CUTPLANE_Z         'z'
94 #define DXTOOLS_KEY_MIDDLE_BUTTON_MODE ' '
95 
96 
97 typedef struct dxtools_context DXTOOLS_CONTEXT;
98 
99 struct dxtools_window {
100   /* Pointer to the context */
101   DXTOOLS_CONTEXT *dxc;
102 
103   /* Internal number of this window */
104   int number;
105 
106   /* data for window layout */
107   char *title;
108   int width, height;
109   int offsetx, offsety;
110 
111   /* data of the drawing area */
112   int draw_width, draw_height;
113 
114   Widget me;
115   Window drawingarea;
116 
117   int use_hardware;
118   int use_perspective;
119   int use_legend;
120   int use_inverse_video;
121   int use_bounding_box;
122   int use_axes;
123   int use_cutplane;
124   int middle_button_mode;
125 
126   /* what is being displayed (mesh, vector, leaf data, etc.) */
127   int dim;
128   DXOBJECT_TYPE type;
129 
130   /* current window object for display */
131   dxObject displayobject;
132 
133   /* a colormap for displaying legends */
134   Field colormap;
135 
136   /* a camera object to store the initial view */
137   dxObject initial_camera;
138 
139   /* cutplane settings */
140   int cutplane_direction;
141   float cutplane_level;
142 
143   /* entries for communication from the main thread */
144   /* window contents should also be dumped to a file. */
145   int save_me;
146 
147   /* window contents need to be redrawn. */
148   int redraw_me;
149 
150   /* camera view should be reset. */
151   int reset_me;
152 
153   /* this window must be opened. */
154   int open_me;
155 
156   /* should this window be closed? */
157   int close_me;
158 
159 };
160 
161 
162 struct dxtools_context {
163   /* lock for thread_data */
164   pthread_mutex_t tlock;
165   /* Condition to signal readiness of windows to the main thread */
166   pthread_cond_t windows_ready;
167   /* Condition to block the main thread if desired */
168   pthread_cond_t block_context;
169 
170   /* wait for signal that windows are ready if this flag is set. */
171   int check_block_context;
172 
173   /* window list */
174   DXTOOLS_WINDOW *win[DXTOOLS_MAX_WINDOWS];
175 
176   /* number of open windows */
177   int n_open_windows;
178 
179   /* is the thread running? */
180   int thread_running;
181 
182   XtAppContext    app;
183   Widget          toplevel;
184 };
185 
186 
187 
188 
189 /*               code to override the DX                                    */
190 /*       standard UserInteractor. These functions are based on the DX file  */
191 /*              <prefix>/src/exec/dxmods/definter.c                         */
192 /*                                                                          */
193 /*              NOTE: Future versions of DX could break this code.          */
194 
195 #define N_USER_INTERACTORS 1
196 
197 static void *RPZInitMode(dxObject, int, int, int *);
198 static void  RPZEndMode(void *);
199 static void  RPZSetCamera(void *, float *, float *,
200 		       float *, int, float, float);
201 static int   RPZGetCamera(void *, float *, float *,
202 		       float *, int *, float *, float *);
203 static void  RPZSetRenderable(void *, dxObject);
204 static int   RPZGetRenderable(void *, dxObject *);
205 static void  RPZEventHandler(void *, DXEvent *);
206 
207 
208 static UserInteractor _userInteractionTable[N_USER_INTERACTORS];
209 
DXDefaultUserInteractors(int * n,void * t)210 int DXDefaultUserInteractors(int *n, void *t)
211 {
212     _userInteractionTable[0].InitMode      = RPZInitMode;
213     _userInteractionTable[0].EndMode       = RPZEndMode;
214     _userInteractionTable[0].SetCamera     = RPZSetCamera;
215     _userInteractionTable[0].GetCamera     = RPZGetCamera;
216     _userInteractionTable[0].SetRenderable = RPZSetRenderable;
217     _userInteractionTable[0].GetRenderable = RPZGetRenderable;
218     _userInteractionTable[0].EventHandler  = RPZEventHandler;
219 
220     *n = N_USER_INTERACTORS;
221     *(void **)t = (void *)_userInteractionTable;
222     return 1;
223 }
224 
225 /***** Control similar to GMV *****/
226 
227 static void StartStroke(void *, DXMouseEvent *);
228 static void RotateEndStroke(void *, DXMouseEvent *);
229 static void PanEndStroke(void *, DXMouseEvent *);
230 static void TiltEndStroke(void *, DXMouseEvent *);
231 static void ZoomEndStroke(void *, DXMouseEvent *);
232 
233 
234 typedef struct RPZData
235 {
236   dxObject args;	/* Interactor arguments		*/
237   int w, h;		/* Width and height of window 	*/
238   dxObject obj;		/* Current object		*/
239 
240   DXTOOLS_WINDOW *me; /* This window */
241 
242   float to[3];	/* Current camera parameters	*/
243   float from[3];
244   float up[3];
245   int p;
246   float fov;
247   float width;
248 
249   float grad_r;
250   float grad_p;
251   float init_width;
252 
253   struct
254   {
255     int x, y;
256   } mousePosition;
257   int buttonStates[3];
258 
259 } RPZData;
260 
261 
262 
263 static void *
RPZInitMode(dxObject args,int w,int h,int * mask)264 RPZInitMode(dxObject args, int w, int h, int *mask)
265 {
266     RPZData *rpzdata = (RPZData *)DXAllocateZero(sizeof(struct RPZData));
267     if (! rpzdata)
268 	return NULL;
269 
270     /* Retrieve the window pointer. */
271     rpzdata->me = (DXTOOLS_WINDOW *)DXGetPrivateData((Private)args);
272 
273     /*
274      * Grab the window size
275      */
276     rpzdata->w = w;
277     rpzdata->h = h;
278 
279     if (w > h)
280 	rpzdata->grad_r = rpzdata->grad_p = h / 2.0;
281     else
282 	rpzdata->grad_r = rpzdata->grad_p = w / 2.0;
283 
284     rpzdata->buttonStates[0] = BUTTON_UP;
285     rpzdata->buttonStates[1] = BUTTON_UP;
286     rpzdata->buttonStates[2] = BUTTON_UP;
287 
288     *mask = DXEVENT_KEYPRESS | DXEVENT_LEFT | DXEVENT_MIDDLE | DXEVENT_RIGHT;
289 
290     return (void *)rpzdata;
291 }
292 
293 static void
RPZEndMode(void * data)294 RPZEndMode(void *data)
295 {
296     RPZData *rpzdata = (RPZData *)data;
297     if (rpzdata)
298     {
299 	if (rpzdata->args)
300 	    DXDelete(rpzdata->args);
301 
302 	if (rpzdata->obj)
303 	    DXDelete(rpzdata->obj);
304     }
305 
306     DXFree(data);
307 }
308 
309 static void
RPZSetCamera(void * data,float to[3],float from[3],float up[3],int proj,float fov,float width)310 RPZSetCamera(void *data, float to[3], float from[3], float up[3],
311 		    int proj, float fov, float width)
312 {
313     int i;
314     RPZData *rpzdata = (RPZData *)data;
315 
316     /*
317      * Grab the camera
318      */
319     for (i = 0; i < 3; i++)
320 	rpzdata->to[i]   = to[i],
321 	rpzdata->from[i] = from[i],
322 	rpzdata->up[i]   = up[i];
323 
324     rpzdata->p     = proj;
325     rpzdata->fov   = fov;
326     rpzdata->width = rpzdata->init_width = width;
327 
328 
329     if (proj) {
330       float dx = to[0] - from[0];
331       float dy = to[1] - from[1];
332       float dz = to[2] - from[2];
333       float vd = sqrtf(dx*dx + dy*dy + dz*dz);
334 
335 	rpzdata->grad_p = (fov * vd) / rpzdata->w;
336     }
337     else
338 	rpzdata->grad_p = width / rpzdata->w;
339 
340 }
341 
342 static int
RPZGetCamera(void * data,float to[3],float from[3],float up[3],int * proj,float * fov,float * width)343 RPZGetCamera(void *data, float to[3], float from[3], float up[3],
344 		    int *proj, float *fov, float *width)
345 {
346     int i;
347     RPZData *rpzdata = (RPZData *)data;
348 
349     /*
350      * Return the camera
351      */
352     for (i = 0; i < 3; i++)
353 	to[i]   = rpzdata->to[i],
354 	from[i] = rpzdata->from[i],
355 	up[i]   = rpzdata->up[i];
356 
357     *proj  = rpzdata->p;
358     *fov   = rpzdata->fov;
359     *width = rpzdata->width;
360 
361     return 1;
362 }
363 
364 static void
RPZSetRenderable(void * data,dxObject obj)365 RPZSetRenderable(void *data, dxObject obj)
366 {
367     RPZData *rpzdata = (RPZData *)data;
368     DXReference(obj);
369     if (rpzdata->obj)
370 	DXDelete(rpzdata->obj);
371     rpzdata->obj = obj;
372 }
373 
374 
375 static int
RPZGetRenderable(void * data,dxObject * obj)376 RPZGetRenderable(void *data, dxObject *obj)
377 {
378     RPZData *rpzdata = (RPZData *)data;
379     if (rpzdata->obj)
380     {
381 	*obj = rpzdata->obj;
382 	return 1;
383     }
384     else
385     {
386 	*obj = NULL;
387 	return 0;
388     }
389 }
390 
391 static void
RPZEventHandler(void * data,DXEvent * event)392 RPZEventHandler(void *data, DXEvent *event)
393 {
394   RPZData *rpzdata = (RPZData *)data;
395   DXTOOLS_WINDOW *win = rpzdata->me;
396   int b = WHICH_BUTTON(event);
397 
398   if(!data)
399     return;
400 
401   switch(event->any.event)
402     {
403     case DXEVENT_LEFT:
404 
405       switch (event->mouse.state)
406 	{
407 	case BUTTON_DOWN:
408 	  StartStroke(data, (DXMouseEvent *)event);
409 	  rpzdata->buttonStates[b] = BUTTON_DOWN;
410 	  break;
411 
412 	case BUTTON_MOTION:
413 	  if (rpzdata->buttonStates[b] == BUTTON_UP)
414 	    StartStroke(data, (DXMouseEvent *)event);
415 	  else
416 	    RotateEndStroke(data, (DXMouseEvent *)event);
417 	  rpzdata->buttonStates[b] = BUTTON_DOWN;
418 	  break;
419 
420 	case BUTTON_UP:
421 	  RotateEndStroke(data, (DXMouseEvent *)event);
422 	  rpzdata->buttonStates[b] = BUTTON_UP;
423 	  break;
424 
425 	default:
426 	  break;
427 	}
428 
429       break;
430     case DXEVENT_MIDDLE:
431 
432       switch (event->mouse.state)
433 	{
434 	case BUTTON_DOWN:
435 	  StartStroke(data, (DXMouseEvent *)event);
436 	  rpzdata->buttonStates[b] = BUTTON_DOWN;
437 	  break;
438 
439 	case BUTTON_MOTION:
440 	  if (rpzdata->buttonStates[b] == BUTTON_UP)
441 	    StartStroke(data, (DXMouseEvent *)event);
442 	  else {
443 	    if(win->middle_button_mode == 0)
444 	      PanEndStroke(data, (DXMouseEvent *)event);
445 	    else
446 	      TiltEndStroke(data, (DXMouseEvent *)event);
447 	  }
448 	  rpzdata->buttonStates[b] = BUTTON_DOWN;
449 	  break;
450 
451 	case BUTTON_UP:
452 	  if(win->middle_button_mode == 0)
453 	    PanEndStroke(data, (DXMouseEvent *)event);
454 	  else
455 	    TiltEndStroke(data, (DXMouseEvent *)event);
456 	  rpzdata->buttonStates[b] = BUTTON_UP;
457 	  break;
458 
459 	default:
460 	  break;
461 	}
462 
463       break;
464     case DXEVENT_RIGHT:
465 
466       switch (event->mouse.state)
467 	{
468 	case BUTTON_DOWN:
469 
470 	  StartStroke(data, (DXMouseEvent *)event);
471 	  rpzdata->buttonStates[b] = BUTTON_DOWN;
472 	  break;
473 
474 	case BUTTON_MOTION:
475 	  if (rpzdata->buttonStates[b] == BUTTON_UP)
476 	    StartStroke(data, (DXMouseEvent *)event);
477 	  else
478 	    ZoomEndStroke(data, (DXMouseEvent *)event);
479 	  rpzdata->buttonStates[b] = BUTTON_DOWN;
480 	  break;
481 
482 	case BUTTON_UP:
483 	  ZoomEndStroke(data, (DXMouseEvent *)event);
484 	  rpzdata->buttonStates[b] = BUTTON_UP;
485 	  break;
486 
487 	default:
488 	  break;
489 	}
490 
491       break;
492     case DXEVENT_KEYPRESS:
493 
494       switch(event->keypress.key)
495 	{
496 	  int n_error;
497 
498 	case DXTOOLS_KEY_HELP:
499 	  printf("****************************************\n");
500 	  printf("Online help for DXTOOLS:\n");
501 	  printf("****************************************\n");
502 	  printf("* Mouse controls:\n");
503 	  printf("Left button:   rotate\n");
504 	  printf("Middle button: pan or tilt, see below\n");
505 	  printf("Right button:  zoom\n\n");
506 	  printf("* Key controls:\n");
507 	  printf("'%c': this help blurb\n",
508 		 DXTOOLS_KEY_HELP);
509 	  printf("'%c': close window\n",
510 		 DXTOOLS_KEY_QUIT);
511 	  printf("'%c': block the simulation from providing new input\n",
512 		 DXTOOLS_KEY_BLOCK);
513 	  printf("'%c': toggle display of legend\n",
514 		 DXTOOLS_KEY_LEGEND);
515 	  printf("'%c': toggle orthographic/perspective projection\n",
516 		 DXTOOLS_KEY_PROJECTION);
517 	  printf("'%c': toggle hardware rendering\n",
518 		 DXTOOLS_KEY_HARDWARE);
519 	  printf("'%c': toggle background color black/white\n",
520 		 DXTOOLS_KEY_VIDEO);
521 	  printf("'%c': toggle display of bounding box\n",
522 		 DXTOOLS_KEY_BOX);
523 	  printf("'%c': toggle display of axes box\n",
524 		 DXTOOLS_KEY_AXES);
525 	  printf("'%c': reset camera view\n",
526 		 DXTOOLS_KEY_RESET);
527 	  printf("'%c': write image to disk\n",
528 		 DXTOOLS_KEY_WRITE);
529 	  printf("'%c': toggle middle mouse button mode between pan/tilt\n",
530 		 DXTOOLS_KEY_MIDDLE_BUTTON_MODE);
531 
532 	  break;
533 	case DXTOOLS_KEY_QUIT:
534 	  win->close_me = true;
535 	  break;
536 	case DXTOOLS_KEY_WRITE:
537 	  win->save_me = true;
538 	  break;
539 	case DXTOOLS_KEY_BLOCK:
540 	  if(win->dxc->check_block_context) {
541 	    win->dxc->check_block_context = false;
542 	    printf("*** DXTOOLS: input UNBLOCKED\n");
543 	    n_error = pthread_cond_broadcast(&win->dxc->block_context);
544 	    if(n_error)
545 	      fprintf(stderr, "Signalling of condition failed!\n");
546 	  }
547 	  else {
548 	    win->dxc->check_block_context = true;
549 	    printf("*** DXTOOLS: input BLOCKED\n");
550 	  }
551 	  break;
552 	case DXTOOLS_KEY_VIDEO:
553 	  if(win->use_inverse_video) {
554 	    win->use_inverse_video = false;
555 	    printf("*** %s: background color is BLACK\n", win->title);
556 	  }
557 	  else {
558 	    win->use_inverse_video = true;
559 	    printf("*** %s: background color is WHITE\n", win->title);
560 	  }
561 
562 	  win->redraw_me = true;
563 	  break;
564 	case DXTOOLS_KEY_RESET:
565 	  win->reset_me = true;
566 	  break;
567 	case DXTOOLS_KEY_LEGEND:
568 	  if (win->use_legend) {
569 	    win->use_legend = false;
570 	    printf("*** %s: legend display is OFF\n", win->title);
571 
572 	    win->redraw_me = true;
573 	  }
574 	  else {
575 	    if(win->type != DXTOOLS_FEVECTOR) {
576 	      printf("*** %s: WARNING: No legend available for mesh display.\n", win->title);
577 	    }
578 	    else {
579 	      win->use_legend = true;
580 	      printf("*** %s: legend display is ON\n", win->title);
581 
582 	      win->redraw_me = true;
583 	    }
584 	  }
585 
586 	  break;
587 	case DXTOOLS_KEY_PROJECTION:
588 	  if (win->use_perspective) {
589 	    win->use_perspective = false;
590 	    printf("*** %s: orthographic projection ON\n", win->title);
591 
592 	    win->reset_me = true;
593 	  }
594 	  else {
595 	    win->use_perspective = true;
596 	    printf("*** %s: perspective projection ON\n", win->title);
597 
598 	    win->reset_me = true;
599 	  }
600 
601 	  break;
602 	case DXTOOLS_KEY_HARDWARE:
603 	  if (win->use_hardware) {
604 	    win->use_hardware = false;
605 	    printf("*** %s: hardware rendering OFF\n", win->title);
606 	  }
607 	  else {
608 	    win->use_hardware = true;
609 	    printf("*** %s: hardware rendering ON\n", win->title);
610 	  }
611 	  win->redraw_me = true;
612 
613 	  break;
614 	case DXTOOLS_KEY_BOX:
615 	  if(win->use_bounding_box) {
616 	    win->use_bounding_box = false;
617 	    printf("*** %s: bounding box OFF\n", win->title);
618 	  }
619 	  else {
620 	    win->use_bounding_box = true;
621 	    printf("*** %s: bounding box ON\n", win->title);
622 	  }
623 
624 	  win->redraw_me = true;
625 	  break;
626 	case DXTOOLS_KEY_AXES:
627 	  if(win->use_axes) {
628 	    win->use_axes = false;
629 	    printf("*** %s: axis display OFF\n", win->title);
630 	  }
631 	  else {
632 	    win->use_axes = true;
633 	    printf("*** %s: axis display ON\n", win->title);
634 	  }
635 
636 	  win->redraw_me = true;
637 	  break;
638 #if DIM_OF_WORLD == 3
639 	case DXTOOLS_KEY_CUTPLANE:
640 	  if(win->use_cutplane) {
641 	    win->use_cutplane = false;
642 	    printf("*** %s: cutplane display OFF\n", win->title);
643 	    win->redraw_me = true;
644 	  }
645 	  else {
646  	    if(win->type != DXTOOLS_FEVECTOR) {
647 	      printf("*** %s: WARNING: cut plane only works for FE data. Operation cancelled.\n", win->title);
648 	    }
649 	    else {
650 	      win->use_cutplane = true;
651 	      printf("*** %s: cutplane display ON\n", win->title);
652 	      win->redraw_me = true;
653 	    }
654 	  }
655 
656 	  break;
657 	case DXTOOLS_KEY_CUTPLANE_X:
658 	  printf("*** %s: cutplane normal is (1,0,0)\n", win->title);
659 	  win->cutplane_direction = 0;
660 	  win->redraw_me = true;
661 	  break;
662 	case DXTOOLS_KEY_CUTPLANE_Y:
663 	  printf("*** %s: cutplane normal is (0,1,0)\n", win->title);
664 	  win->cutplane_direction = 1;
665 	  win->redraw_me = true;
666 	  break;
667 	case DXTOOLS_KEY_CUTPLANE_Z:
668 	  printf("*** %s: cutplane normal is (0,0,1)\n", win->title);
669 	  win->cutplane_direction = 2;
670 	  win->redraw_me = true;
671 	  break;
672 	case DXTOOLS_KEY_CUTPLANE_PLUS:
673 	  win->cutplane_level += 0.1f;
674 	  win->cutplane_level = MIN(win->cutplane_level, 1.0f);
675 
676 	  printf("*** %s: cutplane level at %+.2f\n", win->title,
677 		 win->cutplane_level);
678 	  win->redraw_me = true;
679 	  break;
680 	case DXTOOLS_KEY_CUTPLANE_MINUS:
681 	  win->cutplane_level -= 0.1f;
682 	  win->cutplane_level = MAX(win->cutplane_level, -1.0f);
683 
684 	  printf("*** %s: cutplane level at %+.2f\n", win->title,
685 		 win->cutplane_level);
686 	  win->redraw_me = true;
687 	  break;
688 	case DXTOOLS_KEY_CUTPLANE_PPLUS:
689 	  win->cutplane_level += 0.01f;
690 	  win->cutplane_level = MIN(win->cutplane_level, 1.0f);
691 
692 	  printf("*** %s: cutplane level at %+.2f\n", win->title,
693 		 win->cutplane_level);
694 	  win->redraw_me = true;
695 	  break;
696 	case DXTOOLS_KEY_CUTPLANE_MMINUS:
697 	  win->cutplane_level -= 0.01f;
698 	  win->cutplane_level = MAX(win->cutplane_level, -1.0f);
699 
700 	  printf("*** %s: cutplane level at %+.2f\n", win->title,
701 		 win->cutplane_level);
702 	  win->redraw_me = true;
703 	  break;
704 #endif
705 	case DXTOOLS_KEY_MIDDLE_BUTTON_MODE:
706 	  if(win->middle_button_mode == 1) {
707 	    win->middle_button_mode = 0;
708 	    printf("*** %s: middle mouse button does PAN\n", win->title);
709 	  }
710 	  else {
711 	    win->middle_button_mode = 1;
712 	    printf("*** %s: middle mouse button does TILT\n", win->title);
713 	  }
714 
715 	  break;
716 	default:
717 	  break;
718 	}
719 
720 
721       break;
722     default:
723       break;
724     }
725 }
726 
727 
StartStroke(void * data,DXMouseEvent * event)728 static void StartStroke(void *data, DXMouseEvent *event)
729 {
730     RPZData *rdata = (RPZData *)data;
731 
732     rdata->mousePosition.x = event->x;
733     rdata->mousePosition.y = event->y;
734 
735     return;
736 }
737 
738 static void
RotateEndStroke(void * data,DXMouseEvent * event)739 RotateEndStroke(void *data, DXMouseEvent *event)
740 {
741     RPZData *rdata = (RPZData *)data;
742     float ov[3], nv[3], rot[4][4];
743     float rt[3], up[3];
744     float stroke[3], axis[3], d;
745     float a, dx, dy;
746     float t, s, c;
747 
748     dx = event->x - rdata->mousePosition.x;
749     dy = event->y - rdata->mousePosition.y;
750 
751     if (dx || dy)
752       {
753 
754 	ov[0] = rdata->from[0] - rdata->to[0];
755 	ov[1] = rdata->from[1] - rdata->to[1];
756 	ov[2] = rdata->from[2] - rdata->to[2];
757 
758 	rt[0] = ov[1]*rdata->up[2] - ov[2]*rdata->up[1];
759 	rt[1] = ov[2]*rdata->up[0] - ov[0]*rdata->up[2];
760 	rt[2] = ov[0]*rdata->up[1] - ov[1]*rdata->up[0];
761 
762 	d = sqrtf(rt[0]*rt[0] + rt[1]*rt[1] + rt[2]*rt[2]);
763 	rt[0] /= d;
764 	rt[1] /= d;
765 	rt[2] /= d;
766 
767 	up[0] = rt[1]*ov[2] - rt[2]*ov[1];
768 	up[1] = rt[2]*ov[0] - rt[0]*ov[2];
769 	up[2] = rt[0]*ov[1] - rt[1]*ov[0];
770 	d = sqrtf(up[0]*up[0] + up[1]*up[1] + up[2]*up[2]);
771 	rdata->up[0] = up[0] /= d;
772 	rdata->up[1] = up[1] /= d;
773 	rdata->up[2] = up[2] /= d;
774 
775 	dx /= rdata->grad_r;
776 	dy /= rdata->grad_r;
777 
778 	stroke[0] = dx*rt[0] + dy*up[0];
779 	stroke[1] = dx*rt[1] + dy*up[1];
780 	stroke[2] = dx*rt[2] + dy*up[2];
781 
782 	axis[0] = ov[1]*stroke[2] - ov[2]*stroke[1];
783 	axis[1] = ov[2]*stroke[0] - ov[0]*stroke[2];
784 	axis[2] = ov[0]*stroke[1] - ov[1]*stroke[0];
785 	d = sqrtf(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
786 	axis[0] /= d;
787 	axis[1] /= d;
788 	axis[2] /= d;
789 
790 	a = sqrt(dx*dx + dy*dy);
791 	s = sinf(a);
792 	c = cosf(a);
793 	t = 1.0 - c;
794 
795 	ROTXYZ(rot, axis[0], axis[1], axis[2], s, c, t);
796 
797 	nv[0] = rot[0][0]*ov[0] +
798 	  rot[1][0]*ov[1] +
799 	  rot[2][0]*ov[2];
800 
801 	nv[1] = rot[0][1]*ov[0] +
802 	  rot[1][1]*ov[1] +
803 	  rot[2][1]*ov[2];
804 
805 	nv[2] = rot[0][2]*ov[0] +
806 	  rot[1][2]*ov[1] +
807 	  rot[2][2]*ov[2];
808 
809 	rdata->from[0] = rdata->to[0] + nv[0];
810 	rdata->from[1] = rdata->to[1] + nv[1];
811 	rdata->from[2] = rdata->to[2] + nv[2];
812       }
813 
814 
815     rdata->mousePosition.x = event->x;
816     rdata->mousePosition.y = event->y;
817 
818 
819     return;
820 
821 }
822 
823 
PanEndStroke(void * data,DXMouseEvent * event)824 static void PanEndStroke(void *data, DXMouseEvent *event)
825 {
826     float a, u[3], r[3], v[3];
827     float dx, dy;
828 
829     RPZData *pdata = (RPZData *)data;
830 
831 
832     if (event->x != pdata->mousePosition.x ||
833 	event->y != pdata->mousePosition.y)
834     {
835 
836 	dx = event->x - pdata->mousePosition.x;
837 	dy = event->y - pdata->mousePosition.y;
838 
839 	a = sqrtf(pdata->up[0]*pdata->up[0] +
840 		 pdata->up[1]*pdata->up[1] +
841 		 pdata->up[2]*pdata->up[2]);
842 
843 	u[0] = pdata->up[0]/a;
844 	u[1] = pdata->up[1]/a;
845 	u[2] = pdata->up[2]/a;
846 
847 	v[0] = pdata->from[0] - pdata->to[0];
848 	v[1] = pdata->from[1] - pdata->to[1];
849 	v[2] = pdata->from[2] - pdata->to[2];
850 
851 	r[0] = v[2]*pdata->up[1] - v[1]*pdata->up[2];
852 	r[1] = v[0]*pdata->up[2] - v[2]*pdata->up[0];
853 	r[2] = v[1]*pdata->up[0] - v[0]*pdata->up[1];
854 
855 	a = sqrtf(r[0]*r[0] + r[1]*r[1]+ r[2]*r[2]);
856 	r[0] /= a;
857 	r[1] /= a;
858 	r[2] /= a;
859 
860 	v[0] = (-dx*r[0] + dy*u[0]) * pdata->grad_p;
861 	v[1] = (-dx*r[1] + dy*u[1]) * pdata->grad_p;
862 	v[2] = (-dx*r[2] + dy*u[2]) * pdata->grad_p;
863 
864 	pdata->to[0] += v[0];
865 	pdata->to[1] += v[1];
866 	pdata->to[2] += v[2];
867 
868 	pdata->from[0] += v[0];
869 	pdata->from[1] += v[1];
870 	pdata->from[2] += v[2];
871     }
872 
873     pdata->mousePosition.x = event->x;
874     pdata->mousePosition.y = event->y;
875 
876     return;
877 
878 }
879 
TiltEndStroke(void * data,DXMouseEvent * event)880 static void TiltEndStroke(void *data, DXMouseEvent *event)
881 {
882   RPZData *tdata = (RPZData *)data;
883   float v[3], rot[4][4];
884   float n[3], d;
885   float a, a0, a1;
886   float x0, y0;
887   float x1, y1;
888   float t, s, c;
889   int cx = tdata->w / 2;
890   int cy = tdata->h / 2;
891 
892 
893   if (event->x != tdata->mousePosition.x ||
894       event->y != tdata->mousePosition.y) {
895     x0 = event->x - cx;
896     y0 = event->y - cy;
897 
898     if (x0 == 0 && y0 == 0)
899       x0 = 1.0f;
900 
901     d = sqrtf(x0*x0 + y0*y0);
902     x0 /= d;
903     y0 /= d;
904     if (y0 < 0)
905       a0 = acosf(x0);
906     else
907       a0 = (2*3.1415926) - acos(x0);
908 
909     x1 = tdata->mousePosition.x - cx;
910     y1 = tdata->mousePosition.y - cy;
911 
912     if (x1 == 0 && y1 == 0)
913       x1 = 1.0f;
914 
915     d = sqrtf(x1*x1 + y1*y1);
916     x1 /= d;
917     y1 /= d;
918     if (y1 < 0)
919       a1 = acosf(x1);
920     else
921       a1 = (2*3.1415926) - acos(x1);
922 
923     v[0] = tdata->from[0] - tdata->to[0];
924     v[1] = tdata->from[1] - tdata->to[1];
925     v[2] = tdata->from[2] - tdata->to[2];
926     d = sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
927     v[0] /= d;
928     v[1] /= d;
929     v[2] /= d;
930 
931     a = a1 - a0;
932 
933     s = sinf(a);
934     c = cosf(a);
935     t = 1.0f - c;
936 
937     ROTXYZ(rot, v[0], v[1], v[2], s, c, t);
938 
939     n[0] = rot[0][0]*tdata->up[0] +
940       rot[1][0]*tdata->up[1] +
941       rot[2][0]*tdata->up[2];
942 
943     n[1] = rot[0][1]*tdata->up[0] +
944       rot[1][1]*tdata->up[1] +
945       rot[2][1]*tdata->up[2];
946 
947     n[2] = rot[0][2]*tdata->up[0] +
948       rot[1][2]*tdata->up[1] +
949       rot[2][2]*tdata->up[2];
950 
951     tdata->up[0] = n[0];
952     tdata->up[1] = n[1];
953     tdata->up[2] = n[2];
954   }
955 
956   tdata->mousePosition.x = event->x;
957   tdata->mousePosition.y = event->y;
958 
959   return;
960 }
961 
962 
ZoomEndStroke(void * data,DXMouseEvent * event)963 static void ZoomEndStroke(void *data, DXMouseEvent *event)
964 {
965     float dy;
966     RPZData *zdata = (RPZData *)data;
967 
968 
969 
970     dy = (event->y - zdata->mousePosition.y) /
971 			((float) zdata->h);
972 
973     if (event->x != zdata->mousePosition.x ||
974 	event->y != zdata->mousePosition.y)
975     {
976 	if (zdata->p)
977 	{
978 	    zdata->from[0] -= 0.9*dy*(zdata->to[0] - zdata->from[0]);
979 	    zdata->from[1] -= 0.9*dy*(zdata->to[1] - zdata->from[1]);
980 	    zdata->from[2] -= 0.9*dy*(zdata->to[2] - zdata->from[2]);
981 	}
982 	else
983 	{
984 	    zdata->width += dy * zdata->init_width;
985 	}
986     }
987 
988     zdata->mousePosition.x = event->x;
989     zdata->mousePosition.y = event->y;
990 
991     return;
992 
993 }
994 
995 
996 
997 
998 
999 
1000 
display_error(int n_error)1001 static void display_error(int n_error)
1002 {
1003   FUNCNAME("display_error");
1004 
1005   switch(n_error) {
1006   case EFAULT:
1007     WARNING("Bad pointer. (EFAULT)\n");
1008     break;
1009   case EAGAIN:
1010     WARNING("System lacks resources. (EAGAIN)\n");
1011     break;
1012   case ENOMEM:
1013     WARNING("Insufficient memory. (ENOMEM)\n");
1014     break;
1015   case EINVAL:
1016     WARNING("Invalid attributes? (EINVAL)\n");
1017     break;
1018   case EPERM:
1019     WARNING("Caller lacks permission. (EPERM)\n");
1020     break;
1021   case EBUSY:
1022     WARNING("Object already initialized or busy. (EBUSY)\n");
1023     break;
1024   case EDEADLK:
1025     WARNING("Current thread already owns mutex. (EDEADLK)\n");
1026     break;
1027   case ETIMEDOUT:
1028     WARNING("Timed out while waiting for signal. (ETIMEDOUT)\n");
1029     break;
1030   default:
1031     WARNING("Unknown error %d.\n", n_error);
1032   }
1033 
1034   return;
1035 }
1036 
display_dx_error()1037 static void display_dx_error()
1038 {
1039   FUNCNAME("display_dx_error");
1040 
1041   ERROR("DX error code: %d\n", DXGetError());
1042   ERROR("DX error message: %s\n", DXGetErrorMessage());
1043 
1044 #if ALBERTA_DEBUG
1045   /* Paranoid error behavior. */
1046   ERROR_EXIT("Exiting...\n");
1047 #endif
1048 
1049   return;
1050 }
1051 
1052 /* return true on error. */
1053 
DX_update(DXTOOLS_WINDOW * win)1054 static int DX_update(DXTOOLS_WINDOW *win)
1055 {
1056 
1057   ModuleInput  min[10];
1058   ModuleOutput mout[10];
1059   dxObject tmpobj, tmpcam, tmpwhere;
1060   dxObject events, size, displayobject, where, camera;
1061   dxObject colorbar = NULL, boundingbox = NULL;
1062   Private  winobj;
1063   Array windowsize;
1064   RGBColor color = { 0, };
1065   int *windowsize_ptr;
1066   const int supervise_mode = 0;
1067 
1068   if(!win->displayobject)
1069     return false;
1070 
1071   if(!(windowsize = DXNewArray(TYPE_INT,CATEGORY_REAL,1, 2))) {
1072     display_dx_error();
1073     return true;
1074   }
1075   if(!DXAddArrayData(windowsize,0,1,NULL)) {
1076     display_dx_error();
1077     return true;
1078   }
1079 
1080   windowsize_ptr = (int *)DXGetArrayData(windowsize);
1081   windowsize_ptr[0]=win->draw_width;
1082   windowsize_ptr[1]=win->draw_height;
1083 
1084   /* call SuperviseWindow and check for events */
1085 
1086   DXModSetObjectInput(&min[0], "size", (dxObject)windowsize);
1087   DXModSetIntegerInput(&min[1], "parent", win->drawingarea);
1088   DXModSetIntegerInput(&min[2], "sizeFlag",1);
1089   DXModSetStringInput(&min[3], "name",win->title);
1090   DXModSetObjectOutput(&mout[0], "where", &where);
1091   DXModSetObjectOutput(&mout[1], "size", &size);
1092   DXModSetObjectOutput(&mout[2], "events", &events);
1093   if(!DXCallModule("SuperviseWindow",4,min,3,mout)) {
1094     display_dx_error();
1095     return true;
1096   }
1097 
1098   /* No events? Camera view not reset? Then leave routine. */
1099   if(!events && !win->reset_me && !win->redraw_me && !win->save_me) {
1100     if(!DXDelete(where))
1101       display_dx_error();
1102     if(!DXDelete(size))
1103       display_dx_error();
1104     if(!DXDelete(events))
1105       display_dx_error();
1106 
1107     return false;
1108   }
1109 
1110   /* No initial camera set? Do so now. */
1111   if (win->reset_me || !win->initial_camera) {
1112     if(win->initial_camera && !DXDelete(win->initial_camera))
1113       display_dx_error();
1114 
1115 
1116     if(!DXReference(win->displayobject)) {
1117       display_dx_error();
1118       return true;
1119     }
1120     DXModSetObjectInput(&min[0], "object", win->displayobject);
1121     DXModSetIntegerInput(&min[1], "perspective", win->use_perspective);
1122     if(win->use_inverse_video)
1123       DXModSetStringInput(&min[2], "background", "white");
1124     else
1125       DXModSetStringInput(&min[2], "background", "black");
1126     DXModSetObjectOutput(&mout[0], "camera", &win->initial_camera);
1127     if(!DXCallModule("AutoCamera",3,min,1,mout)) {
1128       display_dx_error();
1129       return true;
1130     }
1131   }
1132 
1133   if(!(winobj = DXNewPrivate((Pointer)win, NULL))) {
1134     display_dx_error();
1135     return true;
1136   }
1137 
1138   if(!DXReference(win->displayobject)) {
1139     display_dx_error();
1140     return true;
1141   }
1142 
1143   if(!DXReference(win->initial_camera)) {
1144     display_dx_error();
1145     return true;
1146   }
1147 
1148   DXModSetObjectInput(&min[0], "where",where);
1149   DXModSetObjectInput(&min[1], "defaultCamera", win->initial_camera);
1150   DXModSetIntegerInput(&min[2], "resetCamera", win->reset_me ? 1: 0);
1151   win->reset_me = false;
1152 
1153   DXModSetObjectInput(&min[3], "object",win->displayobject);
1154   DXModSetIntegerInput(&min[4], "resetObject",1);
1155   DXModSetObjectInput(&min[5], "size",size);
1156   DXModSetObjectInput(&min[6], "events",events);
1157   DXModSetIntegerInput(&min[7], "mode",supervise_mode);
1158   DXModSetObjectInput(&min[8], "args",(dxObject)winobj);
1159   DXModSetObjectOutput(&mout[0], "object",&tmpobj);
1160   DXModSetObjectOutput(&mout[1], "camera",&tmpcam);
1161   DXModSetObjectOutput(&mout[2], "where",&tmpwhere);
1162   if(!DXCallModule("SuperviseState",9,min,3,mout)) {
1163     display_dx_error();
1164     return true;
1165   }
1166 
1167   where         = tmpwhere;
1168   displayobject = tmpobj;
1169   camera        = tmpcam;
1170 
1171 
1172   /* Don't try to to 3D perspective volume rendering - DX can't do it. */
1173 #if DIM_OF_WORLD == 3
1174   if((win->type == DXTOOLS_FEVECTOR)
1175      && !win->use_hardware
1176      && win->use_perspective
1177      && !win->use_cutplane
1178      && win->dim == 3) {
1179     printf("*** %s: WARNING: DX currently does not support perspective volume rendering. Perspective projection OFF.\n", win->title);
1180     win->use_perspective = false;
1181     win->reset_me = true;
1182 
1183     if(!DXDelete(where))
1184       display_dx_error();
1185 
1186     return false;
1187   }
1188 #endif
1189 
1190 
1191   /* Adjust settings of camera, if necessary. */
1192   if(win->use_inverse_video) {
1193     color.r = 1.0f; color.g = 1.0f; color.b = 1.0f;
1194   }
1195   else {
1196     color.r = 0.0f; color.g = 0.0f; color.b = 0.0;
1197   }
1198   camera = (dxObject)DXSetBackgroundColor((Camera)camera, color);
1199 
1200 
1201   /* If we have a colormap, then display of a legend is possible. */
1202 
1203   if(win->use_legend && win->colormap) {
1204     if(!DXReference((dxObject)win->colormap)) {
1205       display_dx_error();
1206       return true;
1207     }
1208 
1209     DXModSetObjectInput(&min[0], "colormap", (dxObject)win->colormap);
1210     if(win->use_inverse_video) {
1211       DXModSetStringInput(&min[1], "colors", "black");
1212       DXModSetStringInput(&min[2], "annotation", "labels");
1213     }
1214     else {
1215       DXModSetStringInput(&min[1], "colors", "white");
1216       DXModSetStringInput(&min[2], "annotation", "labels");
1217     }
1218     DXModSetObjectOutput(&mout[0], "colorbar", &colorbar);
1219 
1220     if(!DXCallModule("ColorBar",3,min,1,mout)) {
1221       display_dx_error();
1222       return true;
1223     }
1224   }
1225 
1226 
1227   /* Show a bounding box if desired. */
1228   /* for display of a cutplane with axes box, we also compute the */
1229   /* bounding box to use it as corners input of AutoAxes. */
1230 
1231   if(win->use_bounding_box || (win->use_axes && win->use_cutplane)) {
1232     if(!DXReference(displayobject)) {
1233       display_dx_error();
1234       return true;
1235     }
1236 
1237     DXModSetObjectInput(&min[0], "input", displayobject);
1238     DXModSetObjectOutput(&mout[0], "box", &boundingbox);
1239 
1240     if(!DXCallModule("ShowBox",1,min,1,mout)) {
1241       display_dx_error();
1242       return true;
1243     }
1244   }
1245 
1246   /* build a cutplane, if desired. Do this after bounding box */
1247   /* so that these are built around the original data. */
1248   if(win->use_cutplane) {
1249     float *array_normal_data;
1250     Array  array_normal;
1251     float *array_center_data;
1252     Array  array_center;
1253     Point  bbox[8] = { { 0,}, };
1254     float  cx[3], dx[3];
1255     int i;
1256 
1257     if(!(array_normal = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3))) {
1258       display_dx_error();
1259       return true;
1260     }
1261 
1262     if(!DXAddArrayData(array_normal, 0, 1, NULL)) {
1263       display_dx_error();
1264       return true;
1265     }
1266 
1267     if(!(array_normal_data = (float *)DXGetArrayData(array_normal))) {
1268       display_dx_error();
1269       return true;
1270     }
1271 
1272 
1273     displayobject = DXBoundingBox(displayobject, bbox);
1274 
1275     cx[0] = (bbox[0].x + bbox[7].x)/2.0f;
1276     cx[1] = (bbox[0].y + bbox[7].y)/2.0f;
1277     cx[2] = (bbox[0].z + bbox[7].z)/2.0f;
1278 
1279     dx[0] = (bbox[7].x - bbox[0].x)/2.0f;
1280     dx[1] = (bbox[7].y - bbox[0].y)/2.0f;
1281     dx[2] = (bbox[7].z - bbox[0].z)/2.0f;
1282 
1283     if(!(array_center = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3))) {
1284       display_dx_error();
1285       return true;
1286     }
1287 
1288     if(!DXAddArrayData(array_center, 0, 1, NULL)) {
1289       display_dx_error();
1290       return true;
1291     }
1292 
1293     if(!(array_center_data = (float *)DXGetArrayData(array_center))) {
1294       display_dx_error();
1295       return true;
1296     }
1297 
1298     for(i = 0; i < 3; i++)
1299       array_center_data[i] = cx[i];
1300     i = win->cutplane_direction;
1301     array_center_data[i] += win->cutplane_level * dx[i];
1302 
1303     array_normal_data[i] = 1.0f;
1304 
1305 
1306     DXModSetObjectInput(&min[0], "data", displayobject);
1307     DXModSetObjectInput(&min[1], "normal", (dxObject)array_normal);
1308     DXModSetObjectInput(&min[2], "point", (dxObject)array_center);
1309     DXModSetObjectOutput(&mout[0], "plane", &tmpobj);
1310 
1311     if(!DXCallModule("MapToPlane", 3, min, 1, mout)) {
1312       display_dx_error();
1313       return true;
1314     }
1315     displayobject = tmpobj;
1316 
1317     /* remove the normals component as advised in the DX documentation */
1318     /* since the shading is not that useful. */
1319 
1320     DXModSetObjectInput(&min[0], "input", displayobject);
1321     DXModSetStringInput(&min[1], "name", "normals");
1322     DXModSetObjectOutput(&mout[0], "output", &tmpobj);
1323 
1324     if(!DXCallModule("Remove",2,min,1,mout)) {
1325       display_dx_error();
1326       return true;
1327     }
1328     displayobject = tmpobj;
1329   }
1330 
1331   /* Show an axes box if desired. */
1332   if(win->use_axes) {
1333     int n_in = 0;
1334 
1335     if(!DXReference(displayobject)) {
1336       display_dx_error();
1337       return true;
1338     }
1339     if(!DXReference(camera)) {
1340       display_dx_error();
1341       return true;
1342     }
1343 
1344     DXModSetObjectInput(&min[n_in++], "input", displayobject);
1345     DXModSetObjectInput(&min[n_in++], "camera", camera);
1346     if(win->use_cutplane) {
1347       /* Reference the bounding box since it might also be displayed. Sigh. */
1348       if(win->use_bounding_box) {
1349 	if(!DXReference(boundingbox)) {
1350 	  display_dx_error();
1351 	  return true;
1352 	}
1353       }
1354       DXModSetObjectInput(&min[n_in++], "corners", boundingbox);
1355     }
1356     DXModSetObjectOutput(&mout[0], "axes", &tmpobj);
1357 
1358     if(!DXCallModule("AutoAxes",n_in, min, 1, mout)) {
1359       display_dx_error();
1360       return true;
1361     }
1362     displayobject = tmpobj;
1363   }
1364 
1365 
1366   /* Collect the colorbar, bounding box, and any other objects. */
1367 
1368   if(win->use_bounding_box || colorbar) {
1369     int n_in = 0;
1370 
1371     DXModSetObjectInput(&min[n_in++],NULL, displayobject);
1372     if(colorbar)
1373       DXModSetObjectInput(&min[n_in++],NULL, colorbar);
1374     if(win->use_bounding_box)
1375       DXModSetObjectInput(&min[n_in++],NULL, boundingbox);
1376 
1377     DXModSetObjectOutput(&mout[0], "group", &tmpobj);
1378 
1379     if(!DXCallModule("Collect",n_in, min, 1, mout)) {
1380       display_dx_error();
1381       return true;
1382     }
1383 
1384     displayobject = tmpobj;
1385   }
1386 
1387   /* Now output the display object with Display. */
1388   if (win->use_hardware) {
1389     DXModSetObjectInput(&min[0], "input", displayobject);
1390     DXModSetStringInput(&min[1], "attribute", "rendering mode");
1391     DXModSetStringInput(&min[2], "value", "hardware");
1392     DXModSetObjectOutput(&mout[0], "output",&tmpobj);
1393     if(!DXCallModule("Options",3,min,1,mout)) {
1394       display_dx_error();
1395       return true;
1396     }
1397 
1398     displayobject = tmpobj;
1399   }
1400 
1401 
1402 
1403   if (win->save_me) {
1404     dxObject image;
1405     static int counter = 0;
1406     char filename[1024] = { '\0', };
1407     char format[1024] = "eps color";
1408 
1409 
1410     GET_PARAMETER(0, "dxtools saving file format", "%s", format);
1411 
1412     DXModSetObjectInput(&min[0], "object", displayobject);
1413     DXModSetObjectInput(&min[1], "camera", camera);
1414     DXModSetObjectOutput(&mout[0], "image", &image);
1415     if(!DXCallModule("Render",2,min,1,mout)) {
1416       display_dx_error();
1417       return true;
1418     }
1419 
1420     if(!DXReference(image)) {
1421       display_dx_error();
1422       return true;
1423     }
1424 
1425     snprintf(filename, 1024, "%s.%.6d", win->title, counter);
1426 
1427     DXModSetObjectInput(&min[0], "image", image);
1428     DXModSetStringInput(&min[1], "format", format);
1429     DXModSetStringInput(&min[2], "name", filename);
1430     if(!DXCallModule("WriteImage",3,min,0,mout)) {
1431       display_dx_error();
1432       return true;
1433     }
1434     printf("*** Image saved as '%s'.\n", filename);
1435 
1436     DXModSetObjectInput(&min[0], "object", image);
1437     DXModSetObjectInput(&min[1], "where", where);
1438     if(!DXCallModule("Display",2,min,0,mout)) {
1439       display_dx_error();
1440       return true;
1441     }
1442 
1443     win->save_me = false;
1444     counter++;
1445   }
1446   else {
1447     DXModSetObjectInput(&min[0], "object", displayobject);
1448     DXModSetObjectInput(&min[1], "camera", camera);
1449     DXModSetObjectInput(&min[2], "where", where);
1450     if(!DXCallModule("Display",3,min,0,mout)) {
1451       display_dx_error();
1452       return true;
1453     }
1454   }
1455 
1456   win->redraw_me = false;
1457 
1458   return false;
1459 }
1460 
1461 
1462 
destroyCB(Widget w,XtPointer xp1,XtPointer xp2)1463 void destroyCB(Widget w, XtPointer xp1, XtPointer xp2)
1464 {
1465   DXTOOLS_WINDOW *win = (DXTOOLS_WINDOW *)xp1;
1466 
1467   win->close_me = true;
1468 
1469   return;
1470 }
1471 
1472 /*
1473  * the following is the resize callback for the drawing area. If the
1474  * drawing area is resized, we need to send the new size to SuperviseWindow
1475  */
1476 
drawing_resizeCB(Widget w,XtPointer xp1,XtPointer xp2)1477 void drawing_resizeCB(Widget w, XtPointer xp1, XtPointer xp2)
1478 {
1479   DXTOOLS_WINDOW *win = (DXTOOLS_WINDOW *)xp1;
1480   Dimension       width, height;
1481 
1482   XtVaGetValues(w,
1483 		XtNwidth, &width,
1484 		XtNheight, &height,
1485 		NULL);
1486 
1487   win->draw_width = (int)width;
1488   win->draw_height = (int)height;
1489 
1490   win->redraw_me = true;
1491 
1492   return;
1493 }
1494 
1495 
create_window(DXTOOLS_WINDOW * win)1496 static void create_window(DXTOOLS_WINDOW *win)
1497 {
1498   Widget          form, drawingarea;
1499 
1500 
1501   win->me = XtVaCreatePopupShell("DXTools",
1502 	         topLevelShellWidgetClass, win->dxc->toplevel,
1503 				 XmNtitle, win->title,
1504 		 XmNwidth,    win->width,
1505 		 XmNheight,   win->height,
1506 				    XmNx, win->offsetx,
1507 				    XmNy, win->offsety,
1508                  NULL);
1509 
1510   form = XtVaCreateManagedWidget("form",
1511 				 xmFormWidgetClass, win->me,
1512 				 XmNfractionBase, 5,
1513 				 NULL);
1514 
1515   drawingarea = XtVaCreateManagedWidget("drawingarea",
1516                  xmDrawingAreaWidgetClass,
1517                  form,
1518                  XmNtopAttachment,   XmATTACH_FORM,
1519                  XmNtopOffset,  5,
1520                  XmNleftAttachment,  XmATTACH_FORM,
1521                  XmNleftOffset,  5,
1522                  XmNrightAttachment,  XmATTACH_FORM,
1523                  XmNrightOffset,  5,
1524                  XmNbottomAttachment,  XmATTACH_FORM,
1525                  XmNbottomOffset,  5,
1526 		 XmNwidth,    win->draw_width,
1527 		 XmNheight,   win->draw_height,
1528                  NULL);
1529 
1530 
1531 
1532   /* add a deletion callback for the drawing area */
1533   XtAddCallback(drawingarea, XtNdestroyCallback,
1534 		(XtCallbackProc)destroyCB,
1535 		(XtPointer)win);
1536 
1537   /* add a resize callback for the drawing area */
1538   XtAddCallback(drawingarea, XmNresizeCallback,
1539 		(XtCallbackProc)drawing_resizeCB,
1540 		(XtPointer)win);
1541 
1542   /* Draw the window! */
1543   XtPopup(win->me, XtGrabNonexclusive);
1544 
1545   /* get the window id of the drawing area */
1546   /* we'll need this to pass to SuperviseWindow */
1547   win->drawingarea = XtWindow(drawingarea);
1548 
1549   win->open_me = false;
1550 
1551   return;
1552 }
1553 
1554 
delete_window(DXTOOLS_WINDOW * win)1555 static void delete_window(DXTOOLS_WINDOW *win)
1556 {
1557   int n_error, i;
1558   DXTOOLS_CONTEXT *dxc = win->dxc;
1559 
1560   XtDestroyWidget(win->me);
1561 
1562   win->drawingarea = 0;
1563 
1564   if(win->displayobject) {
1565     if(!DXDelete(win->displayobject))
1566       display_dx_error();
1567     win->displayobject = NULL;
1568   }
1569 
1570   if(win->colormap) {
1571     if(!DXDelete((dxObject)win->colormap))
1572       display_dx_error();
1573     win->colormap = NULL;
1574   }
1575 
1576 /* If this was the last window, send unblocking signal to the main thread.*/
1577   if(dxc->check_block_context) {
1578     for(i = 0; i < DXTOOLS_MAX_WINDOWS; i++)
1579       if(dxc->win[i] && dxc->win[i]->displayobject)
1580 	break;
1581 
1582     if(i == DXTOOLS_MAX_WINDOWS) {
1583       printf("*** No more blocking content, sending unblocking signal!\n");
1584       dxc->check_block_context = false;
1585       n_error = pthread_cond_broadcast(&win->dxc->block_context);
1586       if(n_error)
1587 	fprintf(stderr, "Signalling of condition failed!\n");
1588     }
1589   }
1590 
1591   win->close_me = false;
1592 
1593   return;
1594 }
1595 
1596 
XCheckRIH(void * data)1597 Boolean XCheckRIH(void *data)
1598 {
1599   FUNCNAME("XCheckRIH");
1600   DXTOOLS_CONTEXT *dxc = (DXTOOLS_CONTEXT *)data;
1601   int    i, n_error;
1602   static struct timespec time_req = {0, 10000};
1603 
1604   if(!dxc) { /* Really bad error */
1605     ERROR("Lost DXTOOLS_CONTEXT object! Giving up.\n");
1606     return True;
1607   }
1608 
1609   /* Lock the context manager. */
1610   n_error = pthread_mutex_lock(&dxc->tlock);
1611   if(n_error){
1612     ERROR("Locking of thread failed!\n");
1613     display_error(n_error);
1614     return True;
1615   }
1616 
1617   /* Let DX handle its X events. */
1618 
1619   DXCheckRIH(0);
1620 
1621   /* Loop through all open windows. */
1622   for(i = 0; i < DXTOOLS_MAX_WINDOWS; i++) {
1623     if(dxc->win[i]) {
1624       /* First check if a window needs to be opened or closed. */
1625       if(dxc->win[i]->open_me)
1626 	create_window(dxc->win[i]);
1627 
1628       if(dxc->win[i]->close_me) {
1629 	delete_window(dxc->win[i]);
1630 	continue;
1631       }
1632 
1633       /* Now let DX check for events in drawing areas. */
1634       if(DX_update(dxc->win[i])) {
1635 	ERROR("Updating DX data failed!\n");
1636 	return True;
1637       }
1638     }
1639   }
1640 
1641   /* Now let the main thread know that some windows might ready. */
1642 
1643   n_error = pthread_cond_broadcast(&dxc->windows_ready);
1644   if(n_error){
1645     ERROR("Signalling of condition failed!\n");
1646     display_error(n_error);
1647     return True;
1648   }
1649 
1650   /* Unlock the context manager. */
1651   n_error = pthread_mutex_unlock(&dxc->tlock);
1652   if(n_error){
1653     ERROR("Unlocking of thread failed!\n");
1654     display_error(n_error);
1655     return True;
1656   }
1657 
1658   /* Put the thread to sleep for a while to avoid hogging resources. */
1659   nanosleep(&time_req, NULL);
1660 
1661   return False;
1662 }
1663 
1664 
1665 
1666 
1667 /* windows_thread(): Entry point for the thread managing windows. */
1668 
1669 /* return true on error or false otherwise. */
1670 
windows_thread(void * data)1671 static void *windows_thread(void *data)
1672 {
1673   FUNCNAME("windows_thread");
1674   DXTOOLS_CONTEXT *dxc = (DXTOOLS_CONTEXT *)data;
1675   static int trv = true;
1676   static int zero = 0;
1677   int    i, n_error = 0;
1678 
1679 #if ALBERTA_DEBUG
1680   /* Paranoid error behavior. */
1681   DXSetErrorExit(2);
1682 #endif
1683 
1684 
1685   /* Perform necessary initialization of the X Toolkit Intrinsics. */
1686   if(XtToolkitThreadInitialize() != True) {
1687     WARNING("X Toolkit Intrinsics do not seem to support multi-threading.\n");
1688     return &trv;
1689   }
1690 
1691   /* Lock the context manager. */
1692   n_error = pthread_mutex_lock(&dxc->tlock);
1693   if(n_error){
1694     ERROR("Locking of thread failed!\n");
1695     display_error(n_error);
1696     return &trv;
1697   }
1698 
1699   dxc->toplevel = XtVaAppInitialize (&dxc->app, "Alberta",
1700 				     NULL, 0, &zero, NULL,
1701 				     NULL, NULL);
1702 
1703   /* Unlock the context manager. */
1704   n_error = pthread_mutex_unlock(&dxc->tlock);
1705   if(n_error){
1706     ERROR("Unlocking of thread failed!\n");
1707     display_error(n_error);
1708     return &trv;
1709   }
1710 
1711   /* Add our event handler and start the event loop. This loop should */
1712   /* not exit, the thread should keep running.  */
1713 
1714   XtAppAddWorkProc(dxc->app, (XtWorkProc)XCheckRIH, dxc);
1715 
1716   XtAppMainLoop(dxc->app);
1717 
1718   /* This should not happen normally, see context_manager() below. */
1719 
1720   WARNING("Fell out of the X application loop! Cleaning up.\n");
1721 
1722   /* Try to clean up. */
1723 
1724   /* Lock the context manager. */
1725   n_error = pthread_mutex_lock(&dxc->tlock);
1726   if(n_error){
1727     ERROR("Locking of thread failed!\n");
1728     display_error(n_error);
1729     return &trv;
1730   }
1731 
1732   for(i = 0; i < DXTOOLS_MAX_WINDOWS; i++)
1733     if(dxc->win[i])
1734       delete_window(dxc->win[i]);
1735 
1736   XtDestroyApplicationContext(dxc->app);
1737 
1738   dxc->n_open_windows = 0;
1739   dxc->thread_running = false;
1740 
1741   /* Now unlock context data */
1742   n_error = pthread_mutex_unlock(&dxc->tlock);
1743   if(n_error){
1744     ERROR("Unlocking of thread failed!\n");
1745     display_error(n_error);
1746   }
1747 
1748   return &trv;
1749 }
1750 
1751 
1752 
context_manager(void)1753 static DXTOOLS_CONTEXT *context_manager(void)
1754 {
1755   FUNCNAME("contex_manager");
1756   int n_error;
1757   static pthread_t *thread = NULL;
1758   static DXTOOLS_CONTEXT *dxc = NULL;
1759 
1760   if(dxc) {
1761     /* Perform some checks before returning the context handle. */
1762 
1763     if(dxc->thread_running)
1764       return dxc;
1765     else
1766       WARNING("Something went wrong, thread no longer running.\n");
1767 
1768     if(thread)
1769       MEM_FREE(thread, 1, pthread_t);
1770     else
1771       ERROR("Thread object missing!\n");
1772 
1773 
1774     /* Now, after complaining, just initialize again. */
1775     /* This behavior could be changed, e.g. the thread might exit normally */
1776     /* after closing the last window. However, I do not expect the */
1777     /* running thread to consume many resources if no window is open. */
1778 
1779     MEM_FREE(dxc, 1, DXTOOLS_CONTEXT);
1780     dxc = NULL;
1781   }
1782 
1783   thread = MEM_CALLOC(1, pthread_t);
1784   if(!thread) {
1785     WARNING("Could not allocate thread object!\n");
1786     return NULL;
1787   }
1788 
1789   /* Perform necessary initialization of DX library. */
1790 
1791   DXInitModules();
1792 
1793   /* Create a context object. */
1794   dxc = MEM_CALLOC(1, DXTOOLS_CONTEXT);
1795   if(!dxc) {
1796     WARNING("Could not allocate context object!\n");
1797     return NULL;
1798   }
1799 
1800 
1801   n_error = pthread_mutex_init(&dxc->tlock, NULL);
1802   if(n_error) {
1803     WARNING("Initialization of mutex failed!\n");
1804     goto error_out;
1805   }
1806 
1807   n_error = pthread_cond_init(&dxc->windows_ready, NULL);
1808   if(n_error) {
1809     WARNING("Initialization of condition variable failed!\n");
1810     display_error(n_error);
1811     goto error_out;
1812   }
1813 
1814   n_error = pthread_cond_init(&dxc->block_context, NULL);
1815   if(n_error) {
1816     WARNING("Initialization of condition variable failed!\n");
1817     display_error(n_error);
1818     goto error_out;
1819   }
1820 
1821   /* Create a new thread for the context. Capture possible errors. */
1822 
1823   dxc->thread_running = true;
1824   n_error = pthread_create(thread, NULL, windows_thread, dxc);
1825 
1826   if(n_error) {
1827     WARNING("Creation of thread failed!\n");
1828     display_error(n_error);
1829     goto error_out;
1830   }
1831 
1832   return dxc;
1833 
1834  error_out:
1835 
1836   MEM_FREE(thread, 1, pthread_t);
1837   MEM_FREE(dxc, 1, DXTOOLS_CONTEXT);
1838   dxc = NULL;
1839   thread = NULL;
1840   return NULL;
1841 }
1842 
1843 
block_windows(DXTOOLS_CONTEXT * dxc)1844 static void block_windows(DXTOOLS_CONTEXT *dxc)
1845 {
1846   FUNCNAME("block_windows");
1847   int n_error;
1848 
1849   if(dxc->check_block_context) {
1850     MSG("*** Simulation blocked. Hit '%c' in any DXTOOLS window to unblock.\n",
1851 	DXTOOLS_KEY_BLOCK);
1852 
1853     n_error = pthread_cond_wait(&dxc->block_context, &dxc->tlock);
1854 
1855     if(n_error) {
1856       ERROR("Error occured while waiting for blocking window thread.\n");
1857       display_error(n_error);
1858     }
1859   }
1860 
1861   return;
1862 }
1863 
1864 
1865 
1866 /****************************************************************************/
1867 /* USER INTERFACE:                                                          */
1868 /****************************************************************************/
1869 
1870 
open_dxtools_window(const char * title,const char * geometry)1871 extern DXTOOLS_WINDOW *open_dxtools_window(const char *title,
1872 					   const char *geometry)
1873 {
1874   FUNCNAME("open_dxtools_window");
1875   DXTOOLS_CONTEXT     *dxc;
1876   DXTOOLS_WINDOW      *win = NULL;
1877   int    i, n_error;
1878   char   wtitle[170];
1879   struct timespec abstime = { 0, };
1880 
1881   /* Get a context manager and start the graphics thread. */
1882   if(!(dxc = context_manager()))
1883     return NULL;
1884 
1885   /* Lock the context manager. */
1886   n_error = pthread_mutex_lock(&dxc->tlock);
1887   if(n_error){
1888     ERROR("Locking of thread failed!\n");
1889     display_error(n_error);
1890     return NULL;
1891   }
1892 
1893 
1894   if(dxc->n_open_windows >= DXTOOLS_MAX_WINDOWS) {
1895     WARNING("Sorry, only %d DXTOOLS windows available!\n",
1896 	    DXTOOLS_MAX_WINDOWS);
1897     return(NULL);
1898   }
1899 
1900   /* Create a new DXTOOLS_WINDOW. */
1901 
1902   for(i = 0; i < DXTOOLS_MAX_WINDOWS; i++) {
1903     if(!dxc->win[i]) {
1904       dxc->win[i] = win = MEM_CALLOC(1, DXTOOLS_WINDOW);
1905 
1906       if(!win) {
1907 	WARNING("Unable to allocate DXTOOLS_WINDOW object!\n");
1908 	return(NULL);
1909       }
1910 
1911       dxc->n_open_windows++;
1912 
1913       break;
1914     }
1915   }
1916   DEBUG_TEST_EXIT(i < DXTOOLS_MAX_WINDOWS, "Inconsistency detected: n_open_windows was apparently small than the number of windows in use!\n");
1917 
1918 
1919 
1920   /* set window data */
1921 
1922   win->dxc    = dxc;
1923   win->number = i;
1924 
1925   GET_PARAMETER(0, "dxtools window use perspective", "%d",
1926 		&win->use_perspective);
1927   GET_PARAMETER(0, "dxtools window use hardware rendering", "%d",
1928 		&win->use_hardware);
1929 
1930   if (geometry)  {
1931     int w, h, x = 0, y = 0, size = 1;
1932     char *s;
1933 
1934     if (strchr(geometry, 'x')) {
1935       if ((s = strchr(geometry, '+'))) {
1936 	/*  "wwxhh+xx+yy"   */
1937 	if (strchr(s+1, '+')) sscanf(geometry, "%dx%d+%d+%d", &w, &h, &x, &y);
1938 	/*  "wwxhh+xx"      */
1939 	else {
1940 	  sscanf(geometry, "%dx%d+%d", &w, &h, &x);
1941 	  y = x;
1942 	}
1943       }
1944       /*  "wwxhh"         */
1945       else {
1946 	sscanf(geometry, "%dx%d", &w, &h);
1947       }
1948     }
1949     else {
1950       size = 0;
1951       if ((s = strchr(geometry, '+'))) {
1952 	/*  "xx+yy"         */
1953 	if (strchr(s+1, '+')) sscanf(s, "+%d+%d", &x, &y);
1954 	/*  "wwxhh+xx"      */
1955 	else {
1956 	  sscanf(s, "+%d", &x);
1957 	  y = x;
1958 	}
1959       }
1960     }
1961     if (size) {
1962       win->width = w;
1963       win->height = h;
1964     }
1965     win->offsetx = x;
1966     win->offsety = y;
1967   }
1968   else win->width = win->height = 500;
1969 
1970   win->draw_width = win->width;
1971   win->draw_height = win->height;
1972 
1973   /* create unique title */
1974   if (title)
1975     snprintf(wtitle, 170, "%s", title);     /* cut too long titles */
1976   else
1977     snprintf(wtitle, 170, "DXTOOLS Window [%d]", i+1);
1978 
1979   win->title = strdup(wtitle);
1980 
1981   /* trigger opening of this window. */
1982   win->open_me = true;
1983 
1984   /* Now wait until the window is ready. */
1985   /* Wait at most 60 seconds (time is money for numerical simulations) */
1986   n_error = clock_gettime(CLOCK_REALTIME, &abstime);
1987   if(n_error) {
1988     ERROR("Could not get absolute system time!\n");
1989     display_error(n_error);
1990     return NULL;
1991   }
1992 
1993   abstime.tv_sec += 60;
1994   while (win->open_me == true) {
1995     n_error = pthread_cond_timedwait(&dxc->windows_ready, &dxc->tlock,
1996 				     &abstime);
1997     if(n_error) {
1998       ERROR("Waiting for window opening failed!\n");
1999       display_error(n_error);
2000       return NULL;
2001     }
2002   }
2003 
2004   /* Now unlock context data */
2005   n_error = pthread_mutex_unlock(&dxc->tlock);
2006   if(n_error){
2007     ERROR("Unlocking of thread failed!\n");
2008     display_error(n_error);
2009   }
2010 
2011   return((DXTOOLS_WINDOW *) win);
2012 }
2013 
2014 
close_dxtools_window(DXTOOLS_WINDOW * win)2015 extern void close_dxtools_window(DXTOOLS_WINDOW *win)
2016 {
2017   FUNCNAME("close_dxtools_window");
2018   DXTOOLS_CONTEXT     *dxc;
2019   int                  i, n_error;
2020   struct timespec      abstime = { 0, };
2021 
2022 
2023   if (!win) return;
2024 
2025   dxc = win->dxc;
2026 
2027   /* Lock the context manager. */
2028   n_error = pthread_mutex_lock(&dxc->tlock);
2029   if(n_error){
2030     ERROR("Locking of thread failed!\n");
2031     display_error(n_error);
2032     return;
2033   }
2034 
2035   /* first check if the context is blocked. */
2036   block_windows(dxc);
2037 
2038   /* trigger thread to close the window */
2039   win->close_me = true;
2040 
2041   /* Now wait until the window is ready. */
2042   /* Wait at most 60 seconds (time is money for numerical simulations) */
2043   n_error = clock_gettime(CLOCK_REALTIME, &abstime);
2044   if(n_error) {
2045     ERROR("Could not get absolute system time!\n");
2046     display_error(n_error);
2047   }
2048 
2049   abstime.tv_sec += 60;
2050   while (win->close_me == true) {
2051     n_error = pthread_cond_timedwait(&dxc->windows_ready, &dxc->tlock,
2052 				     &abstime);
2053     if(n_error) {
2054       ERROR("Error occured while waiting for window to close.\n");
2055       display_error(n_error);
2056 
2057       /* We can not safely deallocate the DXTOOLS_WINDOW object */
2058       /* at this point, this could cause the graphics backround routines to */
2059       /* crash. We just set the dxc->win[i] pointer to NULL which will */
2060       /* cause this window to be ignored in the event loop. */
2061     }
2062   }
2063 
2064   /* Now update entries in the context. */
2065 
2066   for(i = 0; i < DXTOOLS_MAX_WINDOWS; i++) {
2067     if(win == dxc->win[i]) {
2068       if(!n_error) {
2069 	free(win->title);
2070 	MEM_FREE(win, 1, DXTOOLS_WINDOW);
2071       }
2072       dxc->win[i] = NULL;
2073       dxc->n_open_windows--;
2074 
2075       break;
2076     }
2077   }
2078   DEBUG_TEST_EXIT(i < DXTOOLS_MAX_WINDOWS, "Did not find window in list!\n");
2079 
2080   /* Unlock the context manager. */
2081   n_error = pthread_mutex_unlock(&dxc->tlock);
2082   if(n_error){
2083     ERROR("Unlocking of thread failed!\n");
2084     display_error(n_error);
2085   }
2086 
2087   return;
2088 }
2089 
2090 
2091 
2092 
create_field_components(MESH * mesh,const DOF_REAL_VEC * drv,const DOF_REAL_D_VEC * drdv,Array * coordinates,Array * connections,Array * data)2093 static int create_field_components(MESH *mesh, const DOF_REAL_VEC *drv,
2094 				   const DOF_REAL_D_VEC *drdv,
2095 				   Array *coordinates, Array *connections,
2096 				   Array *data)
2097 {
2098   FUNCNAME("create_field_components");
2099   TRAVERSE_STACK *stack = NULL;
2100   static const REAL_B vertex_bary[N_VERTICES_LIMIT] =
2101     {INIT_BARY_3D(1.0, 0.0, 0.0, 0.0),
2102      INIT_BARY_3D(0.0, 1.0, 0.0, 0.0),
2103      INIT_BARY_3D(0.0, 0.0, 1.0, 0.0),
2104      INIT_BARY_3D(0.0, 0.0, 0.0, 1.0)};
2105   float            coord[DIM_OF_WORLD], value;
2106   int              conn[N_VERTICES_MAX];
2107   const DOF_ADMIN *admin = NULL;
2108   FLAGS            adm_flags = ADM_FLAGS_DFLT;
2109   const EL_INFO   *el_info = NULL;
2110   DOF_INT_VEC     *dof_vert_ind = NULL;
2111   const FE_SPACE  *fe_space;
2112   PARAMETRIC      *parametric = NULL;
2113   int              dim, n0, nv, ne, i, j, *vert_ind = NULL;
2114   REAL            *data_vec = NULL;
2115   DOF              dof;
2116 
2117   /* Dimension */
2118   dim = mesh->dim;
2119 
2120   /* Create Arrays for coordinates, connections, and data */
2121   if(!(*coordinates = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1,DIM_OF_WORLD))) {
2122     display_dx_error();
2123     goto error_out;
2124   }
2125   if(!(*connections = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, dim+1))) {
2126     display_dx_error();
2127     goto error_out;
2128   }
2129   if(data) {
2130     if(drv)
2131       *data = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 1);
2132     else
2133       *data = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, DIM_OF_WORLD);
2134     if(!*data) {
2135       display_dx_error();
2136       goto error_out;
2137     }
2138   }
2139 
2140   /* allocate memory for coordinates, connections, and data */
2141   if(!DXAddArrayData(*coordinates, 0, mesh->n_vertices, NULL)) {
2142     display_dx_error();
2143     goto error_out;
2144   }
2145 
2146   if(!DXAddArrayData(*connections, 0, mesh->n_elements, NULL)) {
2147     display_dx_error();
2148     goto error_out;
2149   }
2150 
2151   if(data) {
2152     if(!DXAddArrayData(*data, 0, mesh->n_vertices, NULL)) {
2153       display_dx_error();
2154       goto error_out;
2155     }
2156     if(drv)
2157       data_vec = drv->vec;
2158     else if(drdv)
2159       data_vec = (REAL *)drdv->vec;
2160     else
2161       goto error_out;
2162 
2163     if(!data_vec)
2164       goto error_out;
2165   }
2166 
2167   if(drv)
2168     adm_flags = drv->fe_space->admin->flags;
2169   else if(drdv)
2170     adm_flags = drdv->fe_space->admin->flags;
2171 
2172   adm_flags &= ~ADM_PERIODIC;
2173 
2174   /* get dof_admin for vertex count */
2175   admin = get_vertex_admin(mesh, adm_flags);
2176   fe_space = get_dof_space(mesh, "vertex fe_space", admin->n_dof, admin->flags);
2177 
2178   /* get offset for the dofs */
2179   n0 = admin->n0_dof[VERTEX];
2180 
2181   /* pointer for parametric mesh */
2182   parametric = mesh->parametric;
2183 
2184   /* get dof vector for vertex indices and initialize with -1 */
2185   dof_vert_ind = get_dof_int_vec("vertex indices", fe_space);
2186   GET_DOF_VEC(vert_ind, dof_vert_ind);
2187   FOR_ALL_DOFS(admin, vert_ind[dof] = -1);
2188 
2189   nv = ne = 0;
2190   stack = get_traverse_stack();
2191 
2192   /*------------------------------------------------------------------------*/
2193   /* The first pass counts elements and vertices, checks these against the  */
2194   /* entries of mesh->n_elements, mesh->n_vertices, and fills coordinates   */
2195   /* and data.                                                              */
2196   /*------------------------------------------------------------------------*/
2197   for(el_info = traverse_first(stack, mesh, -1, CALL_LEAF_EL | FILL_COORDS);
2198       el_info;
2199       el_info = traverse_next(stack, el_info)) {
2200 
2201     if (parametric) {
2202       parametric->init_element(el_info, parametric);
2203       parametric->coord_to_world(el_info, NULL, N_VERTICES(dim),
2204 				 vertex_bary, (REAL_D *)el_info->coord);
2205     }
2206 
2207     for (i = 0; i < N_VERTICES(dim); i++) {
2208       dof = el_info->el->dof[i][n0];
2209       if (vert_ind[dof] == -1) {
2210 
2211 	/* assign a global index to each vertex */
2212         vert_ind[dof] = nv;
2213 
2214 	/* insert coordinate into the field (ATTENTION: must be float!) */
2215 	for (j = 0; j < DIM_OF_WORLD; j++)
2216 	  coord[j] = (float)el_info->coord[i][j];
2217 	if(!DXAddArrayData(*coordinates, nv, 1, coord)) {
2218 	  display_dx_error();
2219 	  goto error_out;
2220 	}
2221 
2222 	if(data_vec){
2223 	  if(drv)
2224 	    value = (float)data_vec[dof];
2225 	  else
2226 	    value = (float)data_vec[dof*DIM_OF_WORLD];
2227 
2228 	  if(!DXAddArrayData(*data, nv, 1, &value)) {
2229 	    display_dx_error();
2230 	    goto error_out;
2231 	  }
2232 	}
2233 
2234         nv++;
2235 
2236         if (nv>mesh->n_vertices)
2237 	  ERROR_EXIT("mesh %s: n_vertices (==%d) is too small!\n",
2238 		     mesh->name, mesh->n_vertices);
2239       }
2240     }
2241 
2242     ne++;
2243 
2244     if (ne>mesh->n_elements)
2245       ERROR_EXIT("mesh %s: n_elements (==%d) is too small!\n",
2246 		 mesh->name, mesh->n_elements);
2247   }
2248 
2249   if (ne<mesh->n_elements)
2250     ERROR_EXIT("mesh %s: n_elements (==%d) is too large!\n",
2251 	       mesh->name, mesh->n_elements, ne);
2252 
2253   if (nv<mesh->n_vertices)
2254     ERROR_EXIT("mesh %s: n_vertices (==%d) is too large\n",
2255 	       mesh->name, mesh->n_vertices, nv);
2256 
2257 
2258   ne = 0;
2259 
2260   /*------------------------------------------------------------------------*/
2261   /* The second pass fills connections                                      */
2262   /*------------------------------------------------------------------------*/
2263   for(el_info = traverse_first(stack, mesh, -1, CALL_LEAF_EL);
2264       el_info;
2265       el_info = traverse_next(stack, el_info)) {
2266 
2267     for (i = 0; i < N_VERTICES(dim); i++)
2268       conn[i] = vert_ind[el_info->el->dof[i][n0]];
2269     if(!DXAddArrayData(*connections, ne, 1, conn)) {
2270       display_dx_error();
2271       goto error_out;
2272     }
2273 
2274     ne++;
2275   }
2276 
2277   free_dof_int_vec(dof_vert_ind);
2278   free_fe_space(fe_space);
2279   free_traverse_stack(stack);
2280 
2281   return false;
2282 
2283  error_out:
2284   if(dof_vert_ind) {
2285     free_dof_int_vec(dof_vert_ind);
2286     free_fe_space(fe_space);
2287   }
2288   if(stack)
2289     free_traverse_stack(stack);
2290 
2291   return true;
2292 }
2293 
2294 
2295 
2296 
2297 
dxtools_mesh(DXTOOLS_WINDOW * win,MESH * mesh)2298 extern void dxtools_mesh(DXTOOLS_WINDOW *win, MESH *mesh)
2299 {
2300   FUNCNAME("dxtool_mesh");
2301   DXTOOLS_CONTEXT *dxc = win->dxc;
2302   int              dim, n_error = 0;
2303   REAL             tube_size_real = 0.0;
2304   float            tube_size = 0.0;
2305   Array            coordinates = NULL, connections = NULL;
2306   Field            mf = NULL;
2307   ModuleInput      minput[10];
2308   ModuleOutput     moutput[10];
2309   dxObject         connectionsobject = NULL, displayobject = NULL;
2310 
2311 
2312   if (!mesh || !win)  return;
2313 
2314   /* Set the tube size */
2315   GET_PARAMETER(0, "dxtools mesh tube size", "%f", &tube_size_real);
2316   tube_size = MAX(0.0, (float)tube_size_real);
2317 
2318   /* Dimension */
2319   dim = mesh->dim;
2320 
2321   /* lock thread data */
2322   n_error = pthread_mutex_lock(&dxc->tlock);
2323   if(n_error){
2324     ERROR("Locking of thread failed!\n");
2325     display_error(n_error);
2326   }
2327 
2328   /* first check if the context is blocked. */
2329   block_windows(dxc);
2330 
2331   if(create_field_components(mesh, NULL, NULL, &coordinates, &connections, NULL))
2332     goto error_out;
2333 
2334   /* Create a new field and insert the Array Data */
2335   if(!(mf = DXNewField())) {
2336     display_dx_error();
2337     goto error_out;
2338   }
2339 
2340   DXSetComponentValue(mf, "positions", (dxObject)coordinates);
2341   DXSetComponentValue(mf, "connections", (dxObject)connections);
2342 
2343   switch(dim) {
2344   case 1:
2345     DXSetComponentAttribute(mf, "connections", "element type",
2346 			    (dxObject)DXNewString("lines"));
2347     break;
2348   case 2:
2349     DXSetComponentAttribute(mf, "connections", "element type",
2350 			    (dxObject)DXNewString("triangles"));
2351     break;
2352   case 3:
2353     DXSetComponentAttribute(mf, "connections", "element type",
2354 			    (dxObject)DXNewString("tetrahedra"));
2355     break;
2356   default:
2357     ERROR_EXIT("Bad dimension?\n");
2358   }
2359 
2360   if(!DXEndField(mf)) {
2361     display_dx_error();
2362     goto error_out;
2363   }
2364 
2365 
2366 
2367 
2368   /* Create Connections of the field data */
2369   DXModSetObjectInput(&minput[0], "input", (dxObject)mf);
2370   DXModSetObjectOutput(&moutput[0], "output", &connectionsobject);
2371   if(!DXCallModule("ShowConnections", 1, minput, 1, moutput))
2372     goto error_out;
2373 
2374 
2375   if(tube_size > 0.0) {
2376     /* Draw connections as a tube */
2377     DXModSetObjectInput(&minput[0], "line", connectionsobject);
2378     DXModSetFloatInput(&minput[1], "diameter", tube_size);
2379     DXModSetObjectOutput(&moutput[0], "tube", &displayobject);
2380     if(!DXCallModule("Tube", 2, minput, 1, moutput))
2381       goto error_out;
2382   }
2383   else {
2384     /* Draw connections as plain lines */
2385     displayobject = connectionsobject;
2386   }
2387 
2388   /* Delete possible colormap objects. */
2389   if(win->colormap) {
2390     if(!DXDelete((dxObject)win->colormap))
2391       display_dx_error();
2392     win->colormap = NULL;
2393   }
2394 
2395   /* Setting new object for the window */
2396   if(win->displayobject && !DXDelete(win->displayobject))
2397     display_dx_error();
2398   win->displayobject = displayobject;
2399 
2400   win->type = DXTOOLS_MESH;
2401   win->dim  = dim;
2402   win->redraw_me = true;
2403 
2404   /* Unlock thread data */
2405   pthread_mutex_unlock(&dxc->tlock);
2406   if(n_error){
2407     ERROR("Unlocking of thread failed!\n");
2408     display_error(n_error);
2409   }
2410 
2411   return;
2412 
2413  error_out:
2414   WARNING("Mesh not displayed.\n");
2415   return;
2416 }
2417 
2418 
2419 
dxtools_drv(DXTOOLS_WINDOW * win,const DOF_REAL_VEC * u)2420 extern void dxtools_drv(DXTOOLS_WINDOW *win, const DOF_REAL_VEC *u)
2421 {
2422   FUNCNAME("dxtools_drv");
2423   DXTOOLS_CONTEXT *dxc = win->dxc;
2424   MESH            *mesh;
2425   int              mode_rubber_sheet = 0, mode_color = 1, dim, n_error = 0;
2426   int              mode_glyph = 0;
2427   Array            coordinates = NULL, connections = NULL;
2428   Array            data = NULL;
2429   Field            colormap = NULL, mf = NULL, tmp_mf = NULL;
2430   ModuleInput      minput[10];
2431   ModuleOutput     moutput[10];
2432 
2433 
2434   if (!u || !win)  return;
2435 
2436   if(!strstr(u->fe_space->bas_fcts->name, "lagrange")) {
2437     WARNING("Only implemented for Lagrange Finite Elements!\n");
2438     goto error_out;
2439   }
2440 
2441 
2442   /* Dimension */
2443   mesh = u->fe_space->mesh;
2444   dim = mesh->dim;
2445 
2446   /* lock thread data */
2447   n_error = pthread_mutex_lock(&dxc->tlock);
2448   if(n_error){
2449     ERROR("Locking of thread failed!\n");
2450     display_error(n_error);
2451   }
2452 
2453   /* first check if the context is blocked. */
2454   block_windows(dxc);
2455 
2456   if(create_field_components(mesh, u, NULL,
2457 			     &coordinates, &connections, &data))
2458     goto error_out;
2459 
2460 
2461   /* Create a new field and insert the Array Data */
2462   if(!(mf = DXNewField())) {
2463     display_dx_error();
2464     goto error_out;
2465   }
2466 
2467   DXSetComponentValue(mf, "positions", (dxObject)coordinates);
2468   DXSetComponentValue(mf, "connections", (dxObject)connections);
2469   DXSetComponentValue(mf, "data", (dxObject)data);
2470 
2471   switch(dim) {
2472   case 1:
2473     DXSetComponentAttribute(mf, "connections", "element type",
2474 			    (dxObject)DXNewString("lines"));
2475     break;
2476   case 2:
2477     DXSetComponentAttribute(mf, "connections", "element type",
2478 			    (dxObject)DXNewString("triangles"));
2479     break;
2480   case 3:
2481     DXSetComponentAttribute(mf, "connections", "element type",
2482 			    (dxObject)DXNewString("tetrahedra"));
2483     break;
2484   default:
2485     ERROR_EXIT("Bad dimension?\n");
2486   }
2487 
2488   if(!DXEndField(mf)) {
2489     display_dx_error();
2490     goto error_out;
2491   }
2492 
2493 
2494   GET_PARAMETER(0, "dxtools data use RubberSheet", "%d", &mode_rubber_sheet);
2495   GET_PARAMETER(0, "dxtools data use AutoColor", "%d", &mode_color);
2496   GET_PARAMETER(0, "dxtools data use AutoGlyph", "%d", &mode_glyph);
2497 
2498   /* Enable the DX "rubber sheet" effect, which is basically just a */
2499   /* 1/2D plot of data values as height over the mesh. */
2500 
2501   if (mode_rubber_sheet == 1) {
2502     if(dim == 3) {
2503       WARNING("Rubber sheet display mode is only available for 2D meshes.\n");
2504       mode_rubber_sheet = 0;
2505     }
2506     else {
2507       DXModSetObjectInput(&minput[0], "data", (dxObject)mf);
2508       DXModSetFloatInput(&minput[1], "scale", 1.0f);
2509       DXModSetObjectOutput(&moutput[0], "graph", (dxObject *)(void *)&tmp_mf);
2510       if(!DXCallModule("RubberSheet", 2, minput, 1, moutput)) {
2511 	display_dx_error();
2512 	goto error_out;
2513       }
2514       mf = tmp_mf;
2515     }
2516   }
2517 
2518   /* The rubber sheet and glyph effects add color, so AutoColor is not */
2519   /* always needed. */
2520   if((mode_color == 1) || (mode_rubber_sheet == 0)) {
2521     DXModSetObjectInput(&minput[0], "data", (dxObject)mf);
2522     DXModSetObjectOutput(&moutput[0], "mapped", (dxObject *)(void *)&tmp_mf);
2523     DXModSetObjectOutput(&moutput[1], "colormap", (dxObject *)(void *)&colormap);
2524     if(!DXCallModule("AutoColor", 1, minput, 2, moutput)) {
2525       display_dx_error();
2526       goto error_out;
2527     }
2528     mf = tmp_mf;
2529   }
2530 
2531   /* Apply glyphs, if desired. This includes arrows, textual display of */
2532   /* values, etc. */
2533   if(mode_glyph) {
2534     int  n_in = 0;
2535     char glyph_type[20] = { 0, };
2536     GET_PARAMETER(0, "dxtools data AutoGlyph type", "%s", glyph_type);
2537 
2538 
2539     DXModSetObjectInput(&minput[n_in++], "data", (dxObject)mf);
2540     if(strlen(glyph_type)) {
2541       if(strcmp(glyph_type, "colortext"))
2542 	DXModSetStringInput(&minput[n_in++], "type", glyph_type);
2543       else
2544 	DXModSetStringInput(&minput[n_in++], "type", "colored text");
2545     }
2546 
2547     DXModSetObjectOutput(&moutput[0], "glyphs", (dxObject *)(void *)&tmp_mf);
2548     if(!DXCallModule("AutoGlyph", n_in, minput, 1, moutput)) {
2549       display_dx_error();
2550       goto error_out;
2551     }
2552     mf = tmp_mf;
2553   }
2554 
2555 
2556   /* Set new colormap for the object. */
2557   if(colormap) {
2558     if(win->colormap && !DXDelete((dxObject)win->colormap))
2559       display_dx_error();
2560     win->colormap = colormap;
2561   }
2562 
2563   /* Setting new object for the window */
2564   if(win->displayobject && !DXDelete(win->displayobject))
2565     display_dx_error();
2566   win->displayobject = (dxObject)mf;
2567 
2568   win->type = DXTOOLS_FEVECTOR;
2569   win->dim  = dim;
2570   win->redraw_me = true;
2571 
2572   /* Unlock thread data */
2573   n_error = pthread_mutex_unlock(&dxc->tlock);
2574   if(n_error){
2575     ERROR("Unlocking of thread failed!\n");
2576     display_error(n_error);
2577   }
2578 
2579   return;
2580 
2581  error_out:
2582   WARNING("Vector not displayed.\n");
2583   return;
2584 
2585 
2586 }
2587 
dxtools_drdv(DXTOOLS_WINDOW * win,const DOF_REAL_D_VEC * u)2588 extern void dxtools_drdv(DXTOOLS_WINDOW *win, const DOF_REAL_D_VEC *u)
2589 {
2590   FUNCNAME("dxtools_drdv");
2591   DXTOOLS_CONTEXT *dxc = win->dxc;
2592   MESH            *mesh;
2593   int              mode_rubber_sheet = 0, mode_color = 1, dim, n_error = 0;
2594   int              mode_glyph = 0;
2595   Array            coordinates = NULL, connections = NULL;
2596   Array            data = NULL;
2597   Field            colormap = NULL, mf = NULL, tmp_mf = NULL;
2598   ModuleInput      minput[10];
2599   ModuleOutput     moutput[10];
2600 
2601 
2602   if (!u || !win)  return;
2603 
2604   if(!strstr(u->fe_space->bas_fcts->name, "lagrange")) {
2605     WARNING("Only implemented for Lagrange Finite Elements!\n");
2606     goto error_out;
2607   }
2608 
2609 
2610   /* Dimension */
2611   mesh = u->fe_space->mesh;
2612   dim = mesh->dim;
2613 
2614   /* lock thread data */
2615   n_error = pthread_mutex_lock(&dxc->tlock);
2616   if(n_error){
2617     ERROR("Locking of thread failed!\n");
2618     display_error(n_error);
2619   }
2620 
2621   /* first check if the context is blocked. */
2622   block_windows(dxc);
2623 
2624   if(create_field_components(mesh, NULL, u,
2625 			     &coordinates, &connections, &data))
2626     goto error_out;
2627 
2628 
2629   /* Create a new field and insert the Array Data */
2630   if(!(mf = DXNewField())) {
2631     display_dx_error();
2632     goto error_out;
2633   }
2634 
2635   DXSetComponentValue(mf, "positions", (dxObject)coordinates);
2636   DXSetComponentValue(mf, "connections", (dxObject)connections);
2637   DXSetComponentValue(mf, "data", (dxObject)data);
2638 
2639   switch(dim) {
2640   case 1:
2641     DXSetComponentAttribute(mf, "connections", "element type",
2642 			    (dxObject)DXNewString("lines"));
2643     break;
2644   case 2:
2645     DXSetComponentAttribute(mf, "connections", "element type",
2646 			    (dxObject)DXNewString("triangles"));
2647     break;
2648   case 3:
2649     DXSetComponentAttribute(mf, "connections", "element type",
2650 			    (dxObject)DXNewString("tetrahedra"));
2651     break;
2652   default:
2653     ERROR_EXIT("Bad dimension?\n");
2654   }
2655 
2656   if(!DXEndField(mf)) {
2657     display_dx_error();
2658     goto error_out;
2659   }
2660 
2661 
2662   GET_PARAMETER(0, "dxtools data use RubberSheet", "%d", &mode_rubber_sheet);
2663   GET_PARAMETER(0, "dxtools data use AutoColor", "%d", &mode_color);
2664   GET_PARAMETER(0, "dxtools data use AutoGlyph", "%d", &mode_glyph);
2665 
2666   /* Enable the DX "rubber sheet" effect, which is basically just a */
2667   /* 1/2D plot of data values as height over the mesh. */
2668 
2669   if (mode_rubber_sheet == 1) {
2670     if(dim == 3) {
2671       WARNING("Rubber sheet display mode is only available for 2D meshes.\n");
2672       mode_rubber_sheet = 0;
2673     }
2674     else {
2675       DXModSetObjectInput(&minput[0], "data", (dxObject)mf);
2676       DXModSetFloatInput(&minput[1], "scale", 1.0f);
2677       DXModSetObjectOutput(&moutput[0], "graph", (dxObject *)(void *)&tmp_mf);
2678       if(!DXCallModule("RubberSheet", 2, minput, 1, moutput)) {
2679 	display_dx_error();
2680 	goto error_out;
2681       }
2682       mf = tmp_mf;
2683     }
2684   }
2685 
2686   /* The rubber sheet and glyph effects add color, so AutoColor is not */
2687   /* always needed. */
2688   if((mode_color == 1) || (mode_rubber_sheet == 0)) {
2689     DXModSetObjectInput(&minput[0], "data", (dxObject)mf);
2690     DXModSetObjectOutput(&moutput[0], "mapped", (dxObject *)(void *)&tmp_mf);
2691     DXModSetObjectOutput(&moutput[1], "colormap", (dxObject *)(void *)&colormap);
2692     if(!DXCallModule("AutoColor", 1, minput, 2, moutput)) {
2693       display_dx_error();
2694       goto error_out;
2695     }
2696     mf = tmp_mf;
2697   }
2698 
2699   /* Apply glyphs, if desired. This includes arrows, textual display of */
2700   /* values, etc. */
2701   if(mode_glyph) {
2702     int  n_in = 0;
2703     char glyph_type[20] = { 0, };
2704     GET_PARAMETER(0, "dxtools data AutoGlyph type", "%s", glyph_type);
2705 
2706 
2707     DXModSetObjectInput(&minput[n_in++], "data", (dxObject)mf);
2708     if(strlen(glyph_type)) {
2709       if(strcmp(glyph_type, "colortext"))
2710 	DXModSetStringInput(&minput[n_in++], "type", glyph_type);
2711       else
2712 	DXModSetStringInput(&minput[n_in++], "type", "colored text");
2713     }
2714 
2715     DXModSetObjectOutput(&moutput[0], "glyphs", (dxObject *)(void *)&tmp_mf);
2716     if(!DXCallModule("AutoGlyph", n_in, minput, 1, moutput)) {
2717       display_dx_error();
2718       goto error_out;
2719     }
2720     mf = tmp_mf;
2721   }
2722 
2723 
2724   /* Set new colormap for the object. */
2725   if(colormap) {
2726     if(win->colormap && !DXDelete((dxObject)win->colormap))
2727       display_dx_error();
2728     win->colormap = colormap;
2729   }
2730 
2731   /* Setting new object for the window */
2732   if(win->displayobject && !DXDelete(win->displayobject))
2733     display_dx_error();
2734   win->displayobject = (dxObject)mf;
2735 
2736   win->type = DXTOOLS_FEVECTOR;
2737   win->dim  = dim;
2738   win->redraw_me = true;
2739 
2740   /* Unlock thread data */
2741   n_error = pthread_mutex_unlock(&dxc->tlock);
2742   if(n_error){
2743     ERROR("Unlocking of thread failed!\n");
2744     display_error(n_error);
2745   }
2746 
2747   return;
2748 
2749  error_out:
2750   WARNING("Vector not displayed.\n");
2751   return;
2752 
2753 
2754 }
2755