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