1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12
13 #ifdef OS2
14 #include <stdlib.h>
15 #include <types.h>
16 #endif
17
18 #include <X11/Intrinsic.h>
19 #include <X11/IntrinsicP.h>
20 #include <X11/Xutil.h>
21 #include <X11/Xlib.h>
22 #include <X11/Xatom.h>
23 #include <X11/Shell.h>
24 #include <X11/keysym.h>
25 #if defined(aviion)
26 #include <X11/Xos.h> /* definitions for time variables */
27 #endif
28 #include <Xm/DrawingA.h>
29 #include <Xm/Xm.h>
30 #include <Xm/XmP.h>
31 #include <math.h>
32 #include <float.h>
33 #if defined(HAVE_SYS_TIME_H)
34 #include <sys/time.h>
35 #endif
36 #include "../widgets/FFloat.h"
37 #include "../widgets/Image.h"
38 #include "../widgets/ImageP.h"
39 #include "../widgets/Picture.h"
40 #include "../widgets/PictureP.h"
41
42 #define SCALE .85
43
44 /* External Functions */
45 void find_color(Widget w, XColor *target); /* From findcolor.c */
46 void gamma_correct(XColor *cell_def); /* From gamma.c */
47
48 /* Local Functions */
49
50 static void alloc_drawing_colors(XmPictureWidget w);
51 static void convert_color(XmPictureWidget w, XColor *color);
52 static int delete_cursor ( XmPictureWidget w, int id );
53 static int select_cursor ( XmPictureWidget w , int id);
54 static int deselect_cursor (XmPictureWidget w);
55 static int constrain( XmPictureWidget w, double *s0, double *s1 ,double *s2,
56 double dx, double dy, double dz,
57 double WItrans[4][4], double Wtrans[4][4],
58 int sdx, int sdy );
59 static int add2historybuffer(XmPictureWidget w, int x, int y);
60 static void generate_globe(XmPictureWidget w, double radi);
61 static void keyboard_grab(XmPictureWidget w, Boolean grab);
62 static void restore_rectangle(XmPictureWidget w);
63 static void erase_image(XmPictureWidget w);
64 static double line_of_sight();
65 static void setup_bounding_box(XmPictureWidget w);
66 static void calc_projected_axis(XmPictureWidget w);
67 static void setup_gnomon(XmPictureWidget w, Boolean rotate);
68 static void draw_gnomon (XmPictureWidget w);
69 static void restore_cursors_from_canonical_form (XmPictureWidget w);
70 static void save_cursors_in_canonical_form (XmPictureWidget w, int i);
71 static void draw_rotated_gnomon(XmPictureWidget w);
72 static void create_cursor_pixmaps(XmPictureWidget new);
73 static int create_cursor (XmPictureWidget w);
74 static void XmDrawBbox (XmPictureWidget w);
75 static void XmDrawGlobe (XmPictureWidget w);
76 static void CallCursorCallbacks(XmPictureWidget w, int reason, int cursor_num,
77 double screen_x, double screen_y, double screen_z);
78 static void CallNavigateCallbacks(XmPictureWidget w,
79 int screen_x, int screen_y, int reason);
80 XtTimerCallbackProc ButtonTimeOut( XmPictureWidget w, XtIntervalId *id);
81 XtTimerCallbackProc AutoRepeatTimer( XmPictureWidget w, XtIntervalId *id);
82 static void draw_arrow_head(XmPictureWidget w, int x, int y,
83 int center_x, int center_y);
84 static Boolean trivial_reject(XmPictureWidget w,
85 double x1, double y1, double z1,
86 double x2, double y2, double z2,
87 double sod_width, double sod_height);
88 static Boolean clip_line(XmPictureWidget w, double x1, double y1, double z1,
89 double x2, double y2, double z2,
90 double sod_width, double sod_height,
91 double *new_x1, double *new_y1, double *new_z1,
92 double *new_x2, double *new_y2, double *new_z2);
93 static void
94 XmPictureMoveCamera( XmPictureWidget w,
95 double Wtrans[4][4],
96 double *from_newx, double *from_newy, double *from_newz,
97 double *up_newx, double *up_newy, double *up_newz);
98
99
100 static int inverse(), mult44();
101 static double cofac(), det33() ;
102 static int find_closest(), draw_cursors();
103 static int set_rot ( double res[4][4], double s0, short s1 );
104 static int I44(double w[4][4]);
105 static int set_trans(double res[4][4] , double s0, short s1);
106 int draw_marker ( XmPictureWidget w );
107 int project ( XmPictureWidget w, double s0, double s1 ,double s2,
108 double Wtrans[4][4], double WItrans[4][4] );
109 int move_selected_cursor ( XmPictureWidget w, int x, int y, double z );
110
111
112 #define superclass (&xmImageClassRec)
113 #if !defined(HAS_M_PI)
114 #define M_PI 3.1415926535897931160E0
115 #endif
116 #define COS05 0.996
117 #define SIN15 0.259
118 #define COS15 0.966
119 #define SIN25 0.423
120 #define COS25 0.906
121 #define SIN45 0.707
122 #define SIN35 0.574
123
124 static void Initialize( XmPictureWidget request, XmPictureWidget new );
125 static Boolean SetValues( XmPictureWidget current,
126 XmPictureWidget request,
127 XmPictureWidget new );
128
129 static void ClassInitialize();
130 static void Destroy();
131
132 static void Select();
133 static void Deselect();
134 static void CreateDelete();
135 static void BtnMotion();
136 static void KeyProc();
137 #if 0
138 static void KeyMode();
139 #endif
140 static void ServerMessage (XmPictureWidget w, XEvent *event);
141 static void PropertyNotifyAR (XmPictureWidget w, XEvent *event);
142 static void Realize();
143 static void Redisplay (XmPictureWidget ww,
144 XExposeEvent* event,
145 Region region);
146 static void Resize( XmPictureWidget w );
147 static void
148 xform_coords( double Wtrans[4][4],
149 double x, double y, double z,
150 double *newx, double *newy, double *newz);
151
152 static void
153 perspective_divide( XmPictureWidget w,
154 double x, double y, double z, double *newx, double *newy);
155
156 static void
157 perspective_divide_inverse( XmPictureWidget w,
158 double x, double y, double z, double *newx, double *newy);
159 static void push_redo_camera(XmPictureWidget w);
160 static void push_undo_camera(XmPictureWidget w);
161
162 /* Default translation table and action list */
163 #if (XmVersion < 1001)
164 static char defaultTranslations[] =
165 "<BtnDown>: Select()\n\
166 <BtnUp>: Deselect()\n\
167 <BtnMotion>: BtnMotion()\n\
168 <Key>Right: KeyAct()\n\
169 <Key>Left: KeyAct()\n\
170 <Key>Up: KeyAct()\n\
171 <Key>Down: KeyAct()\n\
172 <KeyUp>Right: KeyAct()\n\
173 <KeyUp>Left: KeyAct()\n\
174 <KeyUp>Up: KeyAct()\n\
175 <KeyUp>Down: KeyAct()\n\
176 <ClientMessage>: ClientMessage()\n\
177 <PropertyNotify>: PropertyNotify()";
178 #else
179 static char defaultTranslations[] =
180 "<BtnDown>: Select()\n\
181 <BtnUp>: Deselect()\n\
182 <BtnMotion>: BtnMotion()\n\
183 <Key>osfRight: KeyAct()\n\
184 <Key>osfLeft: KeyAct()\n\
185 <Key>osfUp: KeyAct()\n\
186 <Key>osfDown: KeyAct()\n\
187 <KeyUp>osfRight: KeyAct()\n\
188 <KeyUp>osfLeft: KeyAct()\n\
189 <KeyUp>osfUp: KeyAct()\n\
190 <KeyUp>osfDown: KeyAct()\n\
191 <ClientMessage>: ClientMessage()\n\
192 <PropertyNotify>: PropertyNotify()";
193 #endif
194
195 /*
196 Ctrl<Key>I: KeyMode()\n\
197 Ctrl<Key>G: KeyMode()\n\
198 Ctrl<Key>F: KeyMode()\n\
199 Ctrl<Key>W: KeyMode()\n\
200 Ctrl<Key>X: KeyMode()\n\
201 Ctrl<Key>R: KeyMode()\n\
202 Ctrl<Key>Z: KeyMode()\n\
203 Ctrl<Key>N: KeyMode()\n\
204 Ctrl<Key>U: KeyMode()\n\
205 Ctrl<Key>K: KeyMode()\n\
206
207 Ctrl<Key>I: KeyMode()\n\
208 Ctrl<Key>G: KeyMode()\n\
209 Ctrl<Key>F: KeyMode()\n\
210 Ctrl<Key>W: KeyMode()\n\
211 Ctrl<Key>X: KeyMode()\n\
212 Ctrl<Key>R: KeyMode()\n\
213 Ctrl<Key>Z: KeyMode()\n\
214 Ctrl<Key>N: KeyMode()\n\
215 Ctrl<Key>U: KeyMode()\n\
216 Ctrl<Key>K: KeyMode()\n\
217 */
218
219 static XtActionsRec actionsList[] =
220 {
221 { "Select", (XtActionProc) Select },
222 { "Deselect", (XtActionProc) Deselect },
223 { "BtnMotion", (XtActionProc) BtnMotion },
224 { "KeyAct", (XtActionProc) KeyProc },
225 /* { "KeyMode", (XtActionProc) KeyMode }, */
226 { "ClientMessage", (XtActionProc) ServerMessage },
227 { "PropertyNotify",(XtActionProc) PropertyNotifyAR },
228 };
229
230
231 extern void _XmForegroundColorDefault();
232 extern void _XmBackgroundColorDefault();
233
234 static double DefaultAngle = 0.0;
235
236 static XtResource resources[] =
237 {
238 {
239 XmNdisplayGlobe, XmCDisplayGlobe, XmRBoolean, sizeof(Boolean),
240 XtOffset(XmPictureWidget, picture.display_globe),
241 XmRImmediate, (XtPointer) False
242 },
243 {
244 XmNlookAtAngle, XmCLookAtAngle, XmRDouble, sizeof(double),
245 XtOffset(XmPictureWidget, picture.look_at_angle),
246 XmRDouble, (XtPointer) &DefaultAngle
247 },
248 {
249 XmNlookAtDirection, XmCLookAtDirection, XmRInt, sizeof(int),
250 XtOffset(XmPictureWidget, picture.look_at_direction),
251 XmRImmediate, (XtPointer)XmLOOK_FORWARD
252 },
253 {
254 XmNnavigateDirection, XmCNavigateDirection, XmRInt, sizeof(int),
255 XtOffset(XmPictureWidget, picture.navigate_direction),
256 XmRImmediate, XmFORWARD
257 },
258 {
259 XmNtranslateSpeed, XmCTranslateSpeed, XmRInt, sizeof(int),
260 XtOffset(XmPictureWidget, picture.translate_speed_factor),
261 XmRImmediate, (XtPointer)25
262 },
263 {
264 XmNrotateSpeed, XmCRotateSpeed, XmRInt, sizeof(int),
265 XtOffset(XmPictureWidget, picture.rotate_speed_factor),
266 XmRImmediate, (XtPointer)25
267 },
268 {
269 XmNconstrainCursor, XmCConstrainCursor, XmRInt, sizeof(int),
270 XtOffset(XmPictureWidget, picture.constrain_cursor),
271 XmRInt, XmCONSTRAIN_NONE
272 },
273 { XmNoverlayExposure, XmCOverlayExposure, XmRBoolean, sizeof(Boolean),
274 XtOffset(XmPictureWidget, picture.overlay_exposure),
275 XmRImmediate, (XtPointer) FALSE
276 },
277 {
278 XmNoverlayWid, XmCOverlayWid, XmRWindow, sizeof(Window),
279 XtOffset(XmPictureWidget, picture.overlay_wid),
280 XmRImmediate, NULL
281 },
282 {
283 XmNpicturePixmap, XmCPicturePixmap, XmRPixmap, sizeof(Pixmap),
284 XtOffset(XmPictureWidget, picture.pixmap),
285 XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP
286 },
287 {
288 XmNmode, XmCMode, XmRInt, sizeof(int),
289 XtOffset(XmPictureWidget, picture.mode),
290 XmRInt, XmNULL_MODE
291 },
292 { XmNshowRotatingBBox, XmCShowRotatingBBox, XmRBoolean, sizeof(Boolean),
293 XtOffset(XmPictureWidget, picture.show_rotating_bbox),
294 XmRImmediate, (XtPointer) FALSE
295 },
296 { XmNnewImage, XmCNewImage, XmRBoolean, sizeof(Boolean),
297 XtOffset(XmPictureWidget, picture.new_image),
298 XmRImmediate, (XtPointer) FALSE
299 },
300 {
301 XmNcursorShape, XmCCursorShape, XmRInt, sizeof(int),
302 XtOffset(XmPictureWidget, picture.cursor_shape),
303 XmRInt, XmSQUARE
304 },
305 {
306 XmNglobeRadius, XmCGlobeRadius, XmRInt, sizeof(int),
307 XtOffset(XmPictureWidget, picture.globe_radius),
308 XmRImmediate, (XtPointer)50
309 },
310 {
311 XmNpictureCursorSize, XmCPictureCursorSize, XmRInt, sizeof(int),
312 XtOffset(XmPictureWidget, picture.cursor_size),
313 XmRImmediate, (XtPointer)5
314 },
315 {
316 XmNpictureCursorSpeed, XmCPictureCursorSpeed, XmRInt, sizeof(int),
317 XtOffset(XmPictureWidget, picture.cursor_speed),
318 XmRImmediate, (XtPointer)XmMEDIUM_CURSOR
319 },
320 {
321 XmNcursorCallback, XmCCallback, XmRCallback,
322 sizeof (XtCallbackList),
323 XtOffset (XmPictureWidget, picture.cursor_callback),
324 XmRImmediate, (XtPointer) NULL
325 },
326 {
327 XmNpickCallback, XmCCallback, XmRCallback,
328 sizeof (XtCallbackList),
329 XtOffset (XmPictureWidget, picture.pick_callback),
330 XmRImmediate, (XtPointer) NULL
331 },
332 {
333 XmNmodeCallback, XmCCallback, XmRCallback,
334 sizeof (XtCallbackList),
335 XtOffset (XmPictureWidget, picture.mode_callback),
336 XmRImmediate, (XtPointer) NULL
337 },
338 {
339 XmNundoCallback, XmCCallback, XmRCallback,
340 sizeof (XtCallbackList),
341 XtOffset (XmPictureWidget, picture.undo_callback),
342 XmRImmediate, (XtPointer) NULL
343 },
344 {
345 XmNkeyCallback, XmCCallback, XmRCallback,
346 sizeof (XtCallbackList),
347 XtOffset (XmPictureWidget, picture.key_callback),
348 XmRImmediate, (XtPointer) NULL
349 },
350 {
351 XmNrotationCallback, XmCCallback, XmRCallback,
352 sizeof (XtCallbackList),
353 XtOffset (XmPictureWidget, picture.rotation_callback),
354 XmRImmediate, (XtPointer) NULL
355 },
356 {
357 XmNzoomCallback, XmCCallback, XmRCallback,
358 sizeof (XtCallbackList),
359 XtOffset (XmPictureWidget, picture.zoom_callback),
360 XmRImmediate, (XtPointer) NULL
361 },
362 {
363 XmNroamCallback, XmCCallback, XmRCallback,
364 sizeof (XtCallbackList),
365 XtOffset (XmPictureWidget, picture.roam_callback),
366 XmRImmediate, (XtPointer) NULL
367 },
368 {
369 XmNnavigateCallback, XmCCallback, XmRCallback,
370 sizeof (XtCallbackList),
371 XtOffset (XmPictureWidget, picture.navigate_callback),
372 XmRImmediate, (XtPointer) NULL
373 },
374 {
375 XmNclientMessageCallback, XmCCallback, XmRCallback,
376 sizeof (XtCallbackList),
377 XtOffset (XmPictureWidget, picture.client_message_callback),
378 XmRImmediate, (XtPointer) NULL
379 },
380 {
381 XmNpropertyNotifyCallback, XmCCallback, XmRCallback,
382 sizeof (XtCallbackList),
383 XtOffset (XmPictureWidget, picture.property_notify_callback),
384 XmRImmediate, (XtPointer) NULL
385 },
386 };
387
388 /****************************************************************
389 *
390 * Full class record constant
391 *
392 ****************************************************************/
393
394 XmPictureClassRec xmPictureClassRec =
395 {
396 { /* core_class fields */
397 (WidgetClass) &xmImageClassRec, /* superclass */
398 "XmPicture", /* class_name */
399 sizeof(XmPictureRec), /* widget_size */
400 ClassInitialize, /* class_initialize */
401 NULL, /* class_part_init */
402 FALSE, /* class_inited */
403 (XtInitProc) Initialize, /* initialize */
404 NULL, /* initialize_hook */
405 Realize, /* realize */
406 actionsList, /* actions */
407 XtNumber(actionsList), /* num_actions */
408 resources, /* resources */
409 XtNumber(resources), /* num_resources */
410 NULLQUARK, /* xrm_class */
411 FALSE, /* compress_motion */
412 TRUE, /* compress_exposure */
413 TRUE, /* compress_enterlv */
414 FALSE, /* visible_interest */
415 Destroy, /* destroy */
416 (XtWidgetProc) Resize, /* resize */
417 (XtExposeProc)Redisplay, /* expose */
418 (XtSetValuesFunc) SetValues, /* set_values */
419 NULL, /* set_values_hook */
420 (XtAlmostProc)_XtInherit, /* set_values_almost */
421 NULL, /* get_values_hook */
422 NULL, /* accept_focus */
423 XtVersion, /* version */
424 NULL, /* callback_private */
425 defaultTranslations, /* tm_table */
426 XtInheritQueryGeometry, /* query_geometry */
427 NULL, /* display_accelerator */
428 NULL, /* extension */
429 },
430
431 { /* composite_class fields */
432 XtInheritGeometryManager, /* geometry_manager */
433 (XtWidgetProc)_XtInherit, /* change_managed */
434 (XtWidgetProc)_XtInherit, /* insert_child */
435 (XtWidgetProc)_XtInherit, /* delete_child */
436 NULL, /* extension */
437 },
438
439 { /* constraint_class fields */
440 NULL, /* resource list */
441 0, /* num resources */
442 0, /* constraint size */
443 NULL, /* init proc */
444 NULL, /* destroy proc */
445 NULL, /* set values proc */
446 NULL, /* extension */
447 },
448
449 { /* manager_class fields */
450 #if (XmVersion >= 1001)
451 XtInheritTranslations, /* translations */
452 #else
453 NULL, /* translations */
454 #endif
455 NULL, /* get resources */
456 0, /* num get_resources */
457 NULL, /* get_cont_resources */
458 0, /* num_get_cont_resources */
459 (XmParentProcessProc)NULL, /* parent_process */
460 NULL, /* extension */
461 },
462
463 { /* drawing area class - none */
464 NULL, /* mumble */
465 },
466
467 { /* image class - none */
468 NULL, /* mumble */
469 },
470
471 { /* picture class - none */
472 NULL, /* mumble */
473 }
474 };
475
476 WidgetClass xmPictureWidgetClass = (WidgetClass) &xmPictureClassRec;
477
Resize(XmPictureWidget w)478 static void Resize( XmPictureWidget w )
479 {
480 double radi;
481
482 (*superclass->core_class.resize) ((Widget)w);
483 if (!XtIsRealized((Widget)w)) return;
484 /* Get the pixmap and its sizes */
485 w->picture.PIXMAPWIDTH = w->core.width;
486 w->picture.PIXMAPHEIGHT = w->core.height;
487
488 radi = (double)(w->picture.globe_radius);
489
490 generate_globe ( w, radi );
491 setup_gnomon(w, False);
492
493 if (w->image.frame_buffer)
494 {
495 XResizeWindow(XtDisplay(w),
496 w->picture.overlay_wid,
497 w->core.width,
498 w->core.height);
499
500 }
501 else
502 {
503 w->picture.pixmap = XmUNSPECIFIED_PIXMAP;
504 }
505 w->picture.disable_temp = True;
506 }
507
508
Realize(XmPictureWidget new,XtValueMask * value_mask,XSetWindowAttributes * attributes)509 static void Realize ( XmPictureWidget new, XtValueMask *value_mask,
510 XSetWindowAttributes *attributes )
511 {
512 unsigned long gc_value_mask;
513 XGCValues gc_values;
514 XSetWindowAttributes att;
515 unsigned long mask;
516 char dash_list[2];
517
518 (*superclass->core_class.realize) ((Widget)new,value_mask, attributes);
519
520 /*
521 * FIXME:
522 * This chunk of code lives in the top of Initialize also. It should probably
523 * be here only. I needed to move it here because dx -image has never worked
524 * on aviion. But so close to a release, I didn't want to be making noncrucial
525 * changes in this file. So after the release, erase these ifdefs and the chunk
526 * in Initialize. Alternative: update the dgux and X/Motif on shade and then
527 * remove this delta.
528 */
529 #if defined(aviion)
530 {
531 Arg wargs[20];
532 int n;
533 unsigned long valuemask;
534 XGCValues values;
535 XmFontContext context;
536 XmStringCharSet charset;
537 XmFontList font_list;
538
539 /*
540 * Create a Popup shell for the pushbutton
541 */
542 n = 0;
543 XtSetArg(wargs[0], XmNtitle, "Cursor X Y Z Position");
544 new->picture.popup =
545 XtCreatePopupShell("shell", overrideShellWidgetClass, XtParent(new),
546 wargs, 1);
547 new->picture.popped_up = False;
548
549 /*
550 * Create a PushButton widget to display the x, y, z value of a cursor
551 */
552 n = 0;
553 XtSetArg(wargs[n], XmNx, 0); n++;
554 XtSetArg(wargs[n], XmNy, 0); n++;
555 XtSetArg(wargs[n], XmNshadowThickness, 2); n++;
556 XtSetArg(wargs[n], XmNrecomputeSize, False); n++;
557 XtSetArg(wargs[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
558 XtSetArg(wargs[n], XmNwidth, 350); n++;
559
560 new->picture.pb = (XmPushButtonWidget)XmCreatePushButton(new->picture.popup,
561 "PushButton", wargs, n);
562 XtManageChild((Widget)new->picture.pb);
563
564 /*
565 * Set up font inforamtion
566 */
567 XtSetArg(wargs[0], XmNfontList, &font_list);
568 XtGetValues((Widget)new->picture.pb, wargs, 1);
569
570 XmFontListInitFontContext(&context, font_list);
571 XmFontListGetNextFont(context, &charset, &new->picture.font);
572 XmFontListFreeFontContext(context);
573
574 valuemask = GCFont;
575 values.font = new->picture.font->fid;
576 new->picture.fontgc = XtGetGC((Widget)new->picture.pb, valuemask, &values);
577 }
578 #endif
579
580 /* Get the pixmap and its sizes */
581 new->picture.PIXMAPWIDTH = new->core.width;
582 new->picture.PIXMAPHEIGHT = new->core.height;
583 new->picture.pixmap = XmUNSPECIFIED_PIXMAP;
584 new->picture.globe = NULL;
585
586 /*
587 * If we are on the frame buffer, create an overlay window.
588 */
589 if(new->image.frame_buffer)
590 {
591 XFlush(XtDisplay(new));
592 mask = CWBackPixel | CWColormap | CWBorderPixel;
593 att.background_pixel = new->picture.black;
594 att.border_pixel = new->picture.white + 1;
595 att.colormap =
596 DefaultColormap(XtDisplay(new),XScreenNumberOfScreen(XtScreen(new)));
597 new->picture.overlay_wid = XCreateWindow(XtDisplay(new),XtWindow(new),
598 0, 0, new->core.width, new->core.height, 0, 8, InputOutput,
599 DefaultVisual(XtDisplay(new), XScreenNumberOfScreen(XtScreen(new))),
600 mask, &att);
601 XFlush(XtDisplay(new));
602 XSelectInput(XtDisplay(new), new->picture.overlay_wid, ExposureMask);
603 XMapWindow(XtDisplay(new), new->picture.overlay_wid);
604
605 gc_value_mask = GCForeground;
606 gc_values.foreground = new->picture.white;
607 new->picture.gcovl =
608 XCreateGC(XtDisplay(new), new->picture.overlay_wid,
609 gc_value_mask, &gc_values);
610
611 gc_value_mask = GCForeground | GCBackground| GCLineStyle;
612 gc_values.foreground = new->picture.white;
613 gc_values.background = new->picture.black;
614 gc_values.line_style = LineDoubleDash;
615 new->picture.gcovl_dash =
616 XCreateGC(XtDisplay(new), new->picture.overlay_wid,
617 gc_value_mask, &gc_values);
618 dash_list[0] = 2; dash_list[1] = 3;
619 XSetDashes(XtDisplay(new), new->picture.gcovl_dash, 0, dash_list, 2);
620 }
621 }
622
623
624 /*****************************************************************************/
625 /* */
626 /* Subroutine: ClassInitialize */
627 /* Effect: Install non-standard type converters needed by this widget */
628 /* class */
629 /* */
630 /*****************************************************************************/
ClassInitialize()631 static void ClassInitialize()
632 {
633 /* Install converters for type XmRDouble and XmRFloat */
634 XmAddFloatConverters();
635 }
636
637
638
639 /*****************************************************************************/
640 /* */
641 /* Subroutine: Initialize */
642 /* Effect: Create and initialize the component widgets */
643 /* */
644 /*****************************************************************************/
645
Initialize(XmPictureWidget request,XmPictureWidget new)646 static void Initialize( XmPictureWidget request, XmPictureWidget new )
647 {
648
649 int i, j;
650 Arg wargs[20];
651 int n;
652 XmFontList font_list;
653 unsigned long valuemask;
654 XGCValues values;
655 char dash_list[2];
656
657 #if (XmVersion >= 1001)
658 XmFontContext context;
659 XmStringCharSet charset;
660 #endif
661
662
663 /*
664 * FIXME:
665 * This chunk of code lives in the top of Realize also. See the comment.
666 */
667 #if !defined(aviion)
668 /*
669 * Create a Popup shell for the pushbutton
670 */
671 n = 0;
672 XtSetArg(wargs[0], XmNtitle, "Cursor X Y Z Position");
673 new->picture.popup =
674 XtCreatePopupShell("shell", overrideShellWidgetClass, XtParent(new),
675 wargs, 1);
676 new->picture.popped_up = False;
677
678 /*
679 * Create a PushButton widget to display the x, y, z value of a cursor
680 */
681 n = 0;
682 XtSetArg(wargs[n], XmNx, 0); n++;
683 XtSetArg(wargs[n], XmNy, 0); n++;
684 XtSetArg(wargs[n], XmNshadowThickness, 2); n++;
685 XtSetArg(wargs[n], XmNrecomputeSize, False); n++;
686 XtSetArg(wargs[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
687 XtSetArg(wargs[n], XmNwidth, 350); n++;
688
689 new->picture.pb = (XmPushButtonWidget)XmCreatePushButton(new->picture.popup,
690 "PushButton", wargs, n);
691 XtManageChild((Widget)new->picture.pb);
692
693 /*
694 * Set up font inforamtion
695 */
696 XtSetArg(wargs[0], XmNfontList, &font_list);
697 XtGetValues((Widget)new->picture.pb, wargs, 1);
698
699 #if (XmVersion < 1001)
700 new->picture.font = font_list->font;
701 #else
702 XmFontListInitFontContext(&context, font_list);
703 XmFontListGetNextFont(context, &charset, &new->picture.font);
704 XmFontListFreeFontContext(context);
705 #endif
706
707 valuemask = GCFont;
708 values.font = new->picture.font->fid;
709 new->picture.fontgc = XtGetGC((Widget)new->picture.pb, valuemask, &values);
710 #endif
711
712 /* Indicate that none of the cursors are currently active or selected */
713 new->picture.n_cursors = 0;
714 new->picture.selected = NULL;
715 new->picture.xbuff = NULL;
716 new->picture.ybuff = NULL;
717 new->picture.zbuff = NULL;
718 new->picture.cxbuff = NULL;
719 new->picture.cybuff = NULL;
720 new->picture.czbuff = NULL;
721
722 new->picture.CursorBlank = False;
723 new->picture.FirstTime = True;
724 new->picture.FirstTimeMotion = True;
725
726 /* Default the xform to the identity */
727 for ( i = 0 ; i < 4 ; i++ )
728 {
729 for ( j = 0 ; j < 4 ; j++ )
730 {
731 if ( i == j )
732 {
733 new->picture.Wtrans[i][j] = 1.0;
734 }
735 else
736 {
737 new->picture.Wtrans[i][j] = 0.0;
738 }
739 }
740 }
741
742 /*screen = XScreenNumberOfScreen(XtScreen(new));*/
743 new->picture.rubber_band.gc = NULL;
744 new->picture.gcovl = NULL;
745 new->picture.gc = XtGetGC((Widget)new, 0, NULL);
746
747 valuemask = GCForeground | GCBackground| GCLineStyle;
748 values.foreground = new->picture.white;
749 values.background = new->picture.black;
750 values.line_style = LineDoubleDash;
751 new->picture.gc_dash = XtGetGC((Widget)new, valuemask, &values);
752 dash_list[0] = 2; dash_list[1] = 3;
753 XSetDashes(XtDisplay(new), new->picture.gc_dash, 0, dash_list, 2);
754
755
756 new->picture.ActiveSquareCursor[0] = None;
757 if ( (new->picture.mode == XmCURSOR_MODE) ||
758 (new->picture.mode == XmROAM_MODE) ||
759 (new->picture.mode == XmPICK_MODE) )
760 {
761 create_cursor_pixmaps(new);
762 }
763
764 new->picture.tid = (XtIntervalId)NULL;
765 new->picture.key_tid = (XtIntervalId)NULL;
766
767 /*
768 * disable_temp is set when we call back the application with a
769 * message that will cause an execution. Subsequent button presses,
770 * button motion and button release events are ignored, until a
771 * new image is loaded. This is detected when XmPictureNewCamera is
772 * called.
773 */
774 new->picture.good_at_select = True;
775 new->picture.disable_temp = False;
776 new->picture.double_click = False;
777 new->picture.ignore_new_camera = 0;
778 new->picture.globe = NULL;
779 new->picture.first_key_press = True;
780 new->picture.grab_keyboard_count = 0;
781 new->picture.button_pressed = 0;
782 new->picture.undo_count = 0;
783 new->picture.redo_count = 0;
784 new->picture.undo_stk_ptr = -1;
785 new->picture.redo_stk_ptr = -1;
786 new->picture.camera_defined = False;
787 new->picture.piMark = 0;
788 new->picture.cursor = None;
789
790 new->picture.white = 0;
791 new->picture.black = 0;
792 new->picture.box_grey.pixel = 0;
793
794 /* Colors - used to be resources */
795 new->picture.box_grey.red = 0x7e7e;
796 new->picture.box_grey.green = 0x7e7e;
797 new->picture.box_grey.blue = 0x7e7e;
798 new->picture.selected_out_cursor_color.red = 0x0000;
799 new->picture.selected_out_cursor_color.green = 0xffff;
800 new->picture.selected_out_cursor_color.blue = 0x7e7e;
801 new->picture.unselected_out_cursor_color.red = 0xffff;
802 new->picture.unselected_out_cursor_color.green =0xffff;
803 new->picture.unselected_out_cursor_color.blue = 0xffff;
804
805 }
806
807
808 /*****************************************************************************/
809 /* */
810 /* Subroutine: Redisplay */
811 /* Effect: */
812 /* */
813 /*****************************************************************************/
Redisplay(XmPictureWidget w,XExposeEvent * event,Region region)814 static void Redisplay (XmPictureWidget w,
815 XExposeEvent* event,
816 Region region)
817 {
818 XmDrawingAreaCallbackStruct cb;
819
820 cb.reason = XmCR_EXPOSE;
821 cb.event = (XEvent *)event;
822 cb.window = XtWindow(w);
823
824 XtCallCallbacks ((Widget)w, XmNexposeCallback, &cb);
825
826 if (w->picture.mode == XmROTATION_MODE)
827 {
828 XmDrawGlobe (w);
829 draw_gnomon (w);
830 }
831 if ((w->picture.mode == XmCURSOR_MODE) ||
832 (w->picture.mode == XmROAM_MODE) )
833 {
834 draw_gnomon(w);
835 XmDrawGlobe (w);
836 XmDrawBbox (w);
837 draw_cursors(w);
838 }
839 if (w->picture.mode == XmPICK_MODE)
840 {
841 draw_cursors(w);
842 }
843 }
844
845 /*****************************************************************************/
846 /* */
847 /* Subroutine: SetValues */
848 /* Effect: Handles requests to change things from the application */
849 /* */
850 /*****************************************************************************/
SetValues(XmPictureWidget current,XmPictureWidget request,XmPictureWidget new)851 static Boolean SetValues( XmPictureWidget current,
852 XmPictureWidget request,
853 XmPictureWidget new )
854 {
855 Boolean redraw = False;
856
857 if ( (new->picture.mode != current->picture.mode) ||
858 (new->picture.display_globe != current->picture.display_globe) )
859 {
860 if(new->picture.black == new->picture.white)
861 alloc_drawing_colors(new);
862 /*
863 * Erase the old image by restoring the background image
864 */
865 if (current->picture.mode != XmNULL_MODE)
866 {
867 erase_image(new);
868 }
869 if (new->picture.mode == XmNULL_MODE) return redraw;
870 if ( (new->picture.mode == XmCURSOR_MODE) ||
871 (new->picture.mode == XmROAM_MODE) )
872 {
873 create_cursor_pixmaps(new);
874 setup_bounding_box(new);
875 calc_projected_axis(new);
876 setup_gnomon(new, False);
877 draw_gnomon(new);
878 XmDrawBbox (new);
879 XmDrawGlobe (new);
880 restore_cursors_from_canonical_form(new);
881 draw_cursors(new);
882 }
883 if (new->picture.mode == XmPICK_MODE)
884 {
885 setup_bounding_box(new);
886 calc_projected_axis(new);
887 XmPictureDeleteCursors(new, -1);
888 create_cursor_pixmaps(new);
889 draw_cursors(new);
890 }
891 if (new->picture.mode == XmROTATION_MODE)
892 {
893 setup_bounding_box(new);
894 calc_projected_axis(new);
895 setup_gnomon(new, False);
896 XmDrawGlobe (new);
897 draw_gnomon (new);
898 }
899 }
900 if (new->picture.overlay_exposure)
901 {
902 if (new->picture.mode == XmROTATION_MODE)
903 {
904 XmDrawGlobe (new);
905 draw_gnomon (new);
906 }
907 if ( (new->picture.mode == XmCURSOR_MODE) ||
908 (new->picture.mode == XmROAM_MODE) )
909 {
910 if ( (new->picture.ignore_new_camera == 0) &&
911 (!new->image.frame_buffer) )
912 {
913 draw_gnomon(new);
914 XmDrawBbox (new);
915 draw_cursors(new);
916 XmDrawGlobe (new);
917 }
918 }
919 if (new->picture.mode == XmPICK_MODE)
920 {
921 if ( (new->picture.ignore_new_camera == 0) ||
922 (!new->image.frame_buffer) )
923 {
924 draw_cursors(new);
925 }
926 }
927 new->picture.overlay_exposure = False;
928 }
929 if (new->picture.constrain_cursor != current->picture.constrain_cursor)
930 {
931 setup_bounding_box(new);
932 calc_projected_axis(new);
933 if ( (new->picture.mode == XmCURSOR_MODE) ||
934 (new->picture.mode == XmROAM_MODE) )
935 {
936 draw_gnomon(new);
937 XmDrawBbox (new);
938 draw_cursors(new);
939 }
940 if (new->picture.mode == XmROTATION_MODE)
941 {
942 draw_gnomon (new);
943 }
944 }
945 if (new->picture.new_image)
946 {
947 new->picture.disable_temp = False;
948 new->picture.new_image = False;
949 }
950 return redraw;
951 }
952
953 /*****************************************************************************/
954 /* */
955 /* Subroutine: Destroy */
956 /* Effect: Clean up any allocated resources */
957 /* */
958 /*****************************************************************************/
Destroy(XmPictureWidget w)959 static void Destroy( XmPictureWidget w)
960 {
961 if (w->picture.gc)
962 XtReleaseGC((Widget)w, w->picture.gc);
963 if (w->picture.fontgc)
964 XtReleaseGC((Widget)w, w->picture.fontgc);
965 if (w->picture.rubber_band.gc)
966 XtReleaseGC((Widget)w, w->picture.rubber_band.gc);
967 if(w->picture.gcovl)
968 XFreeGC(XtDisplay(w), w->picture.gcovl);
969 if(w->picture.cursor)
970 XFreeCursor ( XtDisplay(w), w->picture.cursor );
971
972 if(w->picture.selected) XtFree((char*)w->picture.selected);
973 if(w->picture.xbuff) XtFree((char*)w->picture.xbuff);
974 if(w->picture.ybuff) XtFree((char*)w->picture.ybuff);
975 if(w->picture.zbuff) XtFree((char*)w->picture.zbuff);
976 if(w->picture.cxbuff) XtFree((char*)w->picture.cxbuff);
977 if(w->picture.cybuff) XtFree((char*)w->picture.cybuff);
978 if(w->picture.czbuff) XtFree((char*)w->picture.czbuff);
979 if(w->picture.globe) XtFree((char*)w->picture.globe);
980 }
981 /*****************************************************************************/
982 /* */
983 /* Subroutine: restore_rectangle */
984 /* Effect: erase a "zoom" rectangle by restoring the image */
985 /* */
986 /*****************************************************************************/
restore_rectangle(XmPictureWidget w)987 static void restore_rectangle(XmPictureWidget w)
988 {
989 int x;
990 int y;
991 int width;
992 int height;
993
994 x = w->picture.rubber_band.old_x;
995 y = w->picture.rubber_band.old_y;
996 width = w->picture.rubber_band.old_width;
997 height = w->picture.rubber_band.old_height;
998
999 if((!w->image.frame_buffer) && (w->picture.pixmap != XmUNSPECIFIED_PIXMAP))
1000 {
1001 /*
1002 * Weird (extra wide) copies are to compensate for GTO bug
1003 */
1004 XCopyArea(XtDisplay(w), w->picture.pixmap, XtWindow(w),
1005 w->picture.rubber_band.gc,
1006 MAX(x-1,0),
1007 MAX(y-1,0),
1008 4,
1009 height+2,
1010 MAX(x-1,0),
1011 MAX(y-1,0));
1012
1013 XCopyArea(XtDisplay(w), w->picture.pixmap, XtWindow(w),
1014 w->picture.rubber_band.gc,
1015 MAX(x-1,0),
1016 MAX(y-1,0),
1017 width+2,
1018 4,
1019 MAX(x-1,0),
1020 MAX(y-1,0));
1021
1022 XCopyArea(XtDisplay(w), w->picture.pixmap, XtWindow(w),
1023 w->picture.rubber_band.gc,
1024 MAX(x + width-2,0),
1025 MAX(y-1,0),
1026 4,
1027 height+4,
1028 MAX(x + width-2,0),
1029 MAX(y-1,0));
1030
1031 XCopyArea(XtDisplay(w), w->picture.pixmap, XtWindow(w),
1032 w->picture.rubber_band.gc,
1033 MAX(x-1,0),
1034 MAX(y + height-2,0),
1035 width+4,
1036 4,
1037 MAX(x-1,0),
1038 MAX(y + height-2,0));
1039 }
1040 else if (w->image.frame_buffer)
1041 {
1042 XSetForeground(XtDisplay(w), w->picture.gcovl,
1043 w->picture.white + 1 );
1044
1045 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
1046 w->picture.gcovl, x, y, width, height);
1047
1048 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
1049 w->picture.gcovl, x+1, y+1, width-2, height-2);
1050
1051 XSetForeground(XtDisplay(w), w->picture.gcovl,
1052 w->picture.white);
1053 }
1054 }
1055
1056 /*****************************************************************************/
1057 /* */
1058 /* Subroutine: erase_image */
1059 /* Effect: Routine to erase the direct interactors */
1060 /* */
1061 /*****************************************************************************/
erase_image(XmPictureWidget w)1062 static void erase_image(XmPictureWidget w)
1063 {
1064
1065 /*
1066 * Erase the old image by restoring the background image
1067 */
1068 if(!w->image.frame_buffer)
1069 {
1070 if (w->picture.pixmap != XmUNSPECIFIED_PIXMAP)
1071 {
1072 XCopyArea (XtDisplay(w),
1073 w->picture.pixmap, XtWindow(w), w->picture.gc,
1074 (int)(0) ,
1075 (int)(0) ,
1076 (int)(w->picture.PIXMAPWIDTH),
1077 (int)(w->picture.PIXMAPHEIGHT),
1078 (int)(0),
1079 (int)(0));
1080 }
1081 else
1082 {
1083 XClearArea (XtDisplay(w),
1084 XtWindow(w),
1085 (int)(0) ,
1086 (int)(0) ,
1087 (int)(w->picture.PIXMAPWIDTH),
1088 (int)(w->picture.PIXMAPHEIGHT),
1089 False);
1090 }
1091 }
1092 else if(w->image.frame_buffer)
1093 {
1094 /* Clear the overlay plane to the transparency color */
1095 XClearArea (XtDisplay(w),
1096 w->picture.overlay_wid,
1097 (int)(0) ,
1098 (int)(0) ,
1099 (int)(w->picture.PIXMAPWIDTH),
1100 (int)(w->picture.PIXMAPHEIGHT),
1101 False);
1102 }
1103 }
1104
1105 /*****************************************************************************/
1106 /* */
1107 /* Subroutine: XmPictureReset */
1108 /* Effect: Reset some important params */
1109 /* */
1110 /*****************************************************************************/
1111
XmPictureReset(XmPictureWidget w)1112 void XmPictureReset(XmPictureWidget w)
1113 {
1114 if (w->picture.tid)
1115 {
1116 XtRemoveTimeOut(w->picture.tid);
1117 }
1118 w->picture.tid = (XtIntervalId)NULL;
1119 if (w->picture.key_tid)
1120 {
1121 XtRemoveTimeOut(w->picture.key_tid);
1122 w->picture.key_tid = (XtIntervalId)NULL;
1123 }
1124 if ( w->picture.CursorBlank )
1125 {
1126 XUndefineCursor(XtDisplay(w), XtWindow(w));
1127 w->picture.CursorBlank = False;
1128 }
1129 /*
1130 * Just in case...
1131 */
1132 XtUngrabKeyboard((Widget)w, CurrentTime);
1133
1134 w->picture.mode = XmNULL_MODE;
1135 w->picture.black = w->picture.white;
1136 erase_image(w);
1137 }
1138 /*****************************************************************************/
1139 /* */
1140 /* Subroutine: XmPictureResetCursor */
1141 /* Effect: Reset some important params */
1142 /* */
1143 /*****************************************************************************/
1144
XmPictureResetCursor(XmPictureWidget w)1145 void XmPictureResetCursor(XmPictureWidget w)
1146 {
1147 w->picture.grab_keyboard_count = 0;
1148 w->picture.ignore_new_camera = 0;
1149 /* if (XtIsManaged(w->picture.popup)) */
1150 /* XtUnmanageChild(w->picture.popup); */
1151 if (w->picture.popped_up)
1152 {
1153 XtPopdown(w->picture.popup);
1154 w->picture.popped_up = False;
1155 }
1156
1157 if ( w->picture.CursorBlank )
1158 {
1159 XUndefineCursor(XtDisplay(w), XtWindow(w));
1160 w->picture.CursorBlank = False;
1161 }
1162 }
1163
1164 /*****************************************************************************/
1165 /* */
1166 /* Subroutine: XmPictureSetView */
1167 /* Effect: Convieniece routine to calc new camera direction vector */
1168 /*****************************************************************************/
XmPictureSetView(XmPictureWidget w,int direction,double * from_x,double * from_y,double * from_z,double * up_x,double * up_y,double * up_z)1169 void XmPictureSetView(XmPictureWidget w, int direction, double *from_x,
1170 double *from_y, double *from_z, double *up_x,
1171 double *up_y, double *up_z)
1172 {
1173 double length;
1174 double tmp_length;
1175 double dir_x;
1176 double dir_y;
1177 double dir_z;
1178
1179
1180 /*
1181 * It is possible that an image was created and we were in NULL_MODE,
1182 * hence its bounding box has not been set up, sooo...
1183 */
1184 setup_bounding_box(w);
1185
1186 dir_x = w->picture.from_x - w->picture.to_x;
1187 dir_y = w->picture.from_y - w->picture.to_y;
1188 dir_z = w->picture.from_z - w->picture.to_z;
1189 length = sqrt(dir_x*dir_x + dir_y*dir_y + dir_z*dir_z);
1190
1191 *up_x = 0.0;
1192 *up_y = 1.0;
1193 *up_z = 0.0;
1194
1195 switch(direction)
1196 {
1197 case FRONT:
1198 dir_x = 0.0;
1199 dir_y = 0.0;
1200 dir_z = 1.0;
1201 break;
1202 case OFF_FRONT:
1203 dir_x = SIN15;
1204 dir_y = SIN15;
1205 dir_z = COS15;
1206 break;
1207 case BACK:
1208 dir_x = 0.0;
1209 dir_y = 0.0;
1210 dir_z = -1.0;
1211 break;
1212 case OFF_BACK:
1213 dir_x = SIN15;
1214 dir_y = SIN15;
1215 dir_z = -COS15;
1216 break;
1217 case TOP:
1218 dir_x = 0.0;
1219 dir_y = 1.0;
1220 dir_z = 0.0;
1221 *up_x = 0.0;
1222 *up_y = 0.0;
1223 *up_z = -1.0;
1224 break;
1225 case OFF_TOP:
1226 dir_x = -SIN15;
1227 dir_y = COS15;
1228 dir_z = -SIN15;
1229 *up_x = 0.0;
1230 *up_y = 0.0;
1231 *up_z = -1.0;
1232 break;
1233 case BOTTOM:
1234 dir_x = 0.0;
1235 dir_y = -1.0;
1236 dir_z = 0.0;
1237 *up_x = 0.0;
1238 *up_y = 0.0;
1239 *up_z = 1.0;
1240 break;
1241 case OFF_BOTTOM:
1242 dir_x = SIN15;
1243 dir_y = -COS15;
1244 dir_z = SIN15;
1245 *up_x = 0.0;
1246 *up_y = 0.0;
1247 *up_z = 1.0;
1248 break;
1249 case RIGHT:
1250 dir_x = 1.0;
1251 dir_y = 0.0;
1252 dir_z = 0.0;
1253 break;
1254 case OFF_RIGHT:
1255 dir_x = COS05;
1256 dir_y = SIN15;
1257 dir_z = SIN15;
1258 break;
1259 case LEFT:
1260 dir_x = -1.0;
1261 dir_y = 0.0;
1262 dir_z = 0.0;
1263 break;
1264 case OFF_LEFT:
1265 dir_x = -COS05;
1266 dir_y = SIN15;
1267 dir_z = SIN15;
1268 break;
1269 case DIAGONAL:
1270 dir_x = SIN45;
1271 dir_y = SIN45;
1272 dir_z = SIN45;
1273 break;
1274 case OFF_DIAGONAL:
1275 dir_x = SIN35;
1276 dir_y = SIN35;
1277 dir_z = SIN45;
1278 break;
1279 }
1280
1281 /*
1282 * Normalize the length...
1283 */
1284 tmp_length = sqrt(dir_x*dir_x + dir_y*dir_y + dir_z*dir_z);
1285 dir_x = dir_x/tmp_length;
1286 dir_y = dir_y/tmp_length;
1287 dir_z = dir_z/tmp_length;
1288
1289 /*
1290 * And restore the original length
1291 */
1292 dir_x *=length;
1293 dir_y *=length;
1294 dir_z *=length;
1295
1296 *from_x = dir_x + w->picture.to_x;
1297 *from_y = dir_y + w->picture.to_y;
1298 *from_z = dir_z + w->picture.to_z;
1299 }
1300 /*****************************************************************************/
1301 /* */
1302 /* Subroutine: XmPictureGetUndoCamera */
1303 /*****************************************************************************/
XmPictureGetUndoCamera(XmPictureWidget w,double * to_x,double * to_y,double * to_z,double * from_x,double * from_y,double * from_z,double * up_x,double * up_y,double * up_z,double * autocamera_width,int * projection,double * view_angle)1304 extern Boolean XmPictureGetUndoCamera(XmPictureWidget w,
1305 double *to_x, double *to_y, double *to_z,
1306 double *from_x, double *from_y, double *from_z,
1307 double *up_x, double *up_y, double *up_z,
1308 double *autocamera_width, int *projection,
1309 double *view_angle)
1310
1311 {
1312 int undo_stk_ptr;
1313
1314 if (w->picture.undo_count < 1)
1315 {
1316 return False;
1317 }
1318
1319 /*
1320 * Push the current camera onto the redo stack
1321 */
1322 push_redo_camera(w);
1323
1324 undo_stk_ptr = w->picture.undo_stk_ptr;
1325
1326 *up_x = w->picture.undo_stack[undo_stk_ptr].up_x;
1327 *up_y = w->picture.undo_stack[undo_stk_ptr].up_y;
1328 *up_z = w->picture.undo_stack[undo_stk_ptr].up_z;
1329 *from_x = w->picture.undo_stack[undo_stk_ptr].from_x;
1330 *from_y = w->picture.undo_stack[undo_stk_ptr].from_y;
1331 *from_z = w->picture.undo_stack[undo_stk_ptr].from_z;
1332 *to_x = w->picture.undo_stack[undo_stk_ptr].to_x;
1333 *to_y = w->picture.undo_stack[undo_stk_ptr].to_y;
1334 *to_z = w->picture.undo_stack[undo_stk_ptr].to_z;
1335 *autocamera_width = w->picture.undo_stack[undo_stk_ptr].width;
1336 *projection = w->picture.undo_stack[undo_stk_ptr].projection;
1337 *view_angle = w->picture.undo_stack[undo_stk_ptr].view_angle;
1338
1339 w->picture.undo_stk_ptr = --w->picture.undo_stk_ptr;
1340 if (w->picture.undo_stk_ptr < 0)
1341 {
1342 w->picture.undo_stk_ptr = UNDO_STACK_DEPTH-1;
1343 }
1344 w->picture.undo_count--;
1345
1346 return True;
1347 }
1348 /*****************************************************************************/
1349 /* */
1350 /* Subroutine: XmPictureGetRedoCamera */
1351 /*****************************************************************************/
XmPictureGetRedoCamera(XmPictureWidget w,double * to_x,double * to_y,double * to_z,double * from_x,double * from_y,double * from_z,double * up_x,double * up_y,double * up_z,double * autocamera_width,int * projection,double * view_angle)1352 extern Boolean XmPictureGetRedoCamera(XmPictureWidget w,
1353 double *to_x, double *to_y, double *to_z,
1354 double *from_x, double *from_y, double *from_z,
1355 double *up_x, double *up_y, double *up_z,
1356 double *autocamera_width, int *projection,
1357 double *view_angle)
1358
1359 {
1360 int redo_stk_ptr;
1361
1362 if (w->picture.redo_count < 1)
1363 {
1364 return False;
1365 }
1366
1367 redo_stk_ptr = w->picture.redo_stk_ptr;
1368
1369 *up_x = w->picture.redo_stack[redo_stk_ptr].up_x;
1370 *up_y = w->picture.redo_stack[redo_stk_ptr].up_y;
1371 *up_z = w->picture.redo_stack[redo_stk_ptr].up_z;
1372 *from_x = w->picture.redo_stack[redo_stk_ptr].from_x;
1373 *from_y = w->picture.redo_stack[redo_stk_ptr].from_y;
1374 *from_z = w->picture.redo_stack[redo_stk_ptr].from_z;
1375 *to_x = w->picture.redo_stack[redo_stk_ptr].to_x;
1376 *to_y = w->picture.redo_stack[redo_stk_ptr].to_y;
1377 *to_z = w->picture.redo_stack[redo_stk_ptr].to_z;
1378 *autocamera_width = w->picture.redo_stack[redo_stk_ptr].width;
1379 *projection = w->picture.redo_stack[redo_stk_ptr].projection;
1380 *view_angle = w->picture.redo_stack[redo_stk_ptr].view_angle;
1381
1382 w->picture.redo_stk_ptr = --w->picture.redo_stk_ptr;
1383 if (w->picture.redo_stk_ptr < 0)
1384 {
1385 w->picture.redo_stk_ptr = UNDO_STACK_DEPTH-1;
1386 }
1387 w->picture.redo_count--;
1388
1389 w->picture.undo_stk_ptr = (w->picture.undo_stk_ptr + 1) % UNDO_STACK_DEPTH;
1390 w->picture.undo_count = MIN(UNDO_STACK_DEPTH, w->picture.undo_count+1);
1391
1392 return True;
1393 }
1394
1395 /*****************************************************************************/
1396 /* */
1397 /* Subroutine: push_undo_camera */
1398 /*****************************************************************************/
push_undo_camera(XmPictureWidget w)1399 static void push_undo_camera(XmPictureWidget w)
1400
1401 {
1402 int undo_stk_ptr;
1403
1404 /*
1405 * Reset the redo stack
1406 */
1407 w->picture.redo_stk_ptr = -1;
1408 w->picture.redo_count = 0;
1409
1410 w->picture.undo_stk_ptr = (w->picture.undo_stk_ptr + 1) % UNDO_STACK_DEPTH;
1411 undo_stk_ptr = w->picture.undo_stk_ptr;
1412
1413 w->picture.undo_count = MIN(UNDO_STACK_DEPTH, w->picture.undo_count+1);
1414
1415 w->picture.undo_stack[undo_stk_ptr].up_x = w->picture.up_x;
1416 w->picture.undo_stack[undo_stk_ptr].up_y = w->picture.up_y;
1417 w->picture.undo_stack[undo_stk_ptr].up_z = w->picture.up_z;
1418 w->picture.undo_stack[undo_stk_ptr].from_x = w->picture.from_x;
1419 w->picture.undo_stack[undo_stk_ptr].from_y = w->picture.from_y;
1420 w->picture.undo_stack[undo_stk_ptr].from_z = w->picture.from_z;
1421 w->picture.undo_stack[undo_stk_ptr].to_x = w->picture.to_x;
1422 w->picture.undo_stack[undo_stk_ptr].to_y = w->picture.to_y;
1423 w->picture.undo_stack[undo_stk_ptr].to_z = w->picture.to_z;
1424 w->picture.undo_stack[undo_stk_ptr].width = w->picture.autocamera_width;
1425 w->picture.undo_stack[undo_stk_ptr].projection = w->picture.projection;
1426 w->picture.undo_stack[undo_stk_ptr].view_angle = w->picture.view_angle;
1427 }
1428
1429 /*****************************************************************************/
1430 /* */
1431 /* Subroutine: push_redo_camera */
1432 /*****************************************************************************/
push_redo_camera(XmPictureWidget w)1433 static void push_redo_camera(XmPictureWidget w)
1434
1435 {
1436 int redo_stk_ptr;
1437
1438 w->picture.redo_stk_ptr = (w->picture.redo_stk_ptr + 1) % UNDO_STACK_DEPTH;
1439 redo_stk_ptr = w->picture.redo_stk_ptr;
1440
1441 w->picture.redo_count = MIN(UNDO_STACK_DEPTH, w->picture.redo_count+1);
1442
1443 w->picture.redo_stack[redo_stk_ptr].up_x = w->picture.up_x;
1444 w->picture.redo_stack[redo_stk_ptr].up_y = w->picture.up_y;
1445 w->picture.redo_stack[redo_stk_ptr].up_z = w->picture.up_z;
1446 w->picture.redo_stack[redo_stk_ptr].from_x = w->picture.from_x;
1447 w->picture.redo_stack[redo_stk_ptr].from_y = w->picture.from_y;
1448 w->picture.redo_stack[redo_stk_ptr].from_z = w->picture.from_z;
1449 w->picture.redo_stack[redo_stk_ptr].to_x = w->picture.to_x;
1450 w->picture.redo_stack[redo_stk_ptr].to_y = w->picture.to_y;
1451 w->picture.redo_stack[redo_stk_ptr].to_z = w->picture.to_z;
1452 w->picture.redo_stack[redo_stk_ptr].width = w->picture.autocamera_width;
1453 w->picture.redo_stack[redo_stk_ptr].projection = w->picture.projection;
1454 w->picture.redo_stack[redo_stk_ptr].view_angle = w->picture.view_angle;
1455 }
1456
1457 /*****************************************************************************/
1458 /* */
1459 /* Subroutine: set_nav_camera_from_camera */
1460 /* Effect: Calculate a navigation direction based on the current camera */
1461 /* and the current "look at" parameters */
1462 /*****************************************************************************/
set_nav_camera_from_camera(XmPictureWidget w)1463 int set_nav_camera_from_camera(XmPictureWidget w)
1464 {
1465 double l;
1466 double angle1;
1467 double angle2;
1468 double angle3;
1469 double xform[4][4];
1470 double dx, dy, dz;
1471 double up_xp, up_yp, up_zp;
1472 double dir_x, dir_y, dir_z;
1473 double dir_xp, dir_yp, dir_zp;
1474 double dir_xpp, dir_ypp, dir_zpp;
1475 double new_dir_x, new_dir_y, new_dir_z;
1476 int direction;
1477 double angle;
1478
1479 direction = w->picture.look_at_direction;
1480 angle = w->picture.look_at_angle;
1481
1482 /*
1483 * Note that the normal interpretation of "direction" is reversed here
1484 * for the convience of calculations. It is reversed when the final
1485 * results are calculated.
1486 */
1487 dir_x = w->picture.to_x - w->picture.from_x;
1488 dir_y = w->picture.to_y - w->picture.from_y;
1489 dir_z = w->picture.to_z - w->picture.from_z;
1490
1491 /*
1492 * Rotate the up vector so it is aligned with the Y axis
1493 */
1494 l = sqrt(w->picture.up_x*w->picture.up_x +
1495 w->picture.up_z*w->picture.up_z);
1496 if (l != 0.0)
1497 {
1498 angle1 = acos(w->picture.up_z/l);
1499 }
1500 else
1501 {
1502 angle1 = 0.0;
1503 }
1504 if (w->picture.up_x > 0)
1505 {
1506 angle1 = -angle1;
1507 }
1508 I44(xform);
1509 set_rot(xform, angle1, Yaxis);
1510 xform_coords( xform, w->picture.up_x,
1511 w->picture.up_y,
1512 w->picture.up_z,
1513 &up_xp,
1514 &up_yp,
1515 &up_zp);
1516 xform_coords( xform, dir_x, dir_y, dir_z, &dir_xp, &dir_yp, &dir_zp);
1517
1518 /*
1519 * Rotation about the x axis
1520 */
1521 l = sqrt(up_yp*up_yp + up_zp*up_zp);
1522 if (l != 0.0)
1523 {
1524 angle2 = acos(up_yp/l);
1525 }
1526 else
1527 {
1528 angle2 = 0.0;
1529 }
1530 if (up_zp > 0)
1531 {
1532 angle2 = -angle2;
1533 }
1534
1535 I44(xform);
1536 set_rot(xform, angle2, Xaxis);
1537 xform_coords( xform, dir_xp, dir_yp, dir_zp, &dir_xpp, &dir_ypp, &dir_zpp);
1538
1539 /*
1540 * Now, rotate the dir_pp vector about the Y axis so it lies
1541 * in the x=0 plane
1542 */
1543 l = sqrt(dir_xpp*dir_xpp + dir_zpp*dir_zpp);
1544 if (l != 0.0)
1545 {
1546 angle3 = acos(dir_zpp/l);
1547 }
1548 else
1549 {
1550 angle3 = 0.0;
1551 }
1552 if (dir_xpp > 0)
1553 {
1554 angle3 = -angle3;
1555 }
1556
1557 I44(xform);
1558
1559 switch(direction)
1560 {
1561 case XmLOOK_LEFT:
1562 /*
1563 * Rotate about the z axis
1564 */
1565 set_rot(xform, angle1, Yaxis);
1566 set_rot(xform, angle2, Xaxis);
1567 set_rot(xform, -angle, Yaxis);
1568 set_rot(xform, -angle2, Xaxis);
1569 set_rot(xform, -angle1, Yaxis);
1570
1571 xform_coords( xform, dir_x, dir_y, dir_z,
1572 &new_dir_x, &new_dir_y, &new_dir_z);
1573
1574 w->picture.navigate_to_x = w->picture.from_x + new_dir_x;
1575 w->picture.navigate_to_y = w->picture.from_y + new_dir_y;
1576 w->picture.navigate_to_z = w->picture.from_z + new_dir_z;
1577 w->picture.navigate_up_x = w->picture.up_x;
1578 w->picture.navigate_up_y = w->picture.up_y;
1579 w->picture.navigate_up_z = w->picture.up_z;
1580 break;
1581
1582 case XmLOOK_RIGHT:
1583 /*
1584 * Rotate about the z axis
1585 */
1586 set_rot(xform, angle1, Yaxis);
1587 set_rot(xform, angle2, Xaxis);
1588 set_rot(xform, angle, Yaxis);
1589 set_rot(xform, -angle2, Xaxis);
1590 set_rot(xform, -angle1, Yaxis);
1591
1592 xform_coords( xform, dir_x, dir_y, dir_z,
1593 &new_dir_x, &new_dir_y, &new_dir_z);
1594
1595 w->picture.navigate_to_x = w->picture.from_x + new_dir_x;
1596 w->picture.navigate_to_y = w->picture.from_y + new_dir_y;
1597 w->picture.navigate_to_z = w->picture.from_z + new_dir_z;
1598 w->picture.navigate_up_x = w->picture.up_x;
1599 w->picture.navigate_up_y = w->picture.up_y;
1600 w->picture.navigate_up_z = w->picture.up_z;
1601 break;
1602
1603 case XmLOOK_UP:
1604 set_rot(xform, angle1, Yaxis);
1605 set_rot(xform, angle2, Xaxis);
1606 set_rot(xform, angle3, Yaxis);
1607 set_rot(xform, angle, Xaxis);
1608 set_rot(xform, -angle3, Yaxis);
1609 set_rot(xform, -angle2, Xaxis);
1610 set_rot(xform, -angle1, Yaxis);
1611
1612 xform_coords( xform, dir_x, dir_y, dir_z,
1613 &new_dir_x, &new_dir_y, &new_dir_z);
1614
1615 xform_coords(xform, w->picture.up_x,
1616 w->picture.up_y,
1617 w->picture.up_z,
1618 &w->picture.navigate_up_x,
1619 &w->picture.navigate_up_y,
1620 &w->picture.navigate_up_z);
1621
1622 w->picture.navigate_to_x = w->picture.from_x + new_dir_x;
1623 w->picture.navigate_to_y = w->picture.from_y + new_dir_y;
1624 w->picture.navigate_to_z = w->picture.from_z + new_dir_z;
1625 break;
1626
1627 case XmLOOK_DOWN:
1628 set_rot(xform, angle1, Yaxis);
1629 set_rot(xform, angle2, Xaxis);
1630 set_rot(xform, angle3, Yaxis);
1631 set_rot(xform, -angle, Xaxis);
1632 set_rot(xform, -angle3, Yaxis);
1633 set_rot(xform, -angle2, Xaxis);
1634 set_rot(xform, -angle1, Yaxis);
1635
1636 xform_coords( xform, dir_x, dir_y, dir_z,
1637 &new_dir_x, &new_dir_y, &new_dir_z);
1638
1639 xform_coords(xform, w->picture.up_x,
1640 w->picture.up_y,
1641 w->picture.up_z,
1642 &w->picture.navigate_up_x,
1643 &w->picture.navigate_up_y,
1644 &w->picture.navigate_up_z);
1645
1646
1647 w->picture.navigate_to_x = w->picture.from_x + new_dir_x;
1648 w->picture.navigate_to_y = w->picture.from_y + new_dir_y;
1649 w->picture.navigate_to_z = w->picture.from_z + new_dir_z;
1650 break;
1651
1652 case XmLOOK_BACKWARD:
1653 dx = w->picture.from_x - w->picture.to_x;
1654 dy = w->picture.from_y - w->picture.to_y;
1655 dz = w->picture.from_z - w->picture.to_z;
1656
1657 w->picture.navigate_to_x = w->picture.from_x + dx;
1658 w->picture.navigate_to_y = w->picture.from_y + dy;
1659 w->picture.navigate_to_z = w->picture.from_z + dz;
1660 w->picture.navigate_up_x = w->picture.up_x;
1661 w->picture.navigate_up_y = w->picture.up_y;
1662 w->picture.navigate_up_z = w->picture.up_z;
1663 break;
1664
1665 case XmLOOK_FORWARD:
1666 w->picture.navigate_to_x = w->picture.to_x;
1667 w->picture.navigate_to_y = w->picture.to_y;
1668 w->picture.navigate_to_z = w->picture.to_z;
1669 w->picture.navigate_up_x = w->picture.up_x;
1670 w->picture.navigate_up_y = w->picture.up_y;
1671 w->picture.navigate_up_z = w->picture.up_z;
1672 break;
1673 }
1674
1675 w->picture.navigate_from_x = w->picture.from_x;
1676 w->picture.navigate_from_y = w->picture.from_y;
1677 w->picture.navigate_from_z = w->picture.from_z;
1678
1679 return 0;
1680 }
1681 /*****************************************************************************/
1682 /* */
1683 /* Subroutine: set_camera_from_nav_camera */
1684 /* Effect: Calculate a navigation direction based on the current camera */
1685 /* and the current "look at" parameters */
1686 /*****************************************************************************/
set_camera_from_nav_camera(XmPictureWidget w)1687 int set_camera_from_nav_camera(XmPictureWidget w)
1688 {
1689 double l;
1690 double angle1;
1691 double angle2;
1692 double angle3;
1693 double xform[4][4];
1694 double dx, dy, dz;
1695 double up_xp, up_yp, up_zp;
1696 double dir_x, dir_y, dir_z;
1697 double dir_xp, dir_yp, dir_zp;
1698 double dir_xpp, dir_ypp, dir_zpp;
1699 double new_dir_x, new_dir_y, new_dir_z;
1700 int direction;
1701 double angle;
1702
1703 direction = w->picture.look_at_direction;
1704 angle = w->picture.look_at_angle;
1705
1706 /*
1707 * Note that the normal interpretation of "direction" is reversed here
1708 * for the convience of calculations. It is reversed when the final
1709 * results are calculated.
1710 */
1711 dir_x = w->picture.navigate_to_x - w->picture.navigate_from_x;
1712 dir_y = w->picture.navigate_to_y - w->picture.navigate_from_y;
1713 dir_z = w->picture.navigate_to_z - w->picture.navigate_from_z;
1714
1715 /*
1716 * Rotate the up vector so it is aligned with the Y axis
1717 */
1718 l = sqrt(w->picture.navigate_up_x*w->picture.navigate_up_x +
1719 w->picture.navigate_up_z*w->picture.navigate_up_z);
1720 if (l != 0.0)
1721 {
1722 angle1 = acos(w->picture.navigate_up_z/l);
1723 }
1724 else
1725 {
1726 angle1 = 0.0;
1727 }
1728 if (w->picture.up_x > 0)
1729 {
1730 angle1 = -angle1;
1731 }
1732 I44(xform);
1733 set_rot(xform, angle1, Yaxis);
1734 xform_coords( xform, w->picture.navigate_up_x,
1735 w->picture.navigate_up_y,
1736 w->picture.navigate_up_z,
1737 &up_xp,
1738 &up_yp,
1739 &up_zp);
1740 xform_coords( xform, dir_x, dir_y, dir_z, &dir_xp, &dir_yp, &dir_zp);
1741
1742 /*
1743 * Rotation about the x axis
1744 */
1745 l = sqrt(up_yp*up_yp + up_zp*up_zp);
1746 if (l != 0.0)
1747 {
1748 angle2 = acos(up_yp/l);
1749 }
1750 else
1751 {
1752 angle2 = 0.0;
1753 }
1754 if (up_zp > 0)
1755 {
1756 angle2 = -angle2;
1757 }
1758
1759 I44(xform);
1760 set_rot(xform, angle2, Xaxis);
1761 xform_coords( xform, dir_xp, dir_yp, dir_zp, &dir_xpp, &dir_ypp, &dir_zpp);
1762
1763 /*
1764 * Now, rotate the dir_pp vector about the Y axis so it lies
1765 * in the x=0 plane
1766 */
1767 l = sqrt(dir_xpp*dir_xpp + dir_zpp*dir_zpp);
1768 if (l != 0.0)
1769 {
1770 angle3 = acos(dir_zpp/l);
1771 }
1772 else
1773 {
1774 angle3 = 0.0;
1775 }
1776 if (dir_xpp > 0)
1777 {
1778 angle3 = -angle3;
1779 }
1780
1781 I44(xform);
1782
1783 switch(direction)
1784 {
1785 case XmLOOK_LEFT:
1786 /*
1787 * Rotate about the z axis
1788 */
1789 set_rot(xform, angle1, Yaxis);
1790 set_rot(xform, angle2, Xaxis);
1791 set_rot(xform, angle, Yaxis);
1792 set_rot(xform, -angle2, Xaxis);
1793 set_rot(xform, -angle1, Yaxis);
1794
1795 xform_coords( xform, dir_x, dir_y, dir_z,
1796 &new_dir_x, &new_dir_y, &new_dir_z);
1797
1798 w->picture.to_x = w->picture.navigate_from_x + new_dir_x;
1799 w->picture.to_y = w->picture.navigate_from_y + new_dir_y;
1800 w->picture.to_z = w->picture.navigate_from_z + new_dir_z;
1801 w->picture.up_x = w->picture.navigate_up_x;
1802 w->picture.up_y = w->picture.navigate_up_y;
1803 w->picture.up_z = w->picture.navigate_up_z;
1804 break;
1805
1806 case XmLOOK_RIGHT:
1807 /*
1808 * Rotate about the z axis
1809 */
1810 set_rot(xform, angle1, Yaxis);
1811 set_rot(xform, angle2, Xaxis);
1812 set_rot(xform, -angle, Yaxis);
1813 set_rot(xform, -angle2, Xaxis);
1814 set_rot(xform, -angle1, Yaxis);
1815
1816 xform_coords( xform, dir_x, dir_y, dir_z,
1817 &new_dir_x, &new_dir_y, &new_dir_z);
1818
1819 w->picture.to_x = w->picture.navigate_from_x + new_dir_x;
1820 w->picture.to_y = w->picture.navigate_from_y + new_dir_y;
1821 w->picture.to_z = w->picture.navigate_from_z + new_dir_z;
1822 w->picture.up_x = w->picture.navigate_up_x;
1823 w->picture.up_y = w->picture.navigate_up_y;
1824 w->picture.up_z = w->picture.navigate_up_z;
1825 break;
1826
1827 case XmLOOK_UP:
1828 set_rot(xform, angle1, Yaxis);
1829 set_rot(xform, angle2, Xaxis);
1830 set_rot(xform, angle3, Yaxis);
1831 set_rot(xform, -angle, Xaxis);
1832 set_rot(xform, -angle3, Yaxis);
1833 set_rot(xform, -angle2, Xaxis);
1834 set_rot(xform, -angle1, Yaxis);
1835
1836 xform_coords( xform, dir_x, dir_y, dir_z,
1837 &new_dir_x, &new_dir_y, &new_dir_z);
1838
1839 xform_coords(xform, w->picture.navigate_up_x,
1840 w->picture.navigate_up_y,
1841 w->picture.navigate_up_z,
1842 &w->picture.up_x,
1843 &w->picture.up_y,
1844 &w->picture.up_z);
1845
1846 w->picture.to_x = w->picture.navigate_from_x + new_dir_x;
1847 w->picture.to_y = w->picture.navigate_from_y + new_dir_y;
1848 w->picture.to_z = w->picture.navigate_from_z + new_dir_z;
1849 break;
1850
1851 case XmLOOK_DOWN:
1852 set_rot(xform, angle1, Yaxis);
1853 set_rot(xform, angle2, Xaxis);
1854 set_rot(xform, angle3, Yaxis);
1855 set_rot(xform, angle, Xaxis);
1856 set_rot(xform, -angle3, Yaxis);
1857 set_rot(xform, -angle2, Xaxis);
1858 set_rot(xform, -angle1, Yaxis);
1859
1860 xform_coords( xform, dir_x, dir_y, dir_z,
1861 &new_dir_x, &new_dir_y, &new_dir_z);
1862
1863 xform_coords(xform, w->picture.navigate_up_x,
1864 w->picture.navigate_up_y,
1865 w->picture.navigate_up_z,
1866 &w->picture.up_x,
1867 &w->picture.up_y,
1868 &w->picture.up_z);
1869
1870
1871 w->picture.to_x = w->picture.navigate_from_x + new_dir_x;
1872 w->picture.to_y = w->picture.navigate_from_y + new_dir_y;
1873 w->picture.to_z = w->picture.navigate_from_z + new_dir_z;
1874 break;
1875
1876 case XmLOOK_BACKWARD:
1877 dx = w->picture.navigate_from_x - w->picture.navigate_to_x;
1878 dy = w->picture.navigate_from_y - w->picture.navigate_to_y;
1879 dz = w->picture.navigate_from_z - w->picture.navigate_to_z;
1880
1881 w->picture.to_x = w->picture.navigate_from_x + dx;
1882 w->picture.to_y = w->picture.navigate_from_y + dy;
1883 w->picture.to_z = w->picture.navigate_from_z + dz;
1884 w->picture.up_x = w->picture.navigate_up_x;
1885 w->picture.up_y = w->picture.navigate_up_y;
1886 w->picture.up_z = w->picture.navigate_up_z;
1887 break;
1888
1889 case XmLOOK_FORWARD:
1890 w->picture.to_x = w->picture.navigate_to_x;
1891 w->picture.to_y = w->picture.navigate_to_y;
1892 w->picture.to_z = w->picture.navigate_to_z;
1893 w->picture.up_x = w->picture.navigate_up_x;
1894 w->picture.up_y = w->picture.navigate_up_y;
1895 w->picture.up_z = w->picture.navigate_up_z;
1896 break;
1897 }
1898
1899 w->picture.from_x = w->picture.navigate_from_x;
1900 w->picture.from_y = w->picture.navigate_from_y;
1901 w->picture.from_z = w->picture.navigate_from_z;
1902
1903 return 0;
1904 }
1905
1906 /*****************************************************************************/
1907 /* */
1908 /* Subroutine: XmPictureChangeLookAt */
1909 /* Effect: Convieniece routine to calc new camera relative to the current*/
1910 /* navigation direction */
1911 /*****************************************************************************/
XmPictureChangeLookAt(XmPictureWidget w,int direction,double angle,double * to_x,double * to_y,double * to_z,double * from_x,double * from_y,double * from_z,double * up_x,double * up_y,double * up_z,double * autocamera_width)1912 extern void XmPictureChangeLookAt(XmPictureWidget w,
1913 int direction, double angle,
1914 double *to_x, double *to_y, double *to_z,
1915 double *from_x, double *from_y, double *from_z,
1916 double *up_x, double *up_y, double *up_z,
1917 double *autocamera_width)
1918 {
1919 double l;
1920 double angle1;
1921 double angle2;
1922 double angle3;
1923 double xform[4][4];
1924 double dx, dy, dz;
1925 double up_xp, up_yp, up_zp;
1926 double dir_x, dir_y, dir_z;
1927 double dir_xp, dir_yp, dir_zp;
1928 double dir_xpp, dir_ypp, dir_zpp;
1929 double new_dir_x, new_dir_y, new_dir_z;
1930
1931 w->picture.look_at_direction = direction;
1932 w->picture.look_at_angle = angle;
1933
1934 /*
1935 * Note that the normal interpretation of "direction" is reversed here
1936 * for the convience of calculations. It is reversed when the final
1937 * results are calculated.
1938 */
1939 dir_x = w->picture.navigate_to_x - w->picture.navigate_from_x;
1940 dir_y = w->picture.navigate_to_y - w->picture.navigate_from_y;
1941 dir_z = w->picture.navigate_to_z - w->picture.navigate_from_z;
1942
1943 /*
1944 * Rotate the up vector so it is aligned with the Y axis
1945 */
1946 l = sqrt(w->picture.navigate_up_x*w->picture.navigate_up_x +
1947 w->picture.navigate_up_z*w->picture.navigate_up_z);
1948 if (l != 0.0)
1949 {
1950 angle1 = acos(w->picture.navigate_up_z/l);
1951 }
1952 else
1953 {
1954 angle1 = 0.0;
1955 }
1956 if (w->picture.navigate_up_x > 0)
1957 {
1958 angle1 = -angle1;
1959 }
1960 I44(xform);
1961 set_rot(xform, angle1, Yaxis);
1962 xform_coords( xform, w->picture.navigate_up_x,
1963 w->picture.navigate_up_y,
1964 w->picture.navigate_up_z,
1965 &up_xp,
1966 &up_yp,
1967 &up_zp);
1968 xform_coords( xform, dir_x, dir_y, dir_z, &dir_xp, &dir_yp, &dir_zp);
1969
1970 /*
1971 * Rotation about the x axis
1972 */
1973 l = sqrt(up_yp*up_yp + up_zp*up_zp);
1974 if (l != 0.0)
1975 {
1976 angle2 = acos(up_yp/l);
1977 }
1978 else
1979 {
1980 angle2 = 0.0;
1981 }
1982 if (up_zp > 0)
1983 {
1984 angle2 = -angle2;
1985 }
1986
1987 I44(xform);
1988 set_rot(xform, angle2, Xaxis);
1989 xform_coords( xform, dir_xp, dir_yp, dir_zp, &dir_xpp, &dir_ypp, &dir_zpp);
1990
1991 /*
1992 * Now, rotate the dir_pp vector about the Y axis so it lies
1993 * in the x=0 plane
1994 */
1995 l = sqrt(dir_xpp*dir_xpp + dir_zpp*dir_zpp);
1996 if (l != 0.0)
1997 {
1998 angle3 = acos(dir_zpp/l);
1999 }
2000 else
2001 {
2002 angle3 = 0.0;
2003 }
2004 if (dir_xpp > 0)
2005 {
2006 angle3 = -angle3;
2007 }
2008
2009 I44(xform);
2010 switch(direction)
2011 {
2012 case XmLOOK_LEFT:
2013 /*
2014 * Rotate about the z axis
2015 */
2016 set_rot(xform, angle1, Yaxis);
2017 set_rot(xform, angle2, Xaxis);
2018 set_rot(xform, angle, Yaxis);
2019 set_rot(xform, -angle2, Xaxis);
2020 set_rot(xform, -angle1, Yaxis);
2021
2022 xform_coords( xform, dir_x, dir_y, dir_z,
2023 &new_dir_x, &new_dir_y, &new_dir_z);
2024
2025 *to_x = w->picture.navigate_from_x + new_dir_x;
2026 *to_y = w->picture.navigate_from_y + new_dir_y;
2027 *to_z = w->picture.navigate_from_z + new_dir_z;
2028 dir_x = -new_dir_x;
2029 dir_y = -new_dir_y;
2030 dir_z = -new_dir_z;
2031 *up_x = w->picture.navigate_up_x;
2032 *up_y = w->picture.navigate_up_y;
2033 *up_z = w->picture.navigate_up_z;
2034 *autocamera_width = w->picture.autocamera_width;
2035 break;
2036 case XmLOOK_RIGHT:
2037 /*
2038 * Rotate about the z axis
2039 */
2040 set_rot(xform, angle1, Yaxis);
2041 set_rot(xform, angle2, Xaxis);
2042 set_rot(xform, -angle, Yaxis);
2043 set_rot(xform, -angle2, Xaxis);
2044 set_rot(xform, -angle1, Yaxis);
2045
2046 xform_coords( xform, dir_x, dir_y, dir_z,
2047 &new_dir_x, &new_dir_y, &new_dir_z);
2048
2049 *to_x = w->picture.navigate_from_x + new_dir_x;
2050 *to_y = w->picture.navigate_from_y + new_dir_y;
2051 *to_z = w->picture.navigate_from_z + new_dir_z;
2052 dir_x = -new_dir_x;
2053 dir_y = -new_dir_y;
2054 dir_z = -new_dir_z;
2055 *up_x = w->picture.navigate_up_x;
2056 *up_y = w->picture.navigate_up_y;
2057 *up_z = w->picture.navigate_up_z;
2058 *autocamera_width = w->picture.autocamera_width;
2059 break;
2060 case XmLOOK_UP:
2061 set_rot(xform, angle1, Yaxis);
2062 set_rot(xform, angle2, Xaxis);
2063 set_rot(xform, angle3, Yaxis);
2064 set_rot(xform, -angle, Xaxis);
2065 set_rot(xform, -angle3, Yaxis);
2066 set_rot(xform, -angle2, Xaxis);
2067 set_rot(xform, -angle1, Yaxis);
2068
2069 xform_coords( xform, dir_x, dir_y, dir_z,
2070 &new_dir_x, &new_dir_y, &new_dir_z);
2071
2072 xform_coords(xform, w->picture.navigate_up_x,
2073 w->picture.navigate_up_y,
2074 w->picture.navigate_up_z, up_x, up_y, up_z);
2075
2076 *to_x = w->picture.navigate_from_x + new_dir_x;
2077 *to_y = w->picture.navigate_from_y + new_dir_y;
2078 *to_z = w->picture.navigate_from_z + new_dir_z;
2079 dir_x = -new_dir_x;
2080 dir_y = -new_dir_y;
2081 dir_z = -new_dir_z;
2082 *autocamera_width = w->picture.autocamera_width;
2083 break;
2084 case XmLOOK_DOWN:
2085 set_rot(xform, angle1, Yaxis);
2086 set_rot(xform, angle2, Xaxis);
2087 set_rot(xform, angle3, Yaxis);
2088 set_rot(xform, angle, Xaxis);
2089 set_rot(xform, -angle3, Yaxis);
2090 set_rot(xform, -angle2, Xaxis);
2091 set_rot(xform, -angle1, Yaxis);
2092
2093 xform_coords( xform, dir_x, dir_y, dir_z,
2094 &new_dir_x, &new_dir_y, &new_dir_z);
2095
2096 xform_coords( xform, w->picture.navigate_up_x,
2097 w->picture.navigate_up_y,
2098 w->picture.navigate_up_z,
2099 up_x, up_y, up_z);
2100
2101 *to_x = w->picture.navigate_from_x + new_dir_x;
2102 *to_y = w->picture.navigate_from_y + new_dir_y;
2103 *to_z = w->picture.navigate_from_z + new_dir_z;
2104 dir_x = -new_dir_x;
2105 dir_y = -new_dir_y;
2106 dir_z = -new_dir_z;
2107 *autocamera_width = w->picture.autocamera_width;
2108 break;
2109 case XmLOOK_BACKWARD:
2110 dx = w->picture.navigate_from_x - w->picture.navigate_to_x;
2111 dy = w->picture.navigate_from_y - w->picture.navigate_to_y;
2112 dz = w->picture.navigate_from_z - w->picture.navigate_to_z;
2113
2114 *to_x = w->picture.navigate_from_x + dx;
2115 *to_y = w->picture.navigate_from_y + dy;
2116 *to_z = w->picture.navigate_from_z + dz;
2117 dir_x = w->picture.navigate_from_x - *to_x;
2118 dir_y = w->picture.navigate_from_y - *to_y;
2119 dir_z = w->picture.navigate_from_z - *to_z;
2120 *up_x = w->picture.navigate_up_x;
2121 *up_y = w->picture.navigate_up_y;
2122 *up_z = w->picture.navigate_up_z;
2123 *autocamera_width = w->picture.autocamera_width;
2124 break;
2125 case XmLOOK_FORWARD:
2126 *to_x = w->picture.navigate_to_x;
2127 *to_y = w->picture.navigate_to_y;
2128 *to_z = w->picture.navigate_to_z;
2129 dir_x = w->picture.navigate_from_x - *to_x;
2130 dir_y = w->picture.navigate_from_y - *to_y;
2131 dir_z = w->picture.navigate_from_z - *to_z;
2132 *up_x = w->picture.navigate_up_x;
2133 *up_y = w->picture.navigate_up_y;
2134 *up_z = w->picture.navigate_up_z;
2135 *autocamera_width = w->picture.autocamera_width;
2136 break;
2137 }
2138 *from_x = dir_x + *to_x;
2139 *from_y = dir_y + *to_y;
2140 *from_z = dir_z + *to_z;
2141 }
2142
2143 /*****************************************************************************/
2144 /* */
2145 /* Subroutine: XmPictureUndoable */
2146 /* Effect: Indicate whether the picture widget is capable of undoing itsef*/
2147 /*****************************************************************************/
2148 void
XmPicturePushUndoCamera(XmPictureWidget w)2149 XmPicturePushUndoCamera(XmPictureWidget w)
2150 {
2151 push_undo_camera(w);
2152 }
2153
2154 /*****************************************************************************/
2155 /* */
2156 /* Subroutine: XmPictureUndoable */
2157 /* Effect: Indicate whether the picture widget is capable of undoing itsef*/
2158 /*****************************************************************************/
2159 Boolean
XmPictureUndoable(XmPictureWidget w)2160 XmPictureUndoable(XmPictureWidget w)
2161 {
2162 return ( (w->picture.undo_count > 0) ? True : False);
2163 }
2164
2165 /*****************************************************************************/
2166 /* */
2167 /* Subroutine: XmPictureRedoable */
2168 /* Effect: Indicate whether the picture widget is capable of redoing itsef*/
2169 /*****************************************************************************/
2170 Boolean
XmPictureRedoable(XmPictureWidget w)2171 XmPictureRedoable(XmPictureWidget w)
2172 {
2173 return ( (w->picture.redo_count > 0) ? True : False);
2174 }
2175
2176 /*****************************************************************************/
2177 /* */
2178 /* Subroutine: XmPictureAlign */
2179 /* Effect: Align the navigation camera with the current view camera */
2180 /*****************************************************************************/
2181 void
XmPictureAlign(XmPictureWidget w)2182 XmPictureAlign(XmPictureWidget w)
2183 {
2184 w->picture.look_at_direction = XmLOOK_FORWARD;
2185 w->picture.look_at_angle = 0.0;
2186 w->picture.navigate_to_x = w->picture.to_x;;
2187 w->picture.navigate_to_y = w->picture.to_y;;
2188 w->picture.navigate_to_z = w->picture.to_z;;
2189 w->picture.navigate_from_x = w->picture.from_x;
2190 w->picture.navigate_from_y = w->picture.from_y;
2191 w->picture.navigate_from_z = w->picture.from_z;
2192 w->picture.navigate_up_x = w->picture.up_x;
2193 w->picture.navigate_up_y = w->picture.up_y;
2194 w->picture.navigate_up_z = w->picture.up_z;
2195 }
2196
2197 /*****************************************************************************/
2198 /* */
2199 /* Subroutine: XmPictureTurnCamera */
2200 /* Effect: Convieniece routine to calc new camera */
2201 /*****************************************************************************/
XmPictureTurnCamera(XmPictureWidget w,int direction,double angle,double * to_x,double * to_y,double * to_z,double * from_x,double * from_y,double * from_z,double * up_x,double * up_y,double * up_z,double * autocamera_width)2202 void XmPictureTurnCamera(XmPictureWidget w, int direction, double angle,
2203 double *to_x, double *to_y, double *to_z,
2204 double *from_x, double *from_y, double *from_z,
2205 double *up_x, double *up_y, double *up_z,
2206 double *autocamera_width)
2207
2208 {
2209 double l;
2210 double angle1;
2211 double angle2;
2212 double angle3;
2213 double xform[4][4];
2214 double dx, dy, dz;
2215 double up_xp, up_yp, up_zp;
2216 double dir_x, dir_y, dir_z;
2217 double dir_xp, dir_yp, dir_zp;
2218 double dir_xpp, dir_ypp, dir_zpp;
2219 double new_dir_x, new_dir_y, new_dir_z;
2220
2221 /*
2222 * Note that the normal interpretation of "direction" is reversed here
2223 * for the convience of calculations. It is reversed when the final
2224 * results are calculated.
2225 */
2226 dir_x = w->picture.to_x - w->picture.from_x;
2227 dir_y = w->picture.to_y - w->picture.from_y;
2228 dir_z = w->picture.to_z - w->picture.from_z;
2229
2230 /*
2231 * Rotate the up vector so it is aligned with the Y axis
2232 */
2233 l = sqrt(w->picture.up_x*w->picture.up_x + w->picture.up_z*w->picture.up_z);
2234 if (l != 0.0)
2235 {
2236 angle1 = acos(w->picture.up_z/l);
2237 }
2238 else
2239 {
2240 angle1 = 0.0;
2241 }
2242 if (w->picture.up_x > 0)
2243 {
2244 angle1 = -angle1;
2245 }
2246 I44(xform);
2247 set_rot(xform, angle1, Yaxis);
2248 xform_coords( xform, w->picture.up_x, w->picture.up_y, w->picture.up_z,
2249 &up_xp, &up_yp, &up_zp);
2250 xform_coords( xform, dir_x, dir_y, dir_z, &dir_xp, &dir_yp, &dir_zp);
2251
2252 /*
2253 * Rotation about the x axis
2254 */
2255 l = sqrt(up_yp*up_yp + up_zp*up_zp);
2256 if (l != 0.0)
2257 {
2258 angle2 = acos(up_yp/l);
2259 }
2260 else
2261 {
2262 angle2 = 0.0;
2263 }
2264 if (up_zp > 0)
2265 {
2266 angle2 = -angle2;
2267 }
2268
2269 I44(xform);
2270 set_rot(xform, angle2, Xaxis);
2271 xform_coords( xform, dir_xp, dir_yp, dir_zp, &dir_xpp, &dir_ypp, &dir_zpp);
2272
2273 /*
2274 * Now, rotate the dir_pp vector about the Y axis so it lies
2275 * in the x=0 plane
2276 */
2277 l = sqrt(dir_xpp*dir_xpp + dir_zpp*dir_zpp);
2278 if (l != 0.0)
2279 {
2280 angle3 = acos(dir_zpp/l);
2281 }
2282 else
2283 {
2284 angle3 = 0.0;
2285 }
2286 if (dir_xpp > 0)
2287 {
2288 angle3 = -angle3;
2289 }
2290
2291 I44(xform);
2292 switch(direction)
2293 {
2294 case XmTURN_LEFT:
2295 /*
2296 * Rotate about the z axis
2297 */
2298 set_rot(xform, angle1, Yaxis);
2299 set_rot(xform, angle2, Xaxis);
2300 set_rot(xform, angle, Yaxis);
2301 set_rot(xform, -angle2, Xaxis);
2302 set_rot(xform, -angle1, Yaxis);
2303
2304 xform_coords( xform, dir_x, dir_y, dir_z,
2305 &new_dir_x, &new_dir_y, &new_dir_z);
2306
2307 *to_x = w->picture.from_x + new_dir_x;
2308 *to_y = w->picture.from_y + new_dir_y;
2309 *to_z = w->picture.from_z + new_dir_z;
2310 dir_x = -new_dir_x;
2311 dir_y = -new_dir_y;
2312 dir_z = -new_dir_z;
2313 *up_x = w->picture.up_x;
2314 *up_y = w->picture.up_y;
2315 *up_z = w->picture.up_z;
2316 *autocamera_width = w->picture.autocamera_width;
2317 break;
2318 case XmTURN_RIGHT:
2319 /*
2320 * Rotate about the z axis
2321 */
2322 set_rot(xform, angle1, Yaxis);
2323 set_rot(xform, angle2, Xaxis);
2324 set_rot(xform, -angle, Yaxis);
2325 set_rot(xform, -angle2, Xaxis);
2326 set_rot(xform, -angle1, Yaxis);
2327
2328 xform_coords( xform, dir_x, dir_y, dir_z,
2329 &new_dir_x, &new_dir_y, &new_dir_z);
2330
2331 *to_x = w->picture.from_x + new_dir_x;
2332 *to_y = w->picture.from_y + new_dir_y;
2333 *to_z = w->picture.from_z + new_dir_z;
2334 dir_x = -new_dir_x;
2335 dir_y = -new_dir_y;
2336 dir_z = -new_dir_z;
2337 *up_x = w->picture.up_x;
2338 *up_y = w->picture.up_y;
2339 *up_z = w->picture.up_z;
2340 *autocamera_width = w->picture.autocamera_width;
2341 break;
2342 case XmTURN_UP:
2343 set_rot(xform, angle1, Yaxis);
2344 set_rot(xform, angle2, Xaxis);
2345 set_rot(xform, angle3, Yaxis);
2346 set_rot(xform, -angle, Xaxis);
2347 set_rot(xform, -angle3, Yaxis);
2348 set_rot(xform, -angle2, Xaxis);
2349 set_rot(xform, -angle1, Yaxis);
2350
2351 xform_coords( xform, dir_x, dir_y, dir_z,
2352 &new_dir_x, &new_dir_y, &new_dir_z);
2353
2354 xform_coords(xform, w->picture.up_x, w->picture.up_y,
2355 w->picture.up_z, up_x, up_y, up_z);
2356
2357 *to_x = w->picture.from_x + new_dir_x;
2358 *to_y = w->picture.from_y + new_dir_y;
2359 *to_z = w->picture.from_z + new_dir_z;
2360 dir_x = -new_dir_x;
2361 dir_y = -new_dir_y;
2362 dir_z = -new_dir_z;
2363 *autocamera_width = w->picture.autocamera_width;
2364 break;
2365 case XmTURN_DOWN:
2366 set_rot(xform, angle1, Yaxis);
2367 set_rot(xform, angle2, Xaxis);
2368 set_rot(xform, angle3, Yaxis);
2369 set_rot(xform, angle, Xaxis);
2370 set_rot(xform, -angle3, Yaxis);
2371 set_rot(xform, -angle2, Xaxis);
2372 set_rot(xform, -angle1, Yaxis);
2373
2374 xform_coords( xform, dir_x, dir_y, dir_z,
2375 &new_dir_x, &new_dir_y, &new_dir_z);
2376
2377 xform_coords( xform, w->picture.up_x, w->picture.up_y,
2378 w->picture.up_z, up_x, up_y, up_z);
2379
2380 *to_x = w->picture.from_x + new_dir_x;
2381 *to_y = w->picture.from_y + new_dir_y;
2382 *to_z = w->picture.from_z + new_dir_z;
2383 dir_x = -new_dir_x;
2384 dir_y = -new_dir_y;
2385 dir_z = -new_dir_z;
2386 *autocamera_width = w->picture.autocamera_width;
2387 break;
2388 case XmTURN_BACK:
2389 dx = w->picture.from_x - w->picture.to_x;
2390 dy = w->picture.from_y - w->picture.to_y;
2391 dz = w->picture.from_z - w->picture.to_z;
2392
2393 *to_x = w->picture.from_x + dx;
2394 *to_y = w->picture.from_y + dy;
2395 *to_z = w->picture.from_z + dz;
2396 dir_x = w->picture.from_x - *to_x;
2397 dir_y = w->picture.from_y - *to_y;
2398 dir_z = w->picture.from_z - *to_z;
2399 *up_x = w->picture.up_x;
2400 *up_y = w->picture.up_y;
2401 *up_z = w->picture.up_z;
2402 *autocamera_width = w->picture.autocamera_width;
2403 break;
2404 }
2405 *from_x = dir_x + *to_x;
2406 *from_y = dir_y + *to_y;
2407 *from_z = dir_z + *to_z;
2408 }
2409 /*****************************************************************************/
2410 /* */
2411 /* Subroutine: XmPictureLoadCursors */
2412 /* Effect: Convieniece routine to load a new set of cursors */
2413 /*****************************************************************************/
2414 void
XmPictureLoadCursors(XmPictureWidget w,int n_cursors,double ** vector_list)2415 XmPictureLoadCursors(XmPictureWidget w,
2416 int n_cursors,
2417 double **vector_list)
2418 {
2419 int i;
2420 double x;
2421 double y;
2422 double z;
2423 double xp;
2424 double yp;
2425 double zp;
2426 int n_cur;
2427
2428 if (!w->picture.camera_defined) return;
2429 /*
2430 * Blow away the old ones.
2431 */
2432 /*
2433 * Set n_cur locally since delete_cursor decrements
2434 * w->picture.n_cursors.
2435 */
2436 n_cur = w->picture.n_cursors;
2437 for (i = 0; i < n_cur; i++)
2438 {
2439 delete_cursor(w, 0);
2440 }
2441
2442 /*
2443 * Create the cursor
2444 */
2445 w->picture.selected = (int *)XtMalloc(n_cursors * sizeof(int));
2446 w->picture.xbuff = (int *)XtMalloc(n_cursors * sizeof(int));
2447 w->picture.ybuff = (int *)XtMalloc(n_cursors * sizeof(int));
2448 w->picture.zbuff = (double *)XtMalloc(n_cursors * sizeof(double));
2449 w->picture.cxbuff = (double *)XtMalloc(n_cursors * sizeof(double));
2450 w->picture.cybuff = (double *)XtMalloc(n_cursors * sizeof(double));
2451 w->picture.czbuff = (double *)XtMalloc(n_cursors * sizeof(double));
2452
2453 /*
2454 * Load the new ones.
2455 */
2456 for (i = 0; i < n_cursors; i++)
2457 {
2458 x = *(vector_list[i] + 0);
2459 y = *(vector_list[i] + 1);
2460 z = *(vector_list[i] + 2);
2461
2462 /*
2463 * xform from world coords --> screen coords
2464 */
2465 xform_coords( w->picture.PureWtrans, x, y, z, &xp, &yp, &zp);
2466 perspective_divide(w, xp, yp, zp, &xp, &yp);
2467 w->picture.xbuff[i] = xp;
2468 w->picture.ybuff[i] = yp;
2469 w->picture.zbuff[i] = zp;
2470 save_cursors_in_canonical_form(w, i);
2471 }
2472
2473 w->picture.n_cursors = n_cursors;
2474
2475 /*
2476 * Grow the bounding box if necessary.
2477 */
2478 setup_bounding_box(w);
2479 if ( (w->picture.mode == XmCURSOR_MODE) ||
2480 (w->picture.mode == XmROAM_MODE) )
2481 {
2482 erase_image(w);
2483 draw_gnomon(w);
2484 XmDrawGlobe(w);
2485 XmDrawBbox(w);
2486 draw_cursors(w);
2487 }
2488 if (w->picture.mode == XmPICK_MODE)
2489 {
2490 erase_image(w);
2491 draw_cursors(w);
2492 }
2493 }
2494 /*****************************************************************************/
2495 /* */
2496 /* Subroutine: XmPictureDeleteCursor */
2497 /* Effect: Convieniece routine to delete cursors */
2498 /*****************************************************************************/
2499 void
XmPictureDeleteCursors(XmPictureWidget w,int cursor_num)2500 XmPictureDeleteCursors(XmPictureWidget w,
2501 int cursor_num)
2502 {
2503 int i;
2504 int n_cursors;
2505
2506 /*
2507 * Blow away the old one(s).
2508 */
2509 if (cursor_num == -1)
2510 {
2511 /*
2512 * Set n_cursors locally since delete_cursor decrements
2513 * w->picture.n_cursors.
2514 */
2515 n_cursors = w->picture.n_cursors;
2516 for (i = 0; i < n_cursors; i++)
2517 {
2518 delete_cursor(w, 0);
2519 }
2520 }
2521 else
2522 {
2523 if (cursor_num < w->picture.n_cursors)
2524 {
2525 delete_cursor(w, cursor_num);
2526 }
2527 else
2528 {
2529 XtWarning ("Bad cursor number in XmPictureDeleteCursors");
2530 return;
2531 }
2532 }
2533
2534 /*
2535 * Display if required
2536 */
2537 if ( (w->picture.mode == XmCURSOR_MODE) ||
2538 (w->picture.mode == XmPICK_MODE) )
2539 {
2540 draw_cursors(w);
2541 }
2542
2543 }
2544
2545
2546 /*****************************************************************************/
2547 /* */
2548 /* Subroutine: XmPictureNewCamera */
2549 /* Effect: Convieniece routine to set new camera */
2550 /* if ignore_new_camera == 0, then update all the internal */
2551 /* camera information, and calculate a new transform. If */
2552 /* ignore_new_camera > 0, then only calc a new transform. */
2553 /*****************************************************************************/
2554 Boolean
XmPictureNewCamera(XmPictureWidget w,XmBasis basis,double matrix[4][4],double from_x,double from_y,double from_z,double to_x,double to_y,double to_z,double up_x,double up_y,double up_z,int image_width,int image_height,double autocamera_width,Boolean autoaxis_enabled,int projection,double view_angle)2555 XmPictureNewCamera(XmPictureWidget w,
2556 XmBasis basis, double matrix[4][4],
2557 double from_x, double from_y, double from_z,
2558 double to_x, double to_y, double to_z,
2559 double up_x, double up_y, double up_z,
2560 int image_width, int image_height, double autocamera_width,
2561 Boolean autoaxis_enabled, int projection, double view_angle)
2562 {
2563 double angle1;
2564 double angle2;
2565 double angle3;
2566 double xform[4][4];
2567 double Wtrans[4][4];
2568 double up_xp, up_yp, up_zp; /* x', y', z' */
2569 double dir_x, dir_y, dir_z; /* x', y', z' */
2570 double dir_xp, dir_yp, dir_zp; /* x', y', z' */
2571 double up_xpp, up_ypp, up_zpp; /* x'', y'', z'' */
2572 double l;
2573 double new_to_x, new_to_y, new_to_z;
2574 int i;
2575 int j;
2576 Boolean was_camera_defined = w->picture.camera_defined;
2577 Boolean new_basis;
2578 Boolean new_camera;
2579 struct
2580 {
2581 double x;
2582 double y;
2583 double z;
2584 } v, zaxis, xaxis, yaxis, screen_from;
2585 Boolean good_bbox = True;
2586 double center_x;
2587 double center_y;
2588
2589 if (w->picture.ignore_new_camera < 0)
2590 {
2591 #ifdef Comment
2592 XtWarning("Internal Error - XmPicture");
2593 #endif
2594 w->picture.ignore_new_camera = 0;
2595 }
2596 w->picture.camera_defined = True;
2597 if (was_camera_defined) {
2598 new_basis = False;
2599 for (i = 0; i < 4; i++)
2600 {
2601 for (j = 0; j < 4; j++)
2602 {
2603 if (basis.Bw[i][j] != w->picture.basis.Bw[i][j])
2604 {
2605 new_basis = True;
2606 break;
2607 }
2608 }
2609 }
2610 } else {
2611 new_basis = True;
2612 }
2613 new_camera = False;
2614 if (w->picture.ignore_new_camera == 0)
2615 {
2616 if( !was_camera_defined ||
2617 (from_x != w->picture.from_x) ||
2618 (from_y != w->picture.from_y) ||
2619 (from_z != w->picture.from_z) ||
2620 (up_x != w->picture.up_x ) ||
2621 (up_y != w->picture.up_y ) ||
2622 (up_z != w->picture.up_z ) ||
2623 (to_x != w->picture.to_x ) ||
2624 (to_y != w->picture.to_y ) ||
2625 (to_z != w->picture.to_z ) ||
2626 (autocamera_width != w->picture.autocamera_width) ||
2627 (autoaxis_enabled != w->picture.autoaxis_enabled) ||
2628 (image_width != w->picture.image_width) ||
2629 (image_height != w->picture.image_height) )
2630 {
2631 w->picture.from_x = from_x;
2632 w->picture.from_y = from_y;
2633 w->picture.from_z = from_z;
2634 w->picture.to_x = to_x;
2635 w->picture.to_y = to_y;
2636 w->picture.to_z = to_z;
2637 w->picture.up_x = up_x;
2638 w->picture.up_y = up_y;
2639 w->picture.up_z = up_z;
2640 w->picture.image_height = image_height;
2641 w->picture.image_width = image_width;
2642 w->picture.autocamera_width = autocamera_width;
2643 w->picture.autoaxis_enabled = autoaxis_enabled;
2644 w->picture.roam_cxbuff = to_x;
2645 w->picture.roam_cybuff = to_y;
2646 w->picture.roam_czbuff = to_z;
2647
2648 /*
2649 * If we are not currently navigating, update the navigation camera
2650 */
2651 if ((w->picture.mode != XmNAVIGATE_MODE) ||
2652 w->picture.first_step)
2653 {
2654 set_nav_camera_from_camera(w);
2655 /*
2656 * Handling ignore_new_camera like this allows the first
2657 * camera of a navigation interaction to flow into the
2658 * widget (this is required since we automatically go into
2659 * a perspective camera, and we need to update the data
2660 * structure to reflect this). This means that when starting
2661 * a navigation sequence, we will wait for the first image to
2662 * come in before requesting a second. After the first image,
2663 * we stay one ahead of the exec by queueing an execution
2664 * after we are informed that the exec has started to work on the
2665 * previous request (this is done in XmPictureExecutionState).
2666 */
2667 if ( (w->picture.mode == XmNAVIGATE_MODE) &&
2668 (w->picture.button_pressed != 0) )
2669 {
2670 w->picture.ignore_new_camera++;
2671 w->picture.first_step = False;
2672 CallNavigateCallbacks(w, w->picture.old_x, w->picture.old_y,
2673 XmPCR_DRAG);
2674 }
2675 }
2676
2677 new_camera = True;
2678 }
2679 }
2680
2681 if (new_camera)
2682 {
2683 if (!w->picture.globe) generate_globe(w, (double)w->picture.globe_radius);
2684 dir_x = from_x - to_x;
2685 dir_y = from_y - to_y;
2686 dir_z = from_z - to_z;
2687
2688 /*
2689 * Set the globe to match the current image if we are not ignoring it
2690 * (i.e. during interactive rotation)
2691 */
2692 if (w->picture.ignore_new_camera == 0)
2693 {
2694 /*
2695 * Rotation about the y axis
2696 */
2697 l = sqrt(dir_x*dir_x + dir_z*dir_z);
2698 if (l != 0.0)
2699 {
2700 angle1 = acos(dir_z/l);
2701 }
2702 else
2703 {
2704 angle1 = 0.0;
2705 }
2706 if (dir_x > 0)
2707 {
2708 angle1 = -angle1;
2709 }
2710 I44(xform);
2711 set_rot(xform, angle1, Yaxis);
2712 xform_coords(xform, up_x, up_y, up_z, &up_xp, &up_yp, &up_zp);
2713 xform_coords(xform, dir_x, dir_y, dir_z, &dir_xp, &dir_yp, &dir_zp);
2714
2715 /*
2716 * Rotation about the x axis
2717 */
2718 l = sqrt(dir_yp*dir_yp + dir_zp*dir_zp);
2719 if (l != 0.0)
2720 {
2721 angle2 = acos(dir_zp/l);
2722 }
2723 else
2724 {
2725 angle2 = 0.0;
2726 }
2727 if (dir_yp < 0)
2728 {
2729 angle2 = -angle2;
2730 }
2731
2732 I44(xform);
2733 set_rot(xform, angle2, Xaxis);
2734 xform_coords(xform, up_xp, up_yp, up_zp, &up_xpp, &up_ypp, &up_zpp);
2735
2736 /*
2737 * Rotate about the z axis so that the up vector is aligned
2738 * w/ the y axis
2739 */
2740 l = sqrt(up_xpp*up_xpp+ up_ypp*up_ypp);
2741 if (l != 0.0)
2742 {
2743 angle3 = acos(up_ypp/l);
2744 }
2745 else
2746 {
2747 angle3 = 0.0;
2748 }
2749 if (up_xpp < 0)
2750 {
2751 angle3 = -angle3;
2752 }
2753
2754 I44(w->picture.globe->Wtrans);
2755 set_rot(w->picture.globe->Wtrans, angle1, Yaxis);
2756 set_rot(w->picture.globe->Wtrans, -angle2, Xaxis);
2757 set_rot(w->picture.globe->Wtrans, -angle3, Zaxis);
2758 }
2759 }
2760
2761 /*
2762 * Calculate the new world to screen transform
2763 */
2764 v.x = from_x - to_x;
2765 v.y = from_y - to_y;
2766 v.z = from_z - to_z;
2767
2768 l = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
2769 zaxis.x = v.x/l;
2770 zaxis.y = v.y/l;
2771 zaxis.z = v.z/l;
2772
2773 /* up X zaxis */
2774 v.x = up_y * zaxis.z - up_z * zaxis.y;
2775 v.y = up_z * zaxis.x - up_x * zaxis.z;
2776 v.z = up_x * zaxis.y - up_y * zaxis.x;
2777
2778 l = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
2779 xaxis.x = v.x/l;
2780 xaxis.y = v.y/l;
2781 xaxis.z = v.z/l;
2782
2783 /* zaxis X xaxis */
2784 v.x = zaxis.y * xaxis.z - zaxis.z * xaxis.y;
2785 v.y = zaxis.z * xaxis.x - zaxis.x * xaxis.z;
2786 v.z = zaxis.x * xaxis.y - zaxis.y * xaxis.x;
2787
2788 l = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
2789 yaxis.x = v.x/l;
2790 yaxis.y = v.y/l;
2791 yaxis.z = v.z/l;
2792
2793 for (i = 0; i < 4; i++)
2794 for (j = 0; j < 4; j++)
2795 w->picture.PureWtrans[i][j] = matrix[i][j];
2796
2797 if (new_camera || new_basis)
2798 {
2799 inverse(matrix, xform);
2800 for (i = 0; i < 4; i++)
2801 xform_coords(xform, basis.Bw[i][0], basis.Bw[i][1], basis.Bw[i][2],
2802 &basis.Bw[i][0], &basis.Bw[i][1], &basis.Bw[i][2]);
2803 }
2804
2805 I44(Wtrans);
2806
2807 I44(xform);
2808 xform[3][0] = -from_x;
2809 xform[3][1] = -from_y;
2810 xform[3][2] = -from_z;
2811
2812 mult44(Wtrans, xform);
2813
2814 I44(xform);
2815 xform[0][0] = xaxis.x; xform[0][1] = -yaxis.x; xform[0][2] = zaxis.x;
2816 xform[1][0] = xaxis.y; xform[1][1] = -yaxis.y; xform[1][2] = zaxis.y;
2817 xform[2][0] = xaxis.z; xform[2][1] = -yaxis.z; xform[2][2] = zaxis.z;
2818
2819 mult44(Wtrans, xform);
2820
2821 I44(xform);
2822 xform[0][0] = (double)image_width/autocamera_width;
2823 xform[1][1] = (double)image_width/autocamera_width;
2824 mult44(Wtrans, xform);
2825
2826
2827 xform_coords(Wtrans, to_x, to_y, to_z, &new_to_x, &new_to_y, &new_to_z);
2828
2829 I44(xform);
2830 xform[3][0] += image_width/2;
2831 xform[3][1] += image_height/2;
2832 xform[3][2] -= new_to_z;
2833
2834 mult44(Wtrans, xform);
2835
2836 mult44(w->picture.PureWtrans, Wtrans);
2837
2838 inverse ( w->picture.PureWtrans, w->picture.PureWItrans );
2839
2840 /*
2841 * Pre-calculate values needed for perspective
2842 */
2843 if (projection == 1)
2844 {
2845 w->picture.DW = (image_width/2)/tan(2*M_PI*view_angle/360);
2846 w->picture.DH = (image_height/2)/tan(2*M_PI*view_angle/360);
2847
2848 /*
2849 * w->picture.D is the value the camera SHOULD be at. Since it is
2850 * not, calc a zscale factor, and use it to adjust the z's for
2851 * perspective calculations.
2852 * D = camera_z * zscale
2853 */
2854 xform_coords(w->picture.PureWtrans, from_x, from_y, from_z,
2855 &screen_from.x, &screen_from.y, &screen_from.z);
2856 w->picture.zscale_width = w->picture.DW/screen_from.z;
2857 w->picture.zscale_height = w->picture.DH/screen_from.z;
2858
2859 }
2860 w->picture.view_angle = view_angle;
2861 w->picture.projection = projection;
2862
2863 if (w->picture.ignore_new_camera == 0)
2864 {
2865 if (new_basis) w->picture.basis = basis;
2866
2867 if ( (new_basis || new_camera) &&
2868 ((w->picture.mode == XmCURSOR_MODE) ||
2869 (w->picture.mode == XmROAM_MODE)) )
2870 {
2871 setup_bounding_box(w);
2872 calc_projected_axis(w);
2873 setup_gnomon(w, False);
2874 restore_cursors_from_canonical_form(w);
2875 }
2876 if ( (w->picture.mode == XmCURSOR_MODE) ||
2877 (w->picture.mode == XmROAM_MODE) )
2878 {
2879 if ( (!w->image.frame_buffer) || new_basis || new_camera)
2880 {
2881 erase_image(w);
2882 draw_gnomon(w);
2883 XmDrawGlobe (w);
2884 XmDrawBbox (w);
2885 draw_cursors(w);
2886 }
2887 }
2888 if (w->picture.mode == XmROTATION_MODE)
2889 {
2890 if ( (!w->image.frame_buffer) || new_camera)
2891 {
2892 setup_bounding_box(w);
2893 calc_projected_axis(w);
2894 setup_gnomon(w, False);
2895 erase_image(w);
2896 XmDrawGlobe (w);
2897 draw_gnomon (w);
2898 }
2899 }
2900 if (new_basis || new_camera)
2901 {
2902 for(i = 0; i < 4; i++)
2903 {
2904 xform_coords( w->picture.PureWtrans,
2905 basis.Bw[i][0], basis.Bw[i][1], basis.Bw[i][2],
2906 &basis.Bs[i][0],&basis.Bs[i][1],&basis.Bs[i][2]);
2907 }
2908 center_x = w->core.width/2;
2909 center_y = w->core.height/2;
2910 if ( (fabs(basis.Bs[0][0] - center_x) < 1) &&
2911 (fabs(basis.Bs[1][0] - center_x) < 1) &&
2912 (fabs(basis.Bs[2][0] - center_x) < 1) &&
2913 (fabs(basis.Bs[3][0] - center_x) < 1) &&
2914 (fabs(basis.Bs[0][1] - center_y) < 1) &&
2915 (fabs(basis.Bs[1][1] - center_y) < 1) &&
2916 (fabs(basis.Bs[2][1] - center_y) < 1) &&
2917 (fabs(basis.Bs[3][1] - center_y) < 1) )
2918 good_bbox = False;
2919 }
2920
2921 }
2922 if (w->image.frame_buffer)
2923 {
2924 w->picture.disable_temp = False;
2925 }
2926
2927 return good_bbox;
2928 }
2929 /*****************************************************************************/
2930 /* */
2931 /* Subroutine: XmPictureExecutionState */
2932 /* Effect: Find out EXACTLY when the exec begins a new execution or */
2933 /* ends an execution when in background mode. */
2934 /*****************************************************************************/
2935 void
XmPictureExecutionState(XmPictureWidget w,Boolean begin)2936 XmPictureExecutionState(XmPictureWidget w, Boolean begin)
2937 {
2938 if( !((w->picture.mode == XmNAVIGATE_MODE) &&
2939 (w->picture.button_pressed != 0)) )
2940 {
2941 return;
2942 }
2943
2944 if (!w->picture.first_step)
2945 {
2946 if(begin)
2947 {
2948 CallNavigateCallbacks(w, w->picture.old_x, w->picture.old_y,
2949 XmPCR_DRAG);
2950 }
2951 }
2952 }
2953
2954 /*****************************************************************************/
2955 /* */
2956 /* Subroutine: XmPictureMoveCamera */
2957 /* Effect: Routine to calc new direction and up vector given a rot matrix*/
2958 /*****************************************************************************/
2959 static void
XmPictureMoveCamera(XmPictureWidget w,double Wtrans[4][4],double * from_newx,double * from_newy,double * from_newz,double * up_newx,double * up_newy,double * up_newz)2960 XmPictureMoveCamera( XmPictureWidget w,
2961 double Wtrans[4][4],
2962 double *from_newx, double *from_newy, double *from_newz,
2963 double *up_newx, double *up_newy, double *up_newz)
2964 {
2965 double angle1;
2966 double angle2;
2967 double angle3;
2968 double l;
2969 double xform[4][4];
2970 double up_x, up_y, up_z; /* x, y, z */
2971 double dir_x, dir_y, dir_z; /* x, y, z */
2972 double up_xp, up_yp, up_zp; /* x', y', z' */
2973 double dir_xp, dir_yp, dir_zp; /* x', y', z' */
2974 double up_xpp, up_ypp, up_zpp; /* x'', y'', z'' */
2975 double dir_newx, dir_newy, dir_newz; /* x'', y'', z'' */
2976
2977 /*
2978 * The overall stategy is to rotate the direction vector so it is aligned
2979 * with the positive Z axis, then rotate the up vector so it is aligned
2980 * with the positive y axis. Build the matrix that performs these rotates,
2981 * apply it to a camera dir of (0, 0, 1) and an up of (0, 1, 0)
2982 */
2983
2984 xform_coords( Wtrans, 0.0, 1.0, 0.0, &up_x, &up_y, &up_z);
2985 xform_coords( Wtrans, 0.0, 0.0, 1.0, &dir_x, &dir_y, &dir_z);
2986
2987 /*
2988 * Rotation about the y axis
2989 */
2990 l = sqrt(dir_x*dir_x + dir_z*dir_z);
2991 if (l != 0.0)
2992 {
2993 angle1 = acos(dir_z/l);
2994 }
2995 else
2996 {
2997 angle1 = 0.0;
2998 }
2999 if (dir_x > 0)
3000 {
3001 angle1 = -angle1;
3002 }
3003 I44(xform);
3004 set_rot(xform, angle1, Yaxis);
3005 xform_coords( xform, up_x, up_y, up_z, &up_xp, &up_yp, &up_zp);
3006 xform_coords( xform, dir_x, dir_y, dir_z, &dir_xp, &dir_yp, &dir_zp);
3007
3008 /*
3009 * Rotation about the x axis
3010 */
3011 l = sqrt(dir_yp*dir_yp + dir_zp*dir_zp);
3012 if (l != 0.0)
3013 {
3014 angle2 = acos(dir_zp/l);
3015 }
3016 else
3017 {
3018 angle2 = 0.0;
3019 }
3020 if (dir_yp < 0)
3021 {
3022 angle2 = -angle2;
3023 }
3024
3025 I44(xform);
3026 set_rot(xform, angle2, Xaxis);
3027 xform_coords(xform, up_xp, up_yp, up_zp, &up_xpp, &up_ypp, &up_zpp);
3028
3029 /*
3030 * Rotate about the z axis so that the up vector is aligned w/ the y axis
3031 */
3032 l = sqrt(up_xpp*up_xpp+ up_ypp*up_ypp);
3033 if (l != 0.0)
3034 {
3035 angle3 = acos(up_ypp/l);
3036 }
3037 else
3038 {
3039 angle3 = 0.0;
3040 }
3041 if (up_xpp < 0)
3042 {
3043 angle3 = -angle3;
3044 }
3045
3046 I44(xform);
3047 set_rot(xform, angle1, Yaxis);
3048 set_rot(xform, -angle2, Xaxis);
3049 set_rot(xform, -angle3, Zaxis);
3050
3051 /*
3052 * We want to preserve the original length of the
3053 * vector between the from point and the to point.
3054 */
3055 l = sqrt( (w->picture.from_x - w->picture.to_x) *
3056 (w->picture.from_x - w->picture.to_x) +
3057 (w->picture.from_y - w->picture.to_y) *
3058 (w->picture.from_y - w->picture.to_y) +
3059 (w->picture.from_z - w->picture.to_z) *
3060 (w->picture.from_z - w->picture.to_z) );
3061
3062 xform_coords( xform, 0.0, 1.0, 0.0, up_newx, up_newy, up_newz);
3063 xform_coords( xform, 0.0, 0.0, l, &dir_newx, &dir_newy, &dir_newz);
3064
3065 *from_newx = dir_newx + w->picture.to_x;
3066 *from_newy = dir_newy + w->picture.to_y;
3067 *from_newz = dir_newz + w->picture.to_z;
3068 }
3069
3070 /*****************************************************************************/
3071 /* */
3072 /* Subroutine: xform_coords */
3073 /* Effect: Convieniece routine to rotate a point given a rotation matrix*/
3074 /*****************************************************************************/
3075 static void
xform_coords(double Wtrans[4][4],double x,double y,double z,double * newx,double * newy,double * newz)3076 xform_coords( double Wtrans[4][4],
3077 double x, double y, double z,
3078 double *newx, double *newy, double *newz)
3079 {
3080 *newx = x*Wtrans[0][Xaxis] +
3081 y*Wtrans[1][Xaxis] +
3082 z*Wtrans[2][Xaxis] +
3083 Wtrans[3][Xaxis];
3084 *newy = x*Wtrans[0][Yaxis] +
3085 y*Wtrans[1][Yaxis] +
3086 z*Wtrans[2][Yaxis] +
3087 Wtrans[3][Yaxis];
3088 *newz = x*Wtrans[0][Zaxis] +
3089 y*Wtrans[1][Zaxis] +
3090 z*Wtrans[2][Zaxis] +
3091 Wtrans[3][Zaxis];
3092
3093 }
3094 /*****************************************************************************/
3095 /* */
3096 /* Subroutine: perspective_divide */
3097 /* Effect: */
3098 /*****************************************************************************/
3099 static void
perspective_divide(XmPictureWidget w,double x,double y,double z,double * newx,double * newy)3100 perspective_divide( XmPictureWidget w,
3101 double x, double y, double z, double *newx, double *newy)
3102 {
3103 if(w->picture.projection == 0)
3104 {
3105 *newx = x;
3106 *newy = y;
3107 return;
3108 }
3109 x = x - w->core.width/2;
3110 y = y - w->core.height/2;
3111
3112 *newx = x*-w->picture.DW/(z*w->picture.zscale_width - w->picture.DW);
3113 *newy = y*-w->picture.DH/(z*w->picture.zscale_height - w->picture.DH);
3114
3115 *newx += w->core.width/2;
3116 *newy += w->core.height/2;
3117 }
3118
3119 /*****************************************************************************/
3120 /* */
3121 /* Subroutine: perspective_divide_inverse */
3122 /* Effect: */
3123 /*****************************************************************************/
3124 static void
perspective_divide_inverse(XmPictureWidget w,double x,double y,double z,double * newx,double * newy)3125 perspective_divide_inverse( XmPictureWidget w,
3126 double x, double y, double z, double *newx, double *newy)
3127 {
3128 if(w->picture.projection == 0)
3129 {
3130 *newx = x;
3131 *newy = y;
3132 return;
3133 }
3134 x = x - w->core.width/2;
3135 y = y - w->core.height/2;
3136
3137 *newx = x / (-w->picture.DW/(z*w->picture.zscale_width - w->picture.DW));
3138 *newy = y / (-w->picture.DH/(z*w->picture.zscale_height - w->picture.DH));
3139
3140 *newx += w->core.width/2;
3141 *newy += w->core.height/2;
3142 }
3143
3144 #if 0
3145 /************************************************************************
3146 *
3147 * KeyMode
3148 *
3149 ************************************************************************/
3150 static void KeyMode (w, event)
3151 XmPictureWidget w;
3152 XKeyEvent *event;
3153
3154 {
3155 XComposeStatus compose;
3156 int charcount;
3157 char buffer[20];
3158 int bufsize = 20;
3159 XmPictureCallbackStruct cb;
3160
3161 charcount =
3162 XLookupString(event, buffer, bufsize, &w->picture.keysym, &compose);
3163
3164 cb.reason = XmPCR_MODE;
3165 switch(w->picture.keysym)
3166 {
3167 case XK_w:
3168 case XK_W:
3169 cb.mode = XmROAM_MODE;
3170 break;
3171 case XK_i:
3172 case XK_I:
3173 cb.mode = XmPICK_MODE;
3174 break;
3175 case XK_x:
3176 case XK_X:
3177 cb.mode = XmCURSOR_MODE;
3178 break;
3179 case XK_r:
3180 case XK_R:
3181 cb.mode = XmROTATION_MODE;
3182 break;
3183 case XK_z:
3184 case XK_Z:
3185 cb.mode = XmZOOM_MODE;
3186 break;
3187 case XK_n:
3188 case XK_N:
3189 cb.mode = XmNAVIGATE_MODE;
3190 break;
3191 case XK_g:
3192 case XK_G:
3193 cb.mode = XmPANZOOM_MODE;
3194 break;
3195 case XK_u:
3196 case XK_U:
3197 cb.reason = XmPCR_UNDO;
3198 break;
3199 case XK_k:
3200 case XK_K:
3201 case XK_f:
3202 case XK_F:
3203 cb.reason = XmPCR_KEY;
3204 cb.keysym = w->picture.keysym;
3205 break;
3206 }
3207 if(cb.reason == XmPCR_MODE)
3208 {
3209 XtCallCallbacks ((Widget)w, XmNmodeCallback, &cb);
3210 }
3211 else if(cb.reason == XmPCR_KEY)
3212 {
3213 XtCallCallbacks ((Widget)w, XmNkeyCallback, &cb);
3214 }
3215 else
3216 {
3217 XtCallCallbacks ((Widget)w, XmNundoCallback, &cb);
3218 }
3219 }
3220 #endif
3221
3222
3223 /************************************************************************
3224 *
3225 * KeyProc
3226 *
3227 ************************************************************************/
KeyProc(w,event)3228 static void KeyProc (w, event)
3229 XmPictureWidget w;
3230 XKeyEvent *event;
3231
3232 {
3233 XComposeStatus compose;
3234 char buffer[20];
3235 int bufsize = 20;
3236 XmPictureCallbackStruct cb;
3237
3238 XLookupString(event, buffer, bufsize, &w->picture.keysym, &compose);
3239 if (w->picture.mode == XmNAVIGATE_MODE)
3240 {
3241 /*
3242 * Do not allow "roll" if we are not looking forward.
3243 */
3244 if ( (w->picture.look_at_direction != XmLOOK_FORWARD) &&
3245 ( (w->picture.keysym == XK_Left) ||
3246 (w->picture.keysym == XK_Right) ) )
3247 {
3248 return;
3249 }
3250 if (event->type == KeyPress)
3251 {
3252 keyboard_grab(w, True);
3253 if (w->picture.first_key_press)
3254 {
3255 XAutoRepeatOff(XtDisplay(w));
3256 w->picture.key_tid =
3257 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w),
3258 (unsigned long)400, (XtTimerCallbackProc)AutoRepeatTimer, w);
3259 }
3260 switch(w->picture.keysym)
3261 {
3262 case XK_Up:
3263 w->picture.translate_speed_factor += 1;
3264 break;
3265
3266 case XK_Down:
3267 w->picture.translate_speed_factor -= 1;
3268 break;
3269
3270 case XK_Left:
3271 w->picture.rotate_speed_factor -= 1;
3272 break;
3273
3274 case XK_Right:
3275 w->picture.rotate_speed_factor += 1;
3276 break;
3277
3278 default:
3279 break;
3280 }
3281
3282 w->picture.rotate_speed_factor =
3283 MAX(0, w->picture.rotate_speed_factor);
3284 w->picture.rotate_speed_factor =
3285 MIN(100, w->picture.rotate_speed_factor);
3286 w->picture.translate_speed_factor =
3287 MAX(0, w->picture.translate_speed_factor);
3288 w->picture.translate_speed_factor =
3289 MIN(100, w->picture.translate_speed_factor);
3290
3291 if ((w->picture.keysym == XK_Up) || (w->picture.keysym == XK_Down))
3292 {
3293 cb.reason = XmPCR_TRANSLATE_SPEED;
3294 cb.translate_speed = w->picture.translate_speed_factor;
3295 XtCallCallbacks ((Widget)w, XmNnavigateCallback, &cb);
3296 }
3297 if ( (w->picture.keysym == XK_Left) ||
3298 (w->picture.keysym == XK_Right) )
3299 {
3300 cb.reason = XmPCR_ROTATE_SPEED;
3301 cb.rotate_speed = w->picture.rotate_speed_factor;
3302 XtCallCallbacks ((Widget)w, XmNnavigateCallback, &cb);
3303 }
3304 }
3305 if (event->type == KeyRelease)
3306 {
3307 keyboard_grab(w, False);
3308 XAutoRepeatOn(XtDisplay(w));
3309 if (w->picture.key_tid)
3310 {
3311 XtRemoveTimeOut(w->picture.key_tid);
3312 w->picture.key_tid = (XtIntervalId)NULL;
3313 }
3314 w->picture.first_key_press = True;
3315 }
3316 else
3317 {
3318 w->picture.first_key_press = False;
3319 }
3320 }
3321 else if (w->picture.mode == XmROAM_MODE)
3322 {
3323 #ifdef Comment
3324 if (w->picture.first_key_press)
3325 {
3326 XAutoRepeatOff(XtDisplay(w));
3327 xform_coords( w->picture.PureWtrans,
3328 w->picture.to_x, w->picture.to_y, w->picture.to_z,
3329 &w->picture.arrow_roam_x, &w->picture.arrow_roam_y,
3330 &w->picture.arrow_roam_z);
3331 w->picture.key_tid =
3332 XtAppAddTimeOut(XtWidgetToApplicationContext(w),
3333 (unsigned long)400, AutoRepeatTimer, w);
3334 }
3335 switch(w->picture.keysym)
3336 {
3337 case XK_Up:
3338 w->picture.arrow_roam_y += 5;
3339 break;
3340
3341 case XK_Down:
3342 w->picture.arrow_roam_y -= 5;
3343 break;
3344
3345 case XK_Left:
3346 w->picture.arrow_roam_x += 5;
3347 break;
3348
3349 case XK_Right:
3350 w->picture.arrow_roam_x -= 5;
3351 break;
3352 }
3353 if (event->type == KeyRelease)
3354 {
3355 XAutoRepeatOn(XtDisplay(w));
3356 if (w->picture.key_tid)
3357 {
3358 XtRemoveTimeOut(w->picture.key_tid);
3359 w->picture.key_tid = NULL;
3360 }
3361 w->picture.first_key_press = True;
3362 }
3363 else
3364 {
3365 w->picture.first_key_press = False;
3366 }
3367 if (event->type == KeyPress)
3368 {
3369 CallCursorCallbacks(w, XmPCR_MOVE, 0,
3370 w->picture.arrow_roam_x,
3371 w->picture.arrow_roam_y,
3372 w->picture.arrow_roam_z);
3373 }
3374 #endif
3375 }
3376 }
3377 /*****************************************************************************/
3378 /* */
3379 /* Subroutine: AutoRepeatTimer */
3380 /* Effect: */
3381 /* */
3382 /*****************************************************************************/
AutoRepeatTimer(XmPictureWidget w,XtIntervalId * id)3383 XtTimerCallbackProc AutoRepeatTimer( XmPictureWidget w, XtIntervalId *id)
3384 {
3385 XmPictureCallbackStruct cb;
3386
3387 w->picture.key_tid =
3388 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w),
3389 (unsigned long)100, (XtTimerCallbackProc)AutoRepeatTimer, w);
3390
3391 if (w->picture.mode == XmNAVIGATE_MODE)
3392 {
3393 switch(w->picture.keysym)
3394 {
3395 case XK_Up:
3396 w->picture.translate_speed_factor += 3;
3397 break;
3398
3399 case XK_Down:
3400 w->picture.translate_speed_factor -= 3;
3401 break;
3402
3403 case XK_Left:
3404 w->picture.rotate_speed_factor -= 3;
3405 break;
3406
3407 case XK_Right:
3408 w->picture.rotate_speed_factor += 3;
3409 break;
3410
3411 default:
3412 break;
3413 }
3414
3415 w->picture.rotate_speed_factor =
3416 MAX(0, w->picture.rotate_speed_factor);
3417 w->picture.rotate_speed_factor =
3418 MIN(100, w->picture.rotate_speed_factor);
3419 w->picture.translate_speed_factor =
3420 MAX(0, w->picture.translate_speed_factor);
3421 w->picture.translate_speed_factor =
3422 MIN(100, w->picture.translate_speed_factor);
3423
3424 if ( (w->picture.keysym == XK_Up) || (w->picture.keysym == XK_Down) )
3425 {
3426 cb.reason = XmPCR_TRANSLATE_SPEED;
3427 cb.translate_speed = w->picture.translate_speed_factor;
3428 XtCallCallbacks ((Widget)w, XmNnavigateCallback, &cb);
3429 }
3430 if ( (w->picture.keysym == XK_Left) || (w->picture.keysym == XK_Right) )
3431 {
3432 cb.reason = XmPCR_ROTATE_SPEED;
3433 cb.rotate_speed = w->picture.rotate_speed_factor;
3434 XtCallCallbacks ((Widget)w, XmNnavigateCallback, &cb);
3435 }
3436
3437 }
3438 else if (w->picture.mode == XmROAM_MODE)
3439 {
3440 #ifdef Comment
3441 switch(w->picture.keysym)
3442 {
3443 case XK_Up:
3444 w->picture.arrow_roam_y += 5;
3445 break;
3446
3447 case XK_Down:
3448 w->picture.arrow_roam_y -= 5;
3449 break;
3450
3451 case XK_Left:
3452 w->picture.arrow_roam_x += 5;
3453 break;
3454
3455 case XK_Right:
3456 w->picture.arrow_roam_x -= 5;
3457 break;
3458 }
3459 CallCursorCallbacks(w, XmPCR_MOVE, 0,
3460 w->picture.arrow_roam_x,
3461 w->picture.arrow_roam_y,
3462 w->picture.arrow_roam_z);
3463 #endif
3464 }
3465 return NULL;
3466 }
3467
3468 /************************************************************************
3469 *
3470 * BtnMotion
3471 * This function processes motion events occuring on the
3472 * drawing area.
3473 *
3474 ************************************************************************/
3475
BtnMotion(w,event)3476 static void BtnMotion (w, event)
3477 XmPictureWidget w;
3478 XEvent *event;
3479
3480 {
3481
3482 int i, x, y;
3483 double dx, dy, dz;
3484 double major_dx, major_dy;
3485 struct globe *globe;
3486 double ay, az;
3487 double l;
3488 double angle;
3489 double angle_tol;
3490 Boolean warp;
3491 double aspect;
3492 int width;
3493 int height;
3494 int trans_x;
3495 int trans_y;
3496 int id;
3497 XEvent ev;
3498 XmPictureCallbackStruct cb;
3499
3500 if (w->picture.button_pressed == 0) return;
3501 if ( (w->picture.disable_temp) || (!w->picture.good_at_select) )
3502 {
3503 return;
3504 }
3505
3506 x = event->xmotion.x ;
3507 y = event->xmotion.y ;
3508 while (XCheckMaskEvent(XtDisplay(w), ButtonMotionMask, &ev))
3509 {
3510 x = ev.xmotion.x;
3511 y = ev.xmotion.y;
3512 }
3513
3514 if ( w->picture.mode == XmPICK_MODE )
3515 {
3516 return;
3517 }
3518 if ( w->picture.mode == XmZOOM_MODE )
3519 {
3520 if (w->picture.rubber_band.gc == NULL) return;
3521
3522 if ( (!(event->xmotion.state & Button1Mask)) &&
3523 (!(event->xmotion.state & Button3Mask)) )
3524 {
3525 return;
3526 }
3527 /*
3528 * Restrict the zoom box to the window
3529 */
3530 if (x < 0) x = 0;
3531 if (x > w->core.width-1) x = w->core.width - 1;
3532 if (y < 0) y = 0;
3533 if (y > w->core.height-1) y = w->core.height - 1;
3534
3535 /*
3536 * Clear the old rectangle.
3537 */
3538 restore_rectangle(w);
3539
3540 aspect = w->picture.rubber_band.aspect;
3541 width = w->core.width;
3542 height = w->core.height;
3543
3544 trans_x = x - w->picture.rubber_band.center_x;
3545 trans_y = y - w->picture.rubber_band.center_y;
3546
3547 if( ((trans_y >= trans_x*aspect) && (trans_y >= -trans_x*aspect)) ||
3548 ((trans_y <= -trans_x*aspect)&& (trans_y <= trans_x*aspect)) )
3549 {
3550 y = height/2 - abs(trans_y);
3551 x = y/aspect;
3552 }
3553 else
3554 {
3555 x = width/2 - abs(trans_x);
3556 y = x*aspect;
3557 }
3558
3559 height = height - 2*y;
3560 width = width - 2*x;
3561
3562 height = MAX(height, 3);
3563 width = MAX(width, 3);
3564 /*
3565 * Draw the two rectangles (one in black, one in white)
3566 */
3567 if (!w->image.frame_buffer)
3568 {
3569 XSetForeground(XtDisplay(w), w->picture.rubber_band.gc,
3570 w->picture.white );
3571 XDrawRectangle(XtDisplay(w), XtWindow(w),
3572 w->picture.rubber_band.gc, x, y, width, height);
3573 XSetForeground(XtDisplay(w), w->picture.rubber_band.gc,
3574 w->picture.black );
3575 XDrawRectangle(XtDisplay(w), XtWindow(w),
3576 w->picture.rubber_band.gc, x+1, y+1, width-2, height-2);
3577 }
3578 else
3579 {
3580 XSetForeground(XtDisplay(w), w->picture.gcovl,
3581 w->picture.white );
3582 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
3583 w->picture.gcovl, x, y, width, height);
3584 XSetForeground(XtDisplay(w), w->picture.gcovl,
3585 w->picture.black );
3586 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
3587 w->picture.gcovl, x+1, y+1, width-2, height-2);
3588 }
3589
3590 /*
3591 * Remember the position so we can erase it next time.
3592 */
3593 w->picture.rubber_band.old_x = x;
3594 w->picture.rubber_band.old_y = y;
3595 w->picture.rubber_band.old_width = width;
3596 w->picture.rubber_band.old_height = height;
3597 }
3598 if ( w->picture.mode == XmPANZOOM_MODE )
3599 {
3600 if (w->picture.rubber_band.gc == NULL) return;
3601
3602 if ( (!(event->xmotion.state & Button1Mask)) &&
3603 (!(event->xmotion.state & Button3Mask)) )
3604 {
3605 return;
3606 }
3607
3608 /*
3609 * Clear the old rectangle.
3610 */
3611 restore_rectangle(w);
3612
3613 aspect = w->picture.rubber_band.aspect;
3614
3615 trans_x = x - w->picture.rubber_band.center_x;
3616 trans_y = y - w->picture.rubber_band.center_y;
3617
3618 if( ((trans_y >= trans_x*aspect) && (trans_y >= -trans_x*aspect)) ||
3619 ((trans_y <= -trans_x*aspect)&& (trans_y <= trans_x*aspect)) )
3620 {
3621 y = w->picture.rubber_band.center_y - abs(trans_y);
3622 height = 2*(w->picture.rubber_band.center_y - y);
3623 width = height/aspect;
3624 x = w->picture.rubber_band.center_x - width/2;
3625 }
3626 else
3627 {
3628 x = w->picture.rubber_band.center_x - abs(trans_x);
3629 width = 2*(w->picture.rubber_band.center_x - x);
3630 height = width*aspect;
3631 y = w->picture.rubber_band.center_y - height/2;
3632 }
3633
3634 /*
3635 * Make the width and height at least two so some X servers don't die.
3636 */
3637 width = MAX(width, 3);
3638 height = MAX(height, 3);
3639
3640 /*
3641 * Draw the two rectangles (one in black, one in white)
3642 */
3643 if (!w->image.frame_buffer)
3644 {
3645 XSetForeground(XtDisplay(w), w->picture.rubber_band.gc,
3646 w->picture.white );
3647 XDrawRectangle(XtDisplay(w), XtWindow(w),
3648 w->picture.rubber_band.gc, x, y, width, height);
3649 XSetForeground(XtDisplay(w), w->picture.rubber_band.gc,
3650 w->picture.black );
3651 XDrawRectangle(XtDisplay(w), XtWindow(w),
3652 w->picture.rubber_band.gc, x+1, y+1, width-2, height-2);
3653 }
3654 else
3655 {
3656 XSetForeground(XtDisplay(w), w->picture.gcovl,
3657 w->picture.white );
3658 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
3659 w->picture.gcovl, x, y, width, height);
3660 XSetForeground(XtDisplay(w), w->picture.gcovl,
3661 w->picture.black );
3662 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
3663 w->picture.gcovl, x+1, y+1, width-2, height-2);
3664 }
3665
3666 /*
3667 * Remember the position so we can erase it next time.
3668 */
3669 w->picture.rubber_band.old_x = x;
3670 w->picture.rubber_band.old_y = y;
3671 w->picture.rubber_band.old_width = width;
3672 w->picture.rubber_band.old_height = height;
3673 }
3674
3675 if ( (w->picture.mode == XmROTATION_MODE ) ||
3676 (((w->picture.mode == XmCURSOR_MODE) ||
3677 (w->picture.mode == XmROAM_MODE)) &&
3678 (w->picture.button_pressed != Button1)) )
3679 {
3680 #ifdef Comment
3681 if ( ((w->picture.mode == XmCURSOR_MODE) ||
3682 (w->picture.mode == XmROAM_MODE)) &&
3683 (event->xmotion.state & Button1Mask))
3684 {
3685 return;
3686 }
3687 #endif
3688 globe = w->picture.globe;
3689
3690 x = x - w->core.width/2;
3691 y = (y - w->core.height/2);
3692
3693 if (w->picture.K < 2)
3694 {
3695 add2historybuffer(w, x, y);
3696 return;
3697 }
3698
3699 major_dx = x - w->picture.px;
3700 major_dy = y - w->picture.py;
3701 if ((major_dx == 0.0) && (major_dy == 0.0) ) return;
3702
3703 if (!globe->on_sphere)
3704 {
3705 l = sqrt(x*x+y*y);
3706 if (l == 0.0) return;
3707 az = acos((double)x/l);
3708 if (y > 0)
3709 {
3710 az = 2*M_PI - az;
3711 }
3712 /*
3713 * The last point was also off the sphere
3714 */
3715 set_rot(globe->Wtrans, -(az - globe->paz), Zaxis);
3716 globe->paz = az;
3717 }
3718 else /* On the sphere... */
3719 {
3720 dx = major_dx;
3721 dy = major_dy;
3722 az = acos(dx/sqrt(dx*dx + dy*dy));
3723 if (dy > 0.0) az = 2*M_PI - az;
3724 set_rot(globe->Wtrans, az, Zaxis);
3725
3726 l = sqrt((w->picture.px - x)*(w->picture.px - x) +
3727 (w->picture.py - y)*(w->picture.py - y) );
3728
3729 ay = (-2*M_PI*l/globe->circumference);
3730 set_rot(globe->Wtrans, -ay, Yaxis);
3731
3732 set_rot(globe->Wtrans, -az, Zaxis);
3733 add2historybuffer(w, x, y);
3734 }
3735 draw_rotated_gnomon(w);
3736 XmDrawGlobe (w);
3737
3738 XmPictureMoveCamera( w, w->picture.globe->Wtrans,
3739 &cb.from_x, &cb.from_y, &cb.from_z,
3740 &cb.up_x, &cb.up_y, &cb.up_z);
3741
3742 cb.event = event;
3743 cb.reason = XmPCR_DRAG;
3744 XtCallCallbacks ((Widget) w, XmNrotationCallback, &cb);
3745 }
3746
3747 if ( ((w->picture.mode == XmCURSOR_MODE) ||
3748 (w->picture.mode == XmROAM_MODE)) &&
3749 (w->picture.button_pressed == Button1) )
3750 {
3751 if (!w->image.frame_buffer)
3752 {
3753 if (w->picture.pixmap == XmUNSPECIFIED_PIXMAP) return;
3754 }
3755 /*
3756 * If we have no selected cursors, return
3757 */
3758 if(w->picture.mode == XmCURSOR_MODE)
3759 {
3760 for(i = 0; i < w->picture.n_cursors; i++)
3761 {
3762 if (w->picture.selected[i]) break;
3763 }
3764 if (i == w->picture.n_cursors) return;
3765 }
3766 else if(w->picture.mode == XmROAM_MODE)
3767 {
3768 if (!w->picture.roam_selected) return;
3769 }
3770
3771 warp = False;
3772 if (x <= 0)
3773 {
3774 x = w->core.width/2;
3775 w->picture.px += x;
3776 w->picture.ppx += x;
3777 w->picture.pppx += x;
3778 warp = True;
3779 }
3780 if (x >= w->core.width-1)
3781 {
3782 x = w->core.width/2;
3783 w->picture.px -= x;
3784 w->picture.ppx -= x;
3785 w->picture.pppx -= x;
3786 warp = True;
3787 }
3788 if (y <= 0)
3789 {
3790 y = w->core.width/2;
3791 w->picture.py += y;
3792 w->picture.ppy += y;
3793 w->picture.pppy += y;
3794 warp = True;
3795 }
3796 if (y >= w->core.width-1)
3797 {
3798 y = w->core.width/2;
3799 w->picture.py -= y;
3800 w->picture.ppy -= y;
3801 w->picture.pppy -= y;
3802 warp = True;
3803 }
3804 if(warp)
3805 {
3806 XWarpPointer(XtDisplay(w), None, XtWindow(w), 0,0, 0,0, x,y);
3807 }
3808
3809 if ( w->picture.K < 4 )
3810 {
3811 add2historybuffer(w, x, y);
3812 return;
3813 }
3814
3815 major_dx = x - w->picture.pppx;
3816 major_dy = y - w->picture.pppy;
3817 if ((major_dx == 0.0) && (major_dy == 0.0) ) return;
3818
3819 angle = acos( major_dx/sqrt(major_dx*major_dx + major_dy*major_dy));
3820 if( major_dy > 0 )
3821 {
3822 angle = 2*M_PI - angle;
3823 }
3824
3825 angle_tol = 0.2;
3826
3827 dz = 0.0;
3828 if ( (fabs(w->picture.angle_posz - angle) < angle_tol) ||
3829 (2*M_PI - fabs(w->picture.angle_posz - angle) < angle_tol) )
3830 {
3831 dz = 1.0;
3832 }
3833 if ( (fabs(w->picture.angle_negz - angle) < angle_tol) ||
3834 (2*M_PI - fabs(w->picture.angle_negz - angle) < angle_tol) )
3835 {
3836 dz = -1.0;
3837 }
3838
3839 dx = 0.0;
3840 if ( (fabs(w->picture.angle_posx - angle) < angle_tol) ||
3841 (2*M_PI - fabs(w->picture.angle_posx - angle) < angle_tol) )
3842 {
3843 dx = 1.0;
3844 }
3845 if ( (fabs(w->picture.angle_negx - angle) < angle_tol) ||
3846 (2*M_PI - fabs(w->picture.angle_negx - angle) < angle_tol) )
3847 {
3848 dx = -1.0;
3849 }
3850
3851 dy = 0.0;
3852 if ( (fabs(w->picture.angle_posy - angle) < angle_tol) ||
3853 (2*M_PI - fabs(w->picture.angle_posy - angle) < angle_tol) )
3854 {
3855 dy = 1.0;
3856 }
3857 if ( (fabs(w->picture.angle_negy - angle) < angle_tol) ||
3858 (2*M_PI - fabs(w->picture.angle_negy - angle) < angle_tol) )
3859 {
3860 dy = -1.0;
3861 }
3862
3863 /*
3864 * Constrain motion along a single axis
3865 */
3866 switch(w->picture.constrain_cursor)
3867 {
3868 case XmCONSTRAIN_NONE:
3869 break;
3870
3871 case XmCONSTRAIN_X:
3872 dy = dz = 0.0;
3873 break;
3874
3875 case XmCONSTRAIN_Y:
3876 dx = dz = 0.0;
3877 break;
3878
3879 case XmCONSTRAIN_Z:
3880 dx = dy = 0.0;
3881 break;
3882 }
3883 if (!w->picture.x_movement_allowed) dx = 0.0;
3884 if (!w->picture.y_movement_allowed) dy = 0.0;
3885 if (!w->picture.z_movement_allowed) dz = 0.0;
3886
3887 /*
3888 * Constrain motion within the bounding box and the widget
3889 */
3890 constrain(w, &w->picture.X, &w->picture.Y, &w->picture.Z, dx, dy, dz,
3891 w->picture.WItrans, w->picture.Wtrans,
3892 x - w->picture.px, y - w->picture.py);
3893
3894 /* Restore the image over the previous marks */
3895 if ( (!w->image.frame_buffer) &&
3896 (w->picture.pixmap != XmUNSPECIFIED_PIXMAP) )
3897 {
3898 for ( i = 0 ; i < w->picture.piMark ; i++ )
3899 {
3900 XCopyArea (XtDisplay(w), w->picture.pixmap, XtWindow(w),
3901 w->picture.gc,
3902 (int)(w->picture.pXmark[i]) - 1,
3903 (int)(w->picture.pYmark[i]) - 1, 3, 3,
3904 (int)(w->picture.pXmark[i]) - 1,
3905 (int)(w->picture.pYmark[i]) - 1);
3906 }
3907
3908 XCopyArea (XtDisplay(w), w->picture.pixmap, XtWindow(w),
3909 w->picture.gc,
3910 w->picture.pcx - w->picture.cursor_size/2,
3911 w->picture.pcy - w->picture.cursor_size/2,
3912 w->picture.cursor_size, w->picture.cursor_size,
3913 w->picture.pcx - w->picture.cursor_size/2,
3914 w->picture.pcy - w->picture.cursor_size/2);
3915 }
3916 else if (w->image.frame_buffer)
3917 {
3918 for ( i = 0 ; i < w->picture.piMark ; i++ )
3919 {
3920 XClearArea (XtDisplay(w), w->picture.overlay_wid,
3921 (int)(w->picture.pXmark[i]) - 1,
3922 (int)(w->picture.pYmark[i]) - 1, 3, 3,
3923 False);
3924 }
3925
3926 XClearArea (XtDisplay(w), w->picture.overlay_wid,
3927 w->picture.pcx - w->picture.cursor_size/2,
3928 w->picture.pcy - w->picture.cursor_size/2,
3929 w->picture.cursor_size, w->picture.cursor_size,
3930 False);
3931 }
3932
3933 id = move_selected_cursor ( w, (int)w->picture.X, (int)w->picture.Y,
3934 w->picture.Z);
3935
3936 CallCursorCallbacks(w, XmPCR_DRAG, id, w->picture.X, w->picture.Y,
3937 w->picture.Z);
3938 /* record prev cursor x,y so we can erase it next time it is moved */
3939 w->picture.pcx = (int)w->picture.X;
3940 w->picture.pcy = (int)w->picture.Y;
3941
3942 if ( w->picture.FirstTimeMotion != True )
3943 {
3944 draw_cursors( w );
3945 }
3946
3947 w->picture.FirstTimeMotion = False;
3948
3949 XmDrawBbox (w);
3950 project ( w, (double)w->picture.X, (double)w->picture.Y,
3951 (double)w->picture.Z, w->picture.Wtrans,
3952 w->picture.WItrans );
3953
3954 draw_marker ( w );
3955
3956 add2historybuffer(w, x, y);
3957 } /* if cursor mode */
3958 if (w->picture.mode == XmNAVIGATE_MODE)
3959 {
3960 w->picture.old_x = x;
3961 w->picture.old_y = y;
3962 }
3963 }
3964
3965 /*****************************************************************************/
3966 /* */
3967 /* Subroutine: draw_arrow_head */
3968 /* Effect: draw the arrow head for the Roam mode arrow */
3969 /* */
3970 /*****************************************************************************/
draw_arrow_head(XmPictureWidget w,int x,int y,int center_x,int center_y)3971 static void draw_arrow_head(XmPictureWidget w, int x, int y,
3972 int center_x, int center_y)
3973 {
3974 double angle;
3975 double hyp;
3976 int x1;
3977 int y1;
3978 double length;
3979 Display *dpy;
3980 Window dw;
3981 GC gc;
3982
3983 if ( (x == center_x) && (y == center_y) ) return;
3984 dpy = XtDisplay(w);
3985 if(!w->image.frame_buffer)
3986 {
3987 dw = XtWindow(w);
3988 gc = w->picture.gc;
3989 }
3990 else
3991 {
3992 dw = w->picture.overlay_wid;
3993 gc = w->picture.gcovl;
3994 }
3995
3996 if ( sqrt( (center_x - x)*(center_x - x) + (center_y - y)*(center_y - y) )
3997 < 7)
3998 {
3999 length = 4;
4000 }
4001 else
4002 {
4003 length = 7;
4004 }
4005 /*
4006 * Normalize things.
4007 */
4008 x = x - center_x;
4009 y = y - center_y;
4010
4011 hyp = sqrt(x*x + y*y);
4012 angle = acos((double)(x/hyp));
4013 if (y < 0) angle = 2*M_PI - angle;
4014
4015 angle = angle + M_PI/6;
4016 if (angle > 2*M_PI) angle = angle - 2*M_PI;
4017 x1 = cos(angle)*length;
4018 y1 = sin(angle)*length;
4019 XDrawLine(dpy, dw, gc,
4020 center_x, center_y, center_x + x1, center_y + y1);
4021
4022 angle = angle - M_PI/3;
4023 if (angle < 0) angle = angle + 2*M_PI;
4024 x1 = cos(angle)*length;
4025 y1 = sin(angle)*length;
4026 XDrawLine(dpy, dw, gc,
4027 center_x, center_y, center_x + x1, center_y + y1);
4028
4029 }
4030
4031 /*****************************************************************************/
4032 /* */
4033 /* Subroutine: draw_rotated_gnomon */
4034 /* Effect: draw the gnomon based on the current rotation of the globe */
4035 /* */
4036 /*****************************************************************************/
draw_rotated_gnomon(XmPictureWidget w)4037 static void draw_rotated_gnomon(XmPictureWidget w)
4038 {
4039 /*
4040 * Recalc the xformed screen coords based on the new rotation xform
4041 */
4042 setup_gnomon(w, True);
4043 draw_gnomon (w);
4044 }
4045
4046 /*****************************************************************************/
4047 /* */
4048 /* Subroutine: move_selected_cursor */
4049 /* Effect: Update the x,y position of any selected cursors to the current*/
4050 /* x,y. */
4051 /* */
4052 /*****************************************************************************/
4053
move_selected_cursor(XmPictureWidget w,int x,int y,double z)4054 int move_selected_cursor ( XmPictureWidget w, int x, int y, double z )
4055 {
4056 int i;
4057
4058 if ((w->picture.mode == XmCURSOR_MODE) ||
4059 (w->picture.mode == XmPICK_MODE))
4060 {
4061 for ( i = 0 ; i < w->picture.n_cursors ; i++ )
4062 {
4063 if ( w->picture.selected[i] == True )
4064 {
4065 w->picture.xbuff[i] = x;
4066 w->picture.ybuff[i] = y;
4067 w->picture.zbuff[i] = z;
4068
4069 save_cursors_in_canonical_form(w, i);
4070 return(i);
4071 }
4072 }
4073 }
4074 else if (w->picture.mode == XmROAM_MODE)
4075 {
4076 if (w->picture.roam_selected)
4077 {
4078 w->picture.roam_xbuff = x;
4079 w->picture.roam_ybuff = y;
4080 w->picture.roam_zbuff = z;
4081
4082 save_cursors_in_canonical_form(w, -1);
4083 return(0);
4084 }
4085 }
4086 return(-1);
4087 }
4088
4089
4090 /************************************************************************
4091 *
4092 * Select
4093 *
4094 ************************************************************************/
4095
Select(w,event)4096 static void Select (w, event)
4097 XmPictureWidget w;
4098 XEvent *event;
4099
4100 {
4101 int x, y;
4102 int id;
4103 int i;
4104 double l;
4105 int screen;
4106 Pixmap p1, p2;
4107 XColor fc, bc;
4108 double aspect;
4109 int trans_x;
4110 int trans_y;
4111 int width;
4112 int height;
4113 XmPictureCallbackStruct cb;
4114 unsigned long value_mask;
4115 XGCValues values;
4116 char tmp_bits[8];
4117
4118
4119 for (i = 0; i < 8; i++)
4120 tmp_bits[i] = 0;
4121
4122 w->picture.button_pressed = event->xbutton.button;
4123 if (w->picture.disable_temp)
4124 {
4125 w->picture.good_at_select = False;
4126 if (w->picture.mode == XmROTATION_MODE)
4127 {
4128 w->picture.ignore_new_camera++;
4129 }
4130 return;
4131 }
4132 w->picture.good_at_select = True;
4133 if ( w->picture.mode == XmZOOM_MODE )
4134 {
4135 if ( (event->xbutton.button != Button1) &&
4136 (event->xbutton.button != Button3) )
4137 {
4138 return;
4139 }
4140 /*
4141 * Create the GC if it doen not already exist.
4142 */
4143 if(w->picture.rubber_band.gc == NULL)
4144 {
4145 value_mask = GCForeground;
4146 values.foreground = w->picture.white;
4147 w->picture.rubber_band.gc =
4148 XtGetGC((Widget)w, value_mask, &values);
4149 }
4150 width = w->core.width;
4151 height = w->core.height;
4152 w->picture.rubber_band.center_x = width/2;
4153 w->picture.rubber_band.center_y = height/2;
4154 w->picture.rubber_band.aspect = (float)height/(float)width;
4155 aspect = w->picture.rubber_band.aspect;
4156
4157 /*
4158 * Calculate the rectangle coords
4159 */
4160 trans_x = event->xbutton.x - w->picture.rubber_band.center_x;
4161 trans_y = event->xbutton.y - w->picture.rubber_band.center_y;
4162
4163 if( ((trans_y >= trans_x*aspect) && (trans_y >= -trans_x*aspect)) ||
4164 ((trans_y <= -trans_x*aspect)&& (trans_y <= trans_x*aspect)) )
4165 {
4166 y = height/2 - abs(trans_y);
4167 x = y/aspect;
4168 }
4169 else
4170 {
4171 x = width/2 - abs(trans_x);
4172 y = x*aspect;
4173 }
4174
4175 height = height - 2*y;
4176 width = width - 2*x;
4177
4178 height = MAX(height, 3);
4179 width = MAX(width, 3);
4180 /*
4181 * Draw the 2 rectangles.
4182 */
4183 if (!w->image.frame_buffer)
4184 {
4185 XSetForeground(XtDisplay(w), w->picture.rubber_band.gc,
4186 w->picture.white );
4187 XDrawRectangle(XtDisplay(w), XtWindow(w),
4188 w->picture.rubber_band.gc, x, y, width, height);
4189 XSetForeground(XtDisplay(w), w->picture.rubber_band.gc,
4190 w->picture.black );
4191 XDrawRectangle(XtDisplay(w), XtWindow(w),
4192 w->picture.rubber_band.gc, x+1, y+1, width-2, height-2);
4193 }
4194 else
4195 {
4196 XSetForeground(XtDisplay(w), w->picture.gcovl,
4197 w->picture.white );
4198 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
4199 w->picture.gcovl, x, y, width, height);
4200 XSetForeground(XtDisplay(w), w->picture.gcovl,
4201 w->picture.black );
4202 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
4203 w->picture.gcovl, x+1, y+1, width-2, height-2);
4204 }
4205
4206 w->picture.rubber_band.old_x = x;
4207 w->picture.rubber_band.old_y = y;
4208 w->picture.rubber_band.old_width = width;
4209 w->picture.rubber_band.old_height = height;
4210 }
4211 if ( w->picture.mode == XmPANZOOM_MODE )
4212 {
4213 if ( (event->xbutton.button != Button1) &&
4214 (event->xbutton.button != Button3) )
4215 {
4216 return;
4217 }
4218 /*
4219 * Create the GC if it doen not already exist.
4220 */
4221 if(w->picture.rubber_band.gc == NULL)
4222 {
4223 value_mask = GCForeground;
4224 values.foreground = w->picture.white;
4225 w->picture.rubber_band.gc =
4226 XtGetGC((Widget)w, value_mask, &values);
4227 }
4228 width = w->core.width;
4229 height = w->core.height;
4230 w->picture.rubber_band.center_x = event->xbutton.x;
4231 w->picture.rubber_band.center_y = event->xbutton.y;
4232 x = event->xbutton.x;
4233 y = event->xbutton.y;
4234 w->picture.rubber_band.aspect = (float)height/(float)width;
4235 aspect = w->picture.rubber_band.aspect;
4236
4237 height = 3;
4238 width = 3;
4239
4240 /*
4241 * Draw the 2 rectangles.
4242 */
4243 if (!w->image.frame_buffer)
4244 {
4245 XSetForeground(XtDisplay(w), w->picture.rubber_band.gc,
4246 w->picture.white );
4247 XDrawRectangle(XtDisplay(w), XtWindow(w),
4248 w->picture.rubber_band.gc, x, y, width, height);
4249 XSetForeground(XtDisplay(w), w->picture.rubber_band.gc,
4250 w->picture.black );
4251 XDrawRectangle(XtDisplay(w), XtWindow(w),
4252 w->picture.rubber_band.gc, x+1, y+1, width-2, height-2);
4253 }
4254 else
4255 {
4256 XSetForeground(XtDisplay(w), w->picture.gcovl,
4257 w->picture.white );
4258 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
4259 w->picture.gcovl, x, y, width, height);
4260 XSetForeground(XtDisplay(w), w->picture.gcovl,
4261 w->picture.black );
4262 XDrawRectangle(XtDisplay(w), w->picture.overlay_wid,
4263 w->picture.gcovl, x+1, y+1, width-2, height-2);
4264 }
4265
4266 w->picture.rubber_band.old_x = x;
4267 w->picture.rubber_band.old_y = y;
4268 w->picture.rubber_band.old_width = width;
4269 w->picture.rubber_band.old_height = height;
4270 }
4271 if ( ((w->picture.CursorBlank == False) &&
4272 ((w->picture.mode == XmCURSOR_MODE) ||
4273 (w->picture.mode == XmROAM_MODE)) &&
4274 (w->picture.button_pressed == Button1)) )
4275 {
4276 if (w->picture.cursor == None)
4277 {
4278 screen = XScreenNumberOfScreen(XtScreen(w));
4279 p1 = XCreatePixmapFromBitmapData ( XtDisplay(w),
4280 RootWindow(XtDisplay(w),screen),
4281 tmp_bits, 4, 4, 0, 0, 1);
4282
4283 p2 = XCreatePixmapFromBitmapData ( XtDisplay(w),
4284 RootWindow(XtDisplay(w),screen),
4285 tmp_bits, 4, 4, 0, 0, 1);
4286
4287 w->picture.cursor =
4288 XCreatePixmapCursor ( XtDisplay(w), p1, p2,
4289 &fc, &bc, 1, 1 );
4290 XFreePixmap ( XtDisplay(w), p1 );
4291 XFreePixmap ( XtDisplay(w), p2 );
4292 }
4293
4294 XDefineCursor( XtDisplay(w), XtWindow(w), w->picture.cursor);
4295 w->picture.CursorBlank = True;
4296 }
4297 /* Double click processing */
4298
4299 /*
4300 * If the tid is not NULL, that means we have a pending "move"
4301 * callback that needs to be removed (so we only report a delete).
4302 */
4303 if (w->picture.tid != (XtIntervalId)NULL)
4304 {
4305 XtRemoveTimeOut(w->picture.tid);
4306 w->picture.tid = (XtIntervalId)NULL;
4307 }
4308 if ( (event->xbutton.time - w->picture.last_time) < 350)
4309 {
4310 if ( ((w->picture.mode == XmCURSOR_MODE) ||
4311 (w->picture.mode == XmROAM_MODE)) &&
4312 (w->picture.button_pressed == Button1) )
4313 {
4314 w->picture.double_click = True;
4315 CreateDelete(w, event);
4316 }
4317 if ( (w->picture.mode == XmROTATION_MODE) ||
4318 (w->picture.mode == XmNAVIGATE_MODE) )
4319
4320 {
4321 w->picture.ignore_new_camera++;
4322 keyboard_grab(w, True);
4323 }
4324 }
4325 else
4326 /* Single click processing */
4327 {
4328 w->picture.last_time = event->xbutton.time;
4329
4330 if (w->picture.mode == XmPICK_MODE)
4331 {
4332 if (event->xbutton.button != Button1)
4333 return;
4334 CreateDelete(w, event);
4335 }
4336 if ( (w->picture.mode == XmROTATION_MODE) ||
4337 (((w->picture.mode == XmCURSOR_MODE) ||
4338 (w->picture.mode == XmROAM_MODE)) &&
4339 (w->picture.button_pressed != Button1)))
4340 {
4341 w->picture.K = 0;
4342
4343 x = event->xbutton.x ;
4344 y = event->xbutton.y ;
4345
4346 /*
4347 * Normalize the x,y coordinates
4348 */
4349 x = x - w->core.width/2;
4350 y = y - w->core.height/2;
4351
4352 /*
4353 * record the angles
4354 */
4355 l = sqrt(x*x + y*y);
4356 if (event->xbutton.button == Button3)
4357 {
4358 w->picture.globe->on_sphere = False;
4359 w->picture.globe->paz = acos((double)x/l);
4360 if (y > 0)
4361 {
4362 w->picture.globe->paz = 2*M_PI - w->picture.globe->paz;
4363 }
4364 }
4365 else if ( (event->xbutton.button == Button1) ||
4366 (event->xbutton.button == Button2) )
4367 {
4368 w->picture.globe->on_sphere = True;
4369 w->picture.globe->paz = -1;
4370 }
4371 else
4372 {
4373 return;
4374 }
4375 w->picture.ignore_new_camera++;
4376
4377 /*
4378 * Adjust the globe circumference to be based on the window size.
4379 */
4380 l = MAX(w->core.width, w->core.height)/4;
4381 w->picture.globe->circumference = M_PI*(l + l);
4382
4383 /*
4384 * So we only see the globe and gnomon while rotating(i.e. not
4385 * the boubding box and cursors).
4386 */
4387 erase_image(w);
4388 draw_gnomon(w);
4389 XmDrawGlobe (w);
4390
4391 /*
4392 * Added to support button up/down approximation
4393 */
4394 cb.event = event;
4395 cb.reason = XmPCR_SELECT;
4396 XtCallCallbacks ((Widget) w, XmNrotationCallback, &cb);
4397 }
4398
4399 if ( ((w->picture.mode == XmCURSOR_MODE) ||
4400 (w->picture.mode == XmROAM_MODE)) &&
4401 (w->picture.button_pressed == Button1) )
4402 {
4403 w->picture.ignore_new_camera++;
4404 w->picture.FirstTimeMotion = True;
4405 w->picture.FirstTime = True;
4406 /*
4407 * Indicate that there are no elements in the history buffer
4408 */
4409 w->picture.K = 0;
4410
4411 x = event->xbutton.x ;
4412 y = event->xbutton.y ;
4413
4414 id = find_closest ( w, x, y );
4415
4416 /*
4417 * If we have not selected a cursor, do nothing.
4418 */
4419 if ( id == -1 )
4420 {
4421 deselect_cursor ( w );
4422 return;
4423 }
4424 else
4425 {
4426 if (w->picture.mode == XmCURSOR_MODE)
4427 {
4428 w->picture.Z = w->picture.zbuff[id];
4429 w->picture.pcx = x = w->picture.X = w->picture.xbuff[id];
4430 w->picture.pcy = y = w->picture.Y = w->picture.ybuff[id];
4431 }
4432 else if (w->picture.mode == XmROAM_MODE)
4433 {
4434 w->picture.Z = w->picture.roam_zbuff;
4435 w->picture.pcx = x = w->picture.X = w->picture.roam_xbuff;
4436 w->picture.pcy = y = w->picture.Y = w->picture.roam_ybuff;
4437 }
4438 deselect_cursor ( w );
4439 select_cursor ( w, id );
4440 }
4441 draw_cursors( w );
4442 project ( w, (double)x, (double)y,
4443 (double)w->picture.Z, w->picture.Wtrans,
4444 w->picture.WItrans );
4445 draw_marker (w);
4446
4447
4448 CallCursorCallbacks(w, XmPCR_SELECT, id, w->picture.X, w->picture.Y,
4449 w->picture.Z);
4450 } /* if cursor mode */
4451 if (w->picture.mode == XmNAVIGATE_MODE)
4452 {
4453 if (event->xbutton.button == Button1)
4454 {
4455 w->picture.navigate_direction = XmFORWARD;
4456 }
4457 else if (event->xbutton.button == Button3)
4458 {
4459 w->picture.navigate_direction = XmBACKWARD;
4460 }
4461 keyboard_grab(w, True);
4462
4463 w->picture.old_x = event->xbutton.x;
4464 w->picture.old_y = event->xbutton.y;
4465 w->picture.first_step = True;
4466 w->picture.ignore_new_camera = 0;
4467
4468 /*
4469 * Save the current camera in case the user wants to undo this
4470 * interaction.
4471 */
4472 push_undo_camera(w);
4473
4474 CallNavigateCallbacks(w, event->xbutton.x, event->xbutton.y,
4475 XmPCR_SELECT);
4476 }
4477 }
4478 }
4479
4480 /*****************************************************************************/
4481 /* */
4482 /* Subroutine: draw_cursors */
4483 /* Effect: Draws Non-selected cursors??? */
4484 /* */
4485 /*****************************************************************************/
4486 static int
draw_cursors(XmPictureWidget w)4487 draw_cursors( XmPictureWidget w )
4488 {
4489 int i;
4490 int depth=0;
4491 Window dw;
4492 GC gc;
4493
4494 /*dpy = XtDisplay(w);*/
4495 if(!w->image.frame_buffer)
4496 {
4497 dw = XtWindow(w);
4498 gc = w->picture.gc;
4499 }
4500 else
4501 {
4502 dw = w->picture.overlay_wid;
4503 gc = w->picture.gcovl;
4504 }
4505
4506 /* For each potential cursor... */
4507 if ((w->picture.mode == XmCURSOR_MODE) ||
4508 (w->picture.mode == XmPICK_MODE))
4509 {
4510 for (i = 0; i < w->picture.n_cursors; i++)
4511 {
4512 switch ( w->picture.cursor_shape )
4513 {
4514 case XmSQUARE :
4515 if(w->picture.mode == XmCURSOR_MODE)
4516 depth = (Z_LEVELS-1)*
4517 (w->picture.zbuff[i] - w->picture.Zmin)/
4518 (w->picture.Zmax - w->picture.Zmin);
4519 else if(w->picture.mode == XmPICK_MODE)
4520 depth = (Z_LEVELS-1);
4521 if( w->picture.selected[i] == True )
4522 {
4523 XCopyArea (XtDisplay(w),
4524 w->picture.ActiveSquareCursor[depth],
4525 dw,
4526 gc,
4527 0,
4528 0,
4529 w->picture.cursor_size,
4530 w->picture.cursor_size,
4531 w->picture.xbuff[i] -
4532 (w->picture.cursor_size / 2),
4533 w->picture.ybuff[i] -
4534 (w->picture.cursor_size / 2) );
4535 }
4536 else
4537 {
4538 XCopyArea (XtDisplay(w),
4539 w->picture.PassiveSquareCursor[depth],
4540 dw,
4541 gc,
4542 0,
4543 0,
4544 w->picture.cursor_size,
4545 w->picture.cursor_size,
4546 w->picture.xbuff[i] -
4547 (w->picture.cursor_size / 2),
4548 w->picture.ybuff[i] -
4549 (w->picture.cursor_size / 2) );
4550 }
4551 break;
4552 }
4553 }
4554 }
4555 else if (w->picture.mode == XmROAM_MODE)
4556 {
4557 switch ( w->picture.cursor_shape )
4558 {
4559 case XmSQUARE :
4560 depth = (Z_LEVELS-1)*
4561 (w->picture.roam_zbuff - w->picture.Zmin)/
4562 (w->picture.Zmax - w->picture.Zmin);
4563 if(w->picture.roam_selected)
4564 {
4565 XCopyArea (XtDisplay(w),
4566 w->picture.ActiveSquareCursor[depth],
4567 dw,
4568 gc,
4569 0,
4570 0,
4571 w->picture.cursor_size,
4572 w->picture.cursor_size,
4573 w->picture.roam_xbuff -
4574 (w->picture.cursor_size / 2),
4575 w->picture.roam_ybuff -
4576 (w->picture.cursor_size / 2) );
4577 }
4578 else
4579 {
4580 XCopyArea (XtDisplay(w),
4581 w->picture.PassiveSquareCursor[depth],
4582 dw,
4583 gc,
4584 0,
4585 0,
4586 w->picture.cursor_size,
4587 w->picture.cursor_size,
4588 w->picture.roam_xbuff -
4589 (w->picture.cursor_size / 2),
4590 w->picture.roam_ybuff -
4591 (w->picture.cursor_size / 2) );
4592 }
4593 break;
4594 }
4595 }
4596 return 0;
4597 }
4598
4599 /*****************************************************************************/
4600 /* */
4601 /* Subroutine: find_closest */
4602 /* Effect: Returns the 1st selected cursor w/in 4 pixels of x,y */
4603 /* */
4604 /*****************************************************************************/
4605 static int
find_closest(XmPictureWidget w,int x,int y)4606 find_closest ( XmPictureWidget w, int x, int y )
4607 {
4608 int i;
4609
4610 if ((w->picture.mode == XmCURSOR_MODE) ||
4611 (w->picture.mode == XmPICK_MODE) )
4612 {
4613 for ( i = 0 ; i < w->picture.n_cursors ; i++ )
4614 {
4615 if ( (abs (w->picture.xbuff[i] - x) < w->picture.cursor_size/2+1) &&
4616 (abs (w->picture.ybuff[i] - y) < w->picture.cursor_size/2+1) )
4617 return i;
4618 }
4619 }
4620 else if (w->picture.mode == XmROAM_MODE)
4621 {
4622 if ( (abs (w->picture.roam_xbuff - x) < w->picture.cursor_size/2+1) &&
4623 (abs (w->picture.roam_ybuff - y) < w->picture.cursor_size/2+1) )
4624 return 0;
4625 }
4626
4627 return -1;
4628 }
4629
4630
4631
4632 /************************************************************************
4633 *
4634 * create_cursor_pixmaps
4635 *
4636 ************************************************************************/
create_cursor_pixmaps(XmPictureWidget new)4637 static void create_cursor_pixmaps(XmPictureWidget new)
4638 {
4639 int i;
4640 int screen;
4641 GC gc;
4642 Window dw;
4643 XColor colorcell_def;
4644 XColor selected_out_cell;
4645 XColor unselected_out_cell;
4646 Pixel unselected_out;
4647 Pixel selected_out;
4648 float level;
4649 XWindowAttributes win_att;
4650 Colormap cm;
4651 int depth;
4652
4653 if (new->picture.ActiveSquareCursor[0] != None) return;
4654
4655 if(!new->image.frame_buffer)
4656 {
4657 dw = XtWindow(new);
4658 gc = new->picture.gc;
4659 depth = new->core.depth;
4660 }
4661 else
4662 {
4663 dw = new->picture.overlay_wid;
4664 gc = new->picture.gcovl;
4665 depth = 8;
4666 }
4667
4668 colorcell_def.flags = DoRed | DoGreen | DoBlue;
4669
4670 /*
4671 * Set the RGB's of the selected outside cursor color
4672 */
4673 selected_out_cell = new->picture.selected_out_cursor_color;
4674 unselected_out_cell = new->picture.unselected_out_cursor_color;
4675
4676 /*
4677 * Set the colormap
4678 */
4679 screen = XScreenNumberOfScreen(XtScreen(new));
4680
4681 XGetWindowAttributes(XtDisplay(new), dw, &win_att);
4682 if((win_att.colormap != None) && (!new->image.frame_buffer))
4683 cm = win_att.colormap;
4684 else
4685 cm = DefaultColormap(XtDisplay(new), screen);
4686
4687 for (i = 0; i < Z_LEVELS; i++)
4688 {
4689 /*
4690 * Note: we will depth cue only the outside color of the cursor
4691 */
4692
4693 /*
4694 * First calc the selected outside color
4695 */
4696 level = (float)(Z_LEVELS/2) + (float)(i)/2;
4697 colorcell_def.red = level * (float)(selected_out_cell.red/Z_LEVELS);
4698 colorcell_def.green = level * (float)(selected_out_cell.green/Z_LEVELS);
4699 colorcell_def.blue = level * (float)(selected_out_cell.blue/Z_LEVELS);
4700 gamma_correct(&colorcell_def);
4701 if (!XAllocColor(XtDisplay(new), cm, &colorcell_def))
4702 {
4703 find_color((Widget)new, &colorcell_def);
4704 }
4705 selected_out = colorcell_def.pixel;
4706
4707 /*
4708 * Then calc the unselected outside color
4709 */
4710 colorcell_def.red = level*(float)(unselected_out_cell.red/Z_LEVELS);
4711 colorcell_def.green = level*(float)(unselected_out_cell.green/Z_LEVELS);
4712 colorcell_def.blue = level*(float)(unselected_out_cell.blue/Z_LEVELS);
4713 gamma_correct(&colorcell_def);
4714 if(!XAllocColor(XtDisplay(new), cm, &colorcell_def))
4715 {
4716 find_color((Widget)new, &colorcell_def);
4717 }
4718 unselected_out = colorcell_def.pixel;
4719
4720 /*
4721 * Create the Pixmaps
4722 */
4723 new->picture.ActiveSquareCursor[i] =
4724 XCreatePixmap ( XtDisplay(new),
4725 dw,
4726 new->picture.cursor_size,
4727 new->picture.cursor_size, depth );
4728
4729 new->picture.PassiveSquareCursor[i] =
4730 XCreatePixmap ( XtDisplay(new),
4731 dw,
4732 new->picture.cursor_size,
4733 new->picture.cursor_size, depth );
4734
4735 /*
4736 * Fill in active and passive cursor pixmaps w/ their 2 colors
4737 */
4738 XSetForeground(XtDisplay(new), gc, selected_out);
4739
4740 XFillRectangle(XtDisplay(new), new->picture.ActiveSquareCursor[i], gc,
4741 0, 0, new->picture.cursor_size, new->picture.cursor_size);
4742
4743 XSetForeground(XtDisplay(new), gc, new->picture.black);
4744
4745 XFillRectangle(XtDisplay(new), new->picture.ActiveSquareCursor[i], gc,
4746 1, 1,
4747 new->picture.cursor_size - 2, new->picture.cursor_size - 2);
4748
4749 XSetForeground(XtDisplay(new), gc, unselected_out);
4750
4751 XFillRectangle(XtDisplay(new), new->picture.PassiveSquareCursor[i], gc,
4752 0, 0, new->picture.cursor_size, new->picture.cursor_size);
4753
4754 XSetForeground(XtDisplay(new), gc, new->picture.black);
4755
4756 XFillRectangle(XtDisplay(new), new->picture.PassiveSquareCursor[i], gc,
4757 1, 1,
4758 new->picture.cursor_size - 2, new->picture.cursor_size - 2);
4759
4760 }
4761
4762
4763 new->picture.marker =
4764 XCreatePixmap ( XtDisplay(new),
4765 dw,
4766 3, 3, depth );
4767
4768 XSetForeground(XtDisplay(new), gc, new->picture.white);
4769 XFillRectangle(XtDisplay(new), new->picture.marker, gc, 0, 0, 3, 3);
4770
4771 }
4772 /************************************************************************
4773 *
4774 * PropertyNotify
4775 *
4776 ************************************************************************/
4777
PropertyNotifyAR(w,event)4778 static void PropertyNotifyAR (w, event)
4779 XmPictureWidget w;
4780 XEvent *event;
4781
4782 {
4783 XmPictureCallbackStruct cb;
4784
4785 cb.event = event;
4786 XtCallCallbacks ((Widget) w, XmNpropertyNotifyCallback, &cb);
4787
4788 }
4789 /************************************************************************
4790 *
4791 * ServerMessage
4792 *
4793 ************************************************************************/
4794
ServerMessage(w,event)4795 static void ServerMessage (w, event)
4796 XmPictureWidget w;
4797 XEvent *event;
4798
4799 {
4800 XmPictureCallbackStruct cb;
4801
4802 cb.event = event;
4803 XtCallCallbacks ((Widget) w, XmNclientMessageCallback, &cb);
4804
4805 }
4806 /************************************************************************
4807 *
4808 * Deselect
4809 *
4810 ************************************************************************/
4811
Deselect(w,event)4812 static void Deselect (w, event)
4813 XmPictureWidget w;
4814 XEvent *event;
4815 {
4816
4817 XmPictureCallbackStruct cb;
4818 int i;
4819 double to_x, to_y, to_z;
4820 double dir_x, dir_y, dir_z;
4821 int width;
4822 double dist;
4823 double new_width;
4824
4825
4826 if (w->picture.button_pressed == 0) return;
4827 w->picture.button_pressed = 0;
4828 if ( w->picture.mode == XmPICK_MODE )
4829 {
4830 if (event->xbutton.button == Button1)
4831 w->picture.ignore_new_camera--;
4832 return;
4833 }
4834 if ( w->picture.mode == XmZOOM_MODE )
4835 {
4836 if (w->picture.rubber_band.gc == NULL) return;
4837 if ( (w->picture.disable_temp) || (!w->picture.good_at_select) )
4838 {
4839 return;
4840 }
4841
4842 if ( (event->xbutton.button != Button1) &&
4843 (event->xbutton.button != Button3) )
4844 {
4845 return;
4846 }
4847
4848 /*
4849 * Save the current camera in case the user wants to undo this
4850 * interaction.
4851 */
4852 push_undo_camera(w);
4853 restore_rectangle(w);
4854 cb.event = event;
4855 width = w->core.width;
4856
4857 /*
4858 * Orthographic projection
4859 */
4860 cb.zoom_factor =
4861 ((double)width-2*(double)w->picture.rubber_band.old_x)/(double)width;
4862 if (event->xbutton.button == Button3)
4863 {
4864 cb.zoom_factor = 1/cb.zoom_factor;
4865 }
4866
4867 /*
4868 * If we are in a perspective projection, calc a new view angle
4869 */
4870 if (w->picture.projection == 1)
4871 {
4872 dist = (w->picture.autocamera_width/2)/
4873 (tan((w->picture.view_angle/2)*2*M_PI/360.0));
4874 new_width = (w->picture.autocamera_width/2)*cb.zoom_factor;
4875 cb.view_angle = (360/M_PI)*atan(new_width/dist);
4876 cb.view_angle = (cb.view_angle < 0.001) ? 0.001 : cb.view_angle;
4877 cb.view_angle = (cb.view_angle > 179.999) ? 179.999 : cb.view_angle;
4878 }
4879 cb.projection = w->picture.projection;
4880 cb.x = w->picture.to_x;
4881 cb.y = w->picture.to_y;
4882 cb.z = w->picture.to_z;
4883 cb.from_x = w->picture.from_x;
4884 cb.from_y = w->picture.from_y;
4885 cb.from_z = w->picture.from_z;
4886
4887 XtCallCallbacks ((Widget) w, XmNzoomCallback, &cb);
4888 w->picture.disable_temp = True;
4889 if (w->picture.double_click)
4890 {
4891 w->picture.double_click = False;
4892 }
4893 }
4894 if ( w->picture.mode == XmPANZOOM_MODE )
4895 {
4896 if (w->picture.rubber_band.gc == NULL) return;
4897 if ( (w->picture.disable_temp) || (!w->picture.good_at_select) )
4898 {
4899 return;
4900 }
4901
4902 if ( (event->xbutton.button != Button1) &&
4903 (event->xbutton.button != Button3) )
4904 {
4905 return;
4906 }
4907
4908 /*
4909 * Save the current camera in case the user wants to undo this
4910 * interaction.
4911 */
4912 push_undo_camera(w);
4913 restore_rectangle(w);
4914 cb.event = event;
4915 width = w->core.width;
4916
4917 /*
4918 * Calculate the new camera "to" point
4919 */
4920 dir_x = w->picture.from_x - w->picture.to_x;
4921 dir_y = w->picture.from_y - w->picture.to_y;
4922 dir_z = w->picture.from_z - w->picture.to_z;
4923 xform_coords(w->picture.PureWtrans,
4924 w->picture.to_x, w->picture.to_y, w->picture.to_z,
4925 &to_x, &to_y, &to_z);
4926 perspective_divide(w, to_x, to_y, to_z, &to_x, &to_y);
4927 to_x = w->picture.rubber_band.center_x;
4928 to_y = w->picture.rubber_band.center_y;
4929 perspective_divide_inverse(w, to_x, to_y, to_z, &to_x, &to_y);
4930 xform_coords(w->picture.PureWItrans, to_x, to_y, to_z,
4931 &cb.x, &cb.y, &cb.z);
4932
4933 if (w->picture.projection == 1)
4934 {
4935 cb.from_x = w->picture.from_x;
4936 cb.from_y = w->picture.from_y;
4937 cb.from_z = w->picture.from_z;
4938 }
4939 else
4940 {
4941 cb.from_x = cb.x + dir_x;
4942 cb.from_y = cb.y + dir_y;
4943 cb.from_z = cb.z + dir_z;
4944 }
4945 /*
4946 * Don't allow infinite zoom
4947 */
4948 if(w->picture.rubber_band.center_x == w->picture.rubber_band.old_x)
4949 w->picture.rubber_band.old_x--;
4950
4951 /*
4952 * Orthographic projection
4953 */
4954 cb.zoom_factor =
4955 (2*(double)(w->picture.rubber_band.center_x -
4956 w->picture.rubber_band.old_x))/
4957 (double)w->core.width;
4958 if (event->xbutton.button == Button3)
4959 {
4960 cb.zoom_factor = 1/cb.zoom_factor;
4961 }
4962
4963 /*
4964 * If we are in a perspective projection, calc a new view angle
4965 */
4966 if (w->picture.projection == 1)
4967 {
4968 dist = (w->picture.autocamera_width/2)/
4969 (tan((w->picture.view_angle/2)*2*M_PI/360.0));
4970 new_width = (w->picture.autocamera_width/2)*cb.zoom_factor;
4971 cb.view_angle = (360/M_PI)*atan(new_width/dist);
4972 cb.view_angle = (cb.view_angle < 0.001) ? 0.001 : cb.view_angle;
4973 cb.view_angle = (cb.view_angle > 179.999) ? 179.999 : cb.view_angle;
4974 }
4975 cb.projection = w->picture.projection;
4976
4977 XtCallCallbacks ((Widget) w, XmNzoomCallback, &cb);
4978 w->picture.disable_temp = True;
4979 if (w->picture.double_click)
4980 {
4981 w->picture.double_click = False;
4982 }
4983 }
4984
4985 if ( (w->picture.mode == XmROTATION_MODE) ||
4986 (((w->picture.mode == XmCURSOR_MODE) ||
4987 (w->picture.mode == XmROAM_MODE)) &&
4988 (event->xbutton.button != Button1)) )
4989 {
4990 #ifdef Comment
4991 if ( (event->xbutton.button != Button1) &&
4992 (event->xbutton.button != Button3) )
4993 {
4994 return;
4995 }
4996 #endif
4997 w->picture.ignore_new_camera--;
4998 if ( (w->picture.disable_temp) || (!w->picture.good_at_select) )
4999 {
5000 return;
5001 }
5002
5003 /*
5004 * Save the current camera in case the user wants to undo this
5005 * interaction.
5006 */
5007 push_undo_camera(w);
5008
5009 XmPictureMoveCamera( w, w->picture.globe->Wtrans,
5010 &cb.from_x, &cb.from_y, &cb.from_z,
5011 &cb.up_x, &cb.up_y, &cb.up_z);
5012
5013 cb.event = event;
5014 cb.reason = XmPCR_MOVE;
5015 XtCallCallbacks ((Widget) w, XmNrotationCallback, &cb);
5016
5017 w->picture.disable_temp = True;
5018 w->picture.K = 0;
5019 if (w->picture.double_click)
5020 {
5021 w->picture.double_click = False;
5022 }
5023 }
5024
5025 if ( ((w->picture.mode == XmCURSOR_MODE) ||
5026 (w->picture.mode == XmROAM_MODE)) &&
5027 (event->xbutton.button == Button1))
5028 {
5029 w->picture.ignore_new_camera--;
5030 if (!w->image.frame_buffer)
5031 {
5032 if (w->picture.pixmap == XmUNSPECIFIED_PIXMAP) return;
5033 }
5034
5035 if (w->picture.mode == XmCURSOR_MODE)
5036 {
5037 for ( i = 0 ; i < w->picture.n_cursors ; i++ )
5038 {
5039 if ( w->picture.selected[i] == True )
5040 {
5041 if ( w->picture.CursorBlank )
5042 {
5043 XWarpPointer ( XtDisplay(w), None, XtWindow(w),
5044 0, 0, 0, 0,
5045 w->picture.xbuff[i] , w->picture.ybuff[i] );
5046 XUndefineCursor(XtDisplay(w), XtWindow(w));
5047 w->picture.CursorBlank = False;
5048 }
5049 /*
5050 * Save the cursor id so the TimeOut routine can use it.
5051 */
5052 w->picture.cursor_num = i;
5053 w->picture.tid = XtAppAddTimeOut(
5054 XtWidgetToApplicationContext((Widget)w),
5055 370, (XtTimerCallbackProc)ButtonTimeOut, w);
5056 break;
5057 }
5058 }
5059 /*
5060 * If none of the cursors were selected...
5061 */
5062 if (i == w->picture.n_cursors)
5063 {
5064 w->picture.cursor_num = -1;
5065 w->picture.tid = XtAppAddTimeOut(
5066 XtWidgetToApplicationContext((Widget)w),
5067 370, (XtTimerCallbackProc)ButtonTimeOut, w);
5068 }
5069 }
5070 else if (w->picture.mode == XmROAM_MODE)
5071 {
5072 if ( w->picture.CursorBlank )
5073 {
5074 if (w->picture.roam_selected)
5075 {
5076 XWarpPointer ( XtDisplay(w), None, XtWindow(w),
5077 0, 0, 0, 0,
5078 w->picture.roam_xbuff,w->picture.roam_ybuff);
5079 }
5080 XUndefineCursor(XtDisplay(w), XtWindow(w));
5081 w->picture.CursorBlank = False;
5082 }
5083 /*
5084 * Save the cursor id so the TimeOut routine can use it.
5085 */
5086 w->picture.cursor_num = 0;
5087 if (!w->picture.double_click)
5088 {
5089 w->picture.tid = XtAppAddTimeOut(
5090 XtWidgetToApplicationContext((Widget)w),
5091 370, (XtTimerCallbackProc)ButtonTimeOut, w);
5092 }
5093 }
5094
5095 /*x = event->xbutton.x;g*/
5096 /*y = event->xbutton.y;g*/
5097
5098 w->picture.FirstTimeMotion = True;
5099 w->picture.FirstTime = True;
5100 w->picture.K = 0;
5101
5102 for ( i = 0 ; i < w->picture.piMark ; i++ )
5103 {
5104 if ( (!w->image.frame_buffer) &&
5105 (w->picture.pixmap != XmUNSPECIFIED_PIXMAP) )
5106 {
5107 XCopyArea (XtDisplay(w),
5108 w->picture.pixmap,
5109 XtWindow(w),
5110 w->picture.gc,
5111 (int)(w->picture.pXmark[i]) - 1,
5112 (int)(w->picture.pYmark[i]) - 1, 3, 3,
5113 (int)(w->picture.pXmark[i]) - 1,
5114 (int)(w->picture.pYmark[i]) - 1);
5115 }
5116 else
5117 {
5118 XClearArea (XtDisplay(w),
5119 w->picture.overlay_wid,
5120 (int)(w->picture.pXmark[i]) - 1,
5121 (int)(w->picture.pYmark[i]) - 1, 3, 3,
5122 False);
5123 }
5124 }
5125 draw_gnomon(w);
5126 XmDrawBbox (w);
5127 draw_cursors( w );
5128 XtPopdown(w->picture.popup);
5129 w->picture.popped_up = False;
5130 if (w->picture.double_click)
5131 {
5132 w->picture.double_click = False;
5133 }
5134 w->picture.piMark = 0;
5135 } /* if cursor mode */
5136 if (w->picture.mode == XmNAVIGATE_MODE)
5137 {
5138 keyboard_grab(w, False);
5139 /*
5140 * Set first_set = True so incoming cameras will set the nav_camera
5141 */
5142 w->picture.first_step = True;
5143 w->picture.ignore_new_camera = 0;
5144 CallNavigateCallbacks(w, event->xbutton.x, event->xbutton.y,
5145 XmPCR_MOVE);
5146 }
5147
5148 }
5149
5150 /*****************************************************************************/
5151 /* */
5152 /* Subroutine: ButtonTimeOut */
5153 /* Effect: This routine is set up the first time a button release occurs.*/
5154 /* If the user double clicks, the time out is removed, otherwise,*/
5155 /* this routine is executed and the application is called back */
5156 /* indicating that a move has occured. */
5157 /* */
5158 /*****************************************************************************/
ButtonTimeOut(XmPictureWidget w,XtIntervalId * id)5159 XtTimerCallbackProc ButtonTimeOut( XmPictureWidget w, XtIntervalId *id)
5160 {
5161 int i;
5162
5163 if ( (w->picture.disable_temp) || (!w->picture.good_at_select) )
5164 {
5165 w->picture.tid = (XtIntervalId)NULL;
5166 return NULL;
5167 }
5168
5169 if ( ((w->picture.mode == XmROAM_MODE) &&
5170 (w->picture.roam_selected)) ||
5171 ((w->picture.mode == XmCURSOR_MODE) &&
5172 (w->picture.cursor_num != -1)) )
5173 {
5174 CallCursorCallbacks(w, XmPCR_MOVE, w->picture.cursor_num,
5175 w->picture.X, w->picture.Y, w->picture.Z);
5176 }
5177
5178 w->picture.tid = (XtIntervalId)NULL;
5179 if ( w->picture.CursorBlank )
5180 {
5181 XUndefineCursor(XtDisplay(w), XtWindow(w));
5182 if ( (w->picture.mode == XmROAM_MODE) &&
5183 (w->picture.roam_selected) )
5184 {
5185 XWarpPointer ( XtDisplay(w), None, XtWindow(w),
5186 0, 0, 0, 0,
5187 w->picture.roam_xbuff, w->picture.roam_ybuff);
5188 }
5189 else if (w->picture.mode == XmCURSOR_MODE)
5190 {
5191 for (i = 0; i < w->picture.n_cursors; i++)
5192 {
5193 if (w->picture.selected[i])
5194 {
5195 XWarpPointer ( XtDisplay(w), None, XtWindow(w),
5196 0, 0, 0, 0,
5197 w->picture.xbuff[i], w->picture.ybuff[i]);
5198 break;
5199 }
5200 }
5201 }
5202 w->picture.CursorBlank = False;
5203 }
5204 return NULL;
5205 }
5206
5207 /*****************************************************************************/
5208 /* */
5209 /* Subroutine: select_cursor */
5210 /* Effect: Set Select flag for this cursor */
5211 /* */
5212 /*****************************************************************************/
5213 static int
select_cursor(XmPictureWidget w,int id)5214 select_cursor ( XmPictureWidget w , int id)
5215 {
5216 if ((w->picture.mode == XmCURSOR_MODE) ||
5217 (w->picture.mode == XmPICK_MODE) )
5218 {
5219 w->picture.selected[id] = True;
5220 }
5221 else
5222 {
5223 w->picture.roam_selected = True;
5224 }
5225
5226 return 0;
5227 }
5228
5229 /*****************************************************************************/
5230 /* */
5231 /* Subroutine: deselect_cursor */
5232 /* Effect: deselect all 32 cursors */
5233 /* */
5234 /*****************************************************************************/
5235 static int
deselect_cursor(XmPictureWidget w)5236 deselect_cursor (XmPictureWidget w)
5237 {
5238 int i;
5239
5240 if ((w->picture.mode == XmCURSOR_MODE) ||
5241 (w->picture.mode == XmPICK_MODE) )
5242 {
5243 for ( i = 0 ; i < w->picture.n_cursors ; i++ )
5244 {
5245 w->picture.selected[i] = False;
5246 }
5247 }
5248 else
5249 {
5250 w->picture.roam_selected = False;
5251 }
5252
5253 return 0;
5254 }
5255
5256 /*****************************************************************************/
5257 /* */
5258 /* Subroutine: create_cursor */
5259 /* Effect: Realloc all of the required arrays */
5260 /* */
5261 /*****************************************************************************/
5262 static int
create_cursor(XmPictureWidget w)5263 create_cursor (XmPictureWidget w)
5264 {
5265 int *itmp;
5266 double *dtmp;
5267 int i;
5268
5269 /*
5270 * Realloc the appropriate arrays
5271 */
5272 itmp = (int *)XtMalloc((w->picture.n_cursors + 1)*sizeof(int));
5273 for (i = 0; i < w->picture.n_cursors; i++)
5274 {
5275 itmp[i] = w->picture.xbuff[i];
5276 }
5277 if (w->picture.n_cursors > 0)
5278 {
5279 XtFree((char*)w->picture.xbuff);
5280 }
5281 w->picture.xbuff = itmp;
5282
5283 itmp = (int *)XtMalloc((w->picture.n_cursors + 1)*sizeof(int));
5284 for (i = 0; i < w->picture.n_cursors; i++)
5285 {
5286 itmp[i] = w->picture.ybuff[i];
5287 }
5288 if (w->picture.n_cursors > 0)
5289 {
5290 XtFree((char*)w->picture.ybuff);
5291 }
5292 w->picture.ybuff = itmp;
5293
5294 dtmp = (double *)XtMalloc((w->picture.n_cursors + 1)*sizeof(double));
5295 for (i = 0; i < w->picture.n_cursors; i++)
5296 {
5297 dtmp[i] = w->picture.zbuff[i];
5298 }
5299 if (w->picture.n_cursors > 0)
5300 {
5301 XtFree((char*)w->picture.zbuff);
5302 }
5303 w->picture.zbuff = dtmp;
5304
5305 dtmp = (double *)XtMalloc((w->picture.n_cursors + 1)*sizeof(double));
5306 for (i = 0; i < w->picture.n_cursors; i++)
5307 {
5308 dtmp[i] = w->picture.cxbuff[i];
5309 }
5310 if (w->picture.n_cursors > 0)
5311 {
5312 XtFree((char*)w->picture.cxbuff);
5313 }
5314 w->picture.cxbuff = dtmp;
5315
5316 dtmp = (double *)XtMalloc((w->picture.n_cursors + 1)*sizeof(double));
5317 for (i = 0; i < w->picture.n_cursors; i++)
5318 {
5319 dtmp[i] = w->picture.cybuff[i];
5320 }
5321 if (w->picture.n_cursors > 0)
5322 {
5323 XtFree((char*)w->picture.cybuff);
5324 }
5325 w->picture.cybuff = dtmp;
5326
5327 dtmp = (double *)XtMalloc((w->picture.n_cursors + 1)*sizeof(double));
5328 for (i = 0; i < w->picture.n_cursors; i++)
5329 {
5330 dtmp[i] = w->picture.czbuff[i];
5331 }
5332 if (w->picture.n_cursors > 0)
5333 {
5334 XtFree((char*)w->picture.czbuff);
5335 }
5336 w->picture.czbuff = dtmp;
5337
5338 itmp = (int *)XtMalloc((w->picture.n_cursors + 1)*sizeof(int));
5339 for (i = 0; i < w->picture.n_cursors; i++)
5340 {
5341 itmp[i] = w->picture.selected[i];
5342 }
5343 if (w->picture.n_cursors > 0)
5344 {
5345 XtFree((char*)w->picture.selected);
5346 }
5347 w->picture.selected = itmp;
5348
5349 w->picture.selected[w->picture.n_cursors] = False;
5350 w->picture.n_cursors++;
5351
5352 return (w->picture.n_cursors - 1);
5353 }
5354
5355 /*****************************************************************************/
5356 /* */
5357 /* Subroutine: delete_cursor */
5358 /* Effect: make cursor inactive by setting appropriate flags */
5359 /* */
5360 /*****************************************************************************/
5361 static int
delete_cursor(XmPictureWidget w,int id)5362 delete_cursor ( XmPictureWidget w, int id )
5363 {
5364 int *itmp;
5365 double *dtmp;
5366 int i;
5367 int k;
5368
5369 w->picture.selected[id] = False;
5370
5371 /*
5372 * Erase the cursor.
5373 */
5374 if (!w->image.frame_buffer)
5375 {
5376 if (w->picture.pixmap != XmUNSPECIFIED_PIXMAP)
5377 XCopyArea (XtDisplay(w), w->picture.pixmap, XtWindow(w), w->picture.gc,
5378 w->picture.xbuff[id] - w->picture.cursor_size/2,
5379 w->picture.ybuff[id] - w->picture.cursor_size/2,
5380 w->picture.cursor_size, w->picture.cursor_size,
5381 w->picture.xbuff[id] - w->picture.cursor_size/2,
5382 w->picture.ybuff[id] - w->picture.cursor_size/2);
5383 }
5384 else
5385 {
5386 XClearArea (XtDisplay(w), w->picture.overlay_wid,
5387 w->picture.xbuff[id] - w->picture.cursor_size/2,
5388 w->picture.ybuff[id] - w->picture.cursor_size/2,
5389 w->picture.cursor_size, w->picture.cursor_size,
5390 False);
5391 }
5392
5393 /*
5394 * Realloc the arrays
5395 */
5396
5397 /*
5398 * xbuff
5399 */
5400 itmp = (int *)XtMalloc((w->picture.n_cursors - 1)*sizeof(int));
5401 k = 0;
5402 for (i = 0; i < w->picture.n_cursors; i++)
5403 {
5404 if (id != i) itmp[k++] = w->picture.xbuff[i];
5405 }
5406 XtFree((char*)w->picture.xbuff);
5407 w->picture.xbuff = itmp;
5408
5409 /*
5410 * ybuff
5411 */
5412 itmp = (int *)XtMalloc((w->picture.n_cursors - 1)*sizeof(int));
5413 k = 0;
5414 for (i = 0; i < w->picture.n_cursors; i++)
5415 {
5416 if (id != i) itmp[k++] = w->picture.ybuff[i];
5417 }
5418 XtFree((char*)w->picture.ybuff);
5419 w->picture.ybuff = itmp;
5420
5421 /*
5422 * zbuff
5423 */
5424 dtmp = (double *)XtMalloc((w->picture.n_cursors - 1)*sizeof(double));
5425 k = 0;
5426 for (i = 0; i < w->picture.n_cursors; i++)
5427 {
5428 if (id != i) dtmp[k++] = w->picture.zbuff[i];
5429 }
5430 XtFree((char*)w->picture.zbuff);
5431 w->picture.zbuff = dtmp;
5432
5433 /*
5434 * cxbuff
5435 */
5436 dtmp = (double *)XtMalloc((w->picture.n_cursors - 1)*sizeof(double));
5437 k = 0;
5438 for (i = 0; i < w->picture.n_cursors; i++)
5439 {
5440 if (id != i) dtmp[k++] = w->picture.cxbuff[i];
5441 }
5442 XtFree((char*)w->picture.cxbuff);
5443 w->picture.cxbuff = dtmp;
5444
5445 /*
5446 * cybuff
5447 */
5448 dtmp = (double *)XtMalloc((w->picture.n_cursors - 1)*sizeof(double));
5449 k = 0;
5450 for (i = 0; i < w->picture.n_cursors; i++)
5451 {
5452 if (id != i) dtmp[k++] = w->picture.cybuff[i];
5453 }
5454 XtFree((char*)w->picture.cybuff);
5455 w->picture.cybuff = dtmp;
5456
5457 /*
5458 * czbuff
5459 */
5460 dtmp = (double *)XtMalloc((w->picture.n_cursors - 1)*sizeof(double));
5461 k = 0;
5462 for (i = 0; i < w->picture.n_cursors; i++)
5463 {
5464 if (id != i) dtmp[k++] = w->picture.czbuff[i];
5465 }
5466 XtFree((char*)w->picture.czbuff);
5467 w->picture.czbuff = dtmp;
5468
5469 /*
5470 * selected
5471 */
5472 itmp = (int *)XtMalloc((w->picture.n_cursors - 1)*sizeof(int));
5473 k = 0;
5474 for (i = 0; i < w->picture.n_cursors; i++)
5475 {
5476 if (id != i) itmp[k++] = w->picture.selected[i];
5477 }
5478 XtFree((char*)w->picture.selected);
5479 w->picture.selected = itmp;
5480
5481 w->picture.n_cursors--;
5482 if (w->picture.pixmap != XmUNSPECIFIED_PIXMAP) {
5483 draw_cursors( w );
5484 XFlush(XtDisplay(w));
5485 }
5486 return 0;
5487 }
5488
5489 /************************************************************************
5490 *
5491 * CreateDelete
5492 *
5493 ************************************************************************/
5494
CreateDelete(w,event)5495 static void CreateDelete (w, event)
5496 XmPictureWidget w;
5497 XEvent *event;
5498
5499 {
5500 int i;
5501 int x;
5502 int y;
5503 int id;
5504 Boolean new_box;
5505
5506 x = event->xbutton.x ;
5507 y = event->xbutton.y ;
5508
5509 id = find_closest ( w, x, y );
5510
5511 if ( id != -1 )
5512 {
5513 if ((w->picture.mode == XmROAM_MODE) ||
5514 (w->picture.mode == XmPICK_MODE))
5515 return;
5516
5517 delete_cursor ( w, id );
5518 CallCursorCallbacks(w, XmPCR_DELETE, id, 0, 0, 0);
5519 return;
5520 }
5521 else
5522 {
5523 /*
5524 * This should not fail, but check the result just in case...
5525 */
5526 w->picture.Z = line_of_sight ( w, (double)(x),
5527 (double)(y),
5528 w->picture.Wtrans,
5529 w->picture.WItrans );
5530
5531 /*
5532 * See if we did not hit the box
5533 */
5534 if ( w->picture.Z == -DBL_MAX )
5535 {
5536 /*
5537 * Choose a reasonable Z value
5538 */
5539 w->picture.Z = w->picture.Zmin +
5540 (w->picture.Zmax - w->picture.Zmin)/2;
5541 new_box = True;
5542 }
5543 else
5544 {
5545 new_box = False;
5546 }
5547
5548 /*
5549 * Got a good position, so procede...
5550 */
5551 if ((w->picture.mode == XmCURSOR_MODE) ||
5552 (w->picture.mode == XmPICK_MODE))
5553 {
5554 w->picture.X = x;
5555 w->picture.Y = y;
5556
5557 deselect_cursor (w);
5558 id = create_cursor(w);
5559 w->picture.xbuff[id] = x;
5560 w->picture.ybuff[id] = y;
5561 w->picture.zbuff[id] = w->picture.Z;
5562 if(w->picture.mode == XmCURSOR_MODE)
5563 select_cursor ( w , id );
5564 else if(w->picture.mode == XmPICK_MODE)
5565 deselect_cursor(w);
5566 save_cursors_in_canonical_form(w, id);
5567 }
5568 else if (w->picture.mode == XmROAM_MODE)
5569 {
5570 /*
5571 * Erase the roam cursor.
5572 */
5573 if (!w->image.frame_buffer)
5574 {
5575 if (w->picture.pixmap == XmUNSPECIFIED_PIXMAP) return;
5576 XCopyArea (XtDisplay(w), w->picture.pixmap, XtWindow(w),
5577 w->picture.gc,
5578 w->picture.roam_xbuff - w->picture.cursor_size/2,
5579 w->picture.roam_ybuff - w->picture.cursor_size/2,
5580 w->picture.cursor_size, w->picture.cursor_size,
5581 w->picture.roam_xbuff - w->picture.cursor_size/2,
5582 w->picture.roam_ybuff - w->picture.cursor_size/2);
5583 }
5584 else
5585 {
5586 XClearArea (XtDisplay(w), w->picture.overlay_wid,
5587 w->picture.roam_xbuff - w->picture.cursor_size/2,
5588 w->picture.roam_ybuff - w->picture.cursor_size/2,
5589 w->picture.cursor_size, w->picture.cursor_size,
5590 False);
5591 }
5592
5593 w->picture.X = x;
5594 w->picture.Y = y;
5595
5596 w->picture.roam_xbuff = x;
5597 w->picture.roam_ybuff = y;
5598 w->picture.roam_zbuff = w->picture.Z;
5599 select_cursor ( w , 0 );
5600 save_cursors_in_canonical_form(w, -1);
5601 }
5602
5603 if (w->picture.mode == XmROAM_MODE)
5604 {
5605 w->picture.ignore_new_camera++;
5606 CallCursorCallbacks(w, XmPCR_MOVE, id, w->picture.X, w->picture.Y,
5607 w->picture.Z);
5608 }
5609 else
5610 {
5611 w->picture.ignore_new_camera++;
5612 CallCursorCallbacks(w, XmPCR_CREATE, id, w->picture.X, w->picture.Y,
5613 w->picture.Z);
5614 }
5615
5616 if ( w->picture.FirstTime != True )
5617 {
5618 for ( i = 0 ; i < w->picture.piMark ; i++ )
5619 {
5620 if (!w->image.frame_buffer)
5621 {
5622 XCopyArea (XtDisplay(w), w->picture.pixmap, XtWindow(w),
5623 w->picture.gc,
5624 (int)(w->picture.pXmark[i]) - 1,
5625 (int)(w->picture.pYmark[i]) - 1, 3, 3,
5626 (int)(w->picture.pXmark[i]) - 1,
5627 (int)(w->picture.pYmark[i]) - 1);
5628 }
5629 else
5630 {
5631 XClearArea (XtDisplay(w), w->picture.overlay_wid,
5632 (int)(w->picture.pXmark[i]) - 1,
5633 (int)(w->picture.pYmark[i]) - 1, 3, 3,
5634 False);
5635 }
5636 }
5637 }
5638
5639 if (new_box && w->picture.mode == XmCURSOR_MODE) erase_image(w);
5640 draw_cursors(w);
5641
5642 if(w->picture.mode == XmPICK_MODE) return;
5643 /*
5644 * reset the pointer history buffer
5645 */
5646 w->picture.K = 0;
5647 add2historybuffer(w, x, y);
5648
5649 draw_gnomon(w);
5650 if (new_box) setup_bounding_box(w);
5651 XmDrawBbox (w);
5652
5653 project ( w, (double)x, (double)y,
5654 (double)w->picture.Z, w->picture.Wtrans,
5655 w->picture.WItrans );
5656
5657 draw_marker (w);
5658
5659 w->picture.FirstTime = False;
5660 w->picture.FirstTimeMotion = True;
5661 id = move_selected_cursor ( w, (int)w->picture.X, (int)w->picture.Y,
5662 w->picture.Z);
5663
5664 /* record prev cursor x,y so we can erase it next time it is moved */
5665 w->picture.pcx = (int)w->picture.X;
5666 w->picture.pcy = (int)w->picture.Y;
5667 }
5668 }
5669
5670 /* ------------- The Geometry and Rendering code ----------------------- */
5671
5672 /*****************************************************************************/
5673 /* */
5674 /* Subroutine: draw_gnomon */
5675 /* Effect: Draw the gnomon */
5676 /* */
5677 /*****************************************************************************/
5678
draw_gnomon(w)5679 static void draw_gnomon (w)
5680 XmPictureWidget w;
5681 {
5682 Display *dpy;
5683 Window dw;
5684 GC gc;
5685 int width;
5686 int height;
5687
5688 dpy = XtDisplay(w);
5689 if(!w->image.frame_buffer)
5690 {
5691 dw = XtWindow(w);
5692 gc = w->picture.gc;
5693 }
5694 else
5695 {
5696 dw = w->picture.overlay_wid;
5697 gc = w->picture.gcovl;
5698 }
5699
5700 if(w->picture.box_grey.pixel == 0)
5701 convert_color(w, &w->picture.box_grey);
5702 /*
5703 * Erase the old image by restoring the background image
5704 */
5705 width = w->core.width - w->picture.gnomon_center_x;
5706 height = w->core.height - w->picture.gnomon_center_y;
5707 if((!w->image.frame_buffer) && (w->picture.pixmap != XmUNSPECIFIED_PIXMAP))
5708 {
5709 XCopyArea (XtDisplay(w), w->picture.pixmap, XtWindow(w), w->picture.gc,
5710 w->picture.gnomon_center_x - (width + 20),
5711 w->picture.gnomon_center_y - (height + 20),
5712 2*width + 20, 2*height + 20,
5713 (w->picture.gnomon_center_x - width) - 20,
5714 (w->picture.gnomon_center_y - height) - 20);
5715 }
5716 else if (w->image.frame_buffer)
5717 {
5718 XClearArea(XtDisplay(w), w->picture.overlay_wid,
5719 (w->picture.gnomon_center_x - width) - 20,
5720 (w->picture.gnomon_center_y - height) - 20,
5721 2*width + 20, 2*height + 20, False);
5722 }
5723
5724 /*
5725 * Draw black projected X axis
5726 */
5727 if ( (w->picture.x_movement_allowed) &&
5728 ( (w->picture.constrain_cursor == XmCONSTRAIN_NONE) ||
5729 (w->picture.constrain_cursor == XmCONSTRAIN_X) ) )
5730 {
5731 XSetForeground( dpy, gc, w->picture.black);
5732
5733 XDrawLine( dpy, dw, gc,
5734 w->picture.gnomon_center_x-1,
5735 w->picture.gnomon_center_y-1,
5736 w->picture.gnomon_xaxis_x-1,
5737 w->picture.gnomon_xaxis_y-1);
5738 draw_arrow_head(w, w->picture.gnomon_center_x-1,
5739 w->picture.gnomon_center_y-1,
5740 w->picture.gnomon_xaxis_x-1,
5741 w->picture.gnomon_xaxis_y-1);
5742
5743 XDrawString( dpy, dw, gc,
5744 w->picture.gnomon_xaxis_label_x-1,
5745 w->picture.gnomon_xaxis_label_y-1,
5746 "X", 1);
5747 }
5748 /*
5749 * Draw white projected X axis
5750 */
5751 if ( (w->picture.x_movement_allowed) &&
5752 ( (w->picture.constrain_cursor == XmCONSTRAIN_NONE) ||
5753 (w->picture.constrain_cursor == XmCONSTRAIN_X) ) )
5754 {
5755 XSetForeground( dpy, gc, w->picture.white);
5756 }
5757 else
5758 {
5759 XSetForeground( dpy, gc, w->picture.box_grey.pixel);
5760 }
5761 XDrawLine( dpy, dw, gc,
5762 w->picture.gnomon_center_x,
5763 w->picture.gnomon_center_y,
5764 w->picture.gnomon_xaxis_x,
5765 w->picture.gnomon_xaxis_y);
5766 draw_arrow_head(w, w->picture.gnomon_center_x,
5767 w->picture.gnomon_center_y,
5768 w->picture.gnomon_xaxis_x,
5769 w->picture.gnomon_xaxis_y);
5770
5771 XDrawString( dpy, dw, gc,
5772 w->picture.gnomon_xaxis_label_x,
5773 w->picture.gnomon_xaxis_label_y,
5774 "X", 1);
5775 /*
5776 * Draw black projected Y axis
5777 */
5778 if ( (w->picture.y_movement_allowed) &&
5779 ( (w->picture.constrain_cursor == XmCONSTRAIN_NONE) ||
5780 (w->picture.constrain_cursor == XmCONSTRAIN_Y) ) )
5781 {
5782 XSetForeground( dpy, gc, w->picture.black);
5783
5784 XDrawLine( dpy, dw, gc,
5785 w->picture.gnomon_center_x-1,
5786 w->picture.gnomon_center_y-1,
5787 w->picture.gnomon_yaxis_x-1,
5788 w->picture.gnomon_yaxis_y-1);
5789 draw_arrow_head(w, w->picture.gnomon_center_x-1,
5790 w->picture.gnomon_center_y-1,
5791 w->picture.gnomon_yaxis_x-1,
5792 w->picture.gnomon_yaxis_y-1);
5793 XDrawString( dpy, dw, gc,
5794 w->picture.gnomon_yaxis_label_x-1,
5795 w->picture.gnomon_yaxis_label_y-1,
5796 "Y", 1);
5797 }
5798 /*
5799 * Draw white projected Y axis
5800 */
5801 if ( (w->picture.y_movement_allowed) &&
5802 ( (w->picture.constrain_cursor == XmCONSTRAIN_NONE) ||
5803 (w->picture.constrain_cursor == XmCONSTRAIN_Y) ) )
5804 {
5805 XSetForeground( dpy, gc, w->picture.white);
5806 }
5807 else
5808 {
5809 XSetForeground( dpy, gc, w->picture.box_grey.pixel);
5810 }
5811 XDrawLine( dpy, dw, gc,
5812 w->picture.gnomon_center_x,
5813 w->picture.gnomon_center_y,
5814 w->picture.gnomon_yaxis_x,
5815 w->picture.gnomon_yaxis_y);
5816 draw_arrow_head(w, w->picture.gnomon_center_x,
5817 w->picture.gnomon_center_y,
5818 w->picture.gnomon_yaxis_x,
5819 w->picture.gnomon_yaxis_y);
5820 XDrawString( dpy, dw, gc,
5821 w->picture.gnomon_yaxis_label_x,
5822 w->picture.gnomon_yaxis_label_y,
5823 "Y", 1);
5824 /*
5825 * Draw black projected Z axis
5826 */
5827 if ( (w->picture.z_movement_allowed) &&
5828 ( (w->picture.constrain_cursor == XmCONSTRAIN_NONE) ||
5829 (w->picture.constrain_cursor == XmCONSTRAIN_Z) ) )
5830 {
5831 XSetForeground( dpy, gc, w->picture.black);
5832
5833 XDrawLine( dpy, dw, gc,
5834 w->picture.gnomon_center_x-1,
5835 w->picture.gnomon_center_y-1,
5836 w->picture.gnomon_zaxis_x-1,
5837 w->picture.gnomon_zaxis_y-1);
5838
5839 draw_arrow_head(w, w->picture.gnomon_center_x-1,
5840 w->picture.gnomon_center_y-1,
5841 w->picture.gnomon_zaxis_x-1,
5842 w->picture.gnomon_zaxis_y-1);
5843 XDrawString( dpy, dw, gc,
5844 w->picture.gnomon_zaxis_label_x-1,
5845 w->picture.gnomon_zaxis_label_y-1,
5846 "Z", 1);
5847 }
5848 /*
5849 * Draw white projected Z axis
5850 */
5851 if ( (w->picture.z_movement_allowed) &&
5852 ( (w->picture.constrain_cursor == XmCONSTRAIN_NONE) ||
5853 (w->picture.constrain_cursor == XmCONSTRAIN_Z) ) )
5854 {
5855 XSetForeground( dpy, gc, w->picture.white);
5856 }
5857 else
5858 {
5859 XSetForeground( dpy, gc, w->picture.box_grey.pixel);
5860 }
5861 XDrawLine( dpy, dw, gc,
5862 w->picture.gnomon_center_x,
5863 w->picture.gnomon_center_y,
5864 w->picture.gnomon_zaxis_x,
5865 w->picture.gnomon_zaxis_y);
5866
5867 draw_arrow_head(w, w->picture.gnomon_center_x,
5868 w->picture.gnomon_center_y,
5869 w->picture.gnomon_zaxis_x,
5870 w->picture.gnomon_zaxis_y);
5871 XDrawString( dpy, dw, gc,
5872 w->picture.gnomon_zaxis_label_x,
5873 w->picture.gnomon_zaxis_label_y,
5874 "Z", 1);
5875
5876 XFlush(XtDisplay(w));
5877 }
5878
5879 /*****************************************************************************/
5880 /* */
5881 /* Subroutine: XmDrawBbox */
5882 /* Effect: Draw the bounding box */
5883 /* */
5884 /*****************************************************************************/
5885
XmDrawBbox(w)5886 static void XmDrawBbox (w)
5887 XmPictureWidget w;
5888 {
5889 Display *dpy;
5890 Window dw;
5891 GC gc;
5892 GC gc_solid;
5893 GC gc_dash;
5894 int i;
5895
5896 dpy = XtDisplay(w);
5897 if(!w->image.frame_buffer)
5898 {
5899 dw = XtWindow(w);
5900 gc_solid = w->picture.gc;
5901 gc_dash = w->picture.gc_dash;
5902 }
5903 else
5904 {
5905 dw = w->picture.overlay_wid;
5906 gc_solid = w->picture.gcovl;
5907 gc_dash = w->picture.gcovl_dash;
5908 }
5909
5910 if(w->picture.box_grey.pixel == 0)
5911 convert_color(w, &w->picture.box_grey);
5912
5913 /*
5914 * Draw all the dashed lines first, in case they are coincident with a
5915 * solid line.
5916 */
5917 gc = gc_dash;
5918 for (i = 0; i < 12; i++)
5919 {
5920 if (w->picture.box_line[i].greyed)
5921 XSetForeground( dpy, gc, w->picture.box_grey.pixel);
5922 else
5923 XSetForeground( dpy, gc, w->picture.white);
5924
5925 if ( (!w->picture.box_line[i].rejected) &&
5926 (w->picture.box_line[i].dotted) )
5927 XDrawLine ( dpy, dw, gc,
5928 w->picture.box_line[i].x1,
5929 w->picture.box_line[i].y1,
5930 w->picture.box_line[i].x2,
5931 w->picture.box_line[i].y2);
5932 }
5933 /*
5934 * Draw all the solid lines last, in case they are coincident with a
5935 * dashed line.
5936 */
5937 gc = gc_solid;
5938 for (i = 0; i < 12; i++)
5939 {
5940 if (w->picture.box_line[i].greyed)
5941 XSetForeground( dpy, gc, w->picture.box_grey.pixel);
5942 else
5943 XSetForeground( dpy, gc, w->picture.white);
5944
5945 if ( (!w->picture.box_line[i].rejected) &&
5946 (!w->picture.box_line[i].dotted) )
5947 XDrawLine ( dpy, dw, gc,
5948 w->picture.box_line[i].x1,
5949 w->picture.box_line[i].y1,
5950 w->picture.box_line[i].x2,
5951 w->picture.box_line[i].y2);
5952 }
5953 XFlush(XtDisplay(w));
5954 }
5955
5956
5957 /*****************************************************************************/
5958 /* */
5959 /* Subroutine: constrain */
5960 /* Effect: force a transformed point to be inside the bounding box */
5961 /* */
5962 /*****************************************************************************/
constrain(w,s0,s1,s2,dx,dy,dz,WItrans,Wtrans,sdx,sdy)5963 static int constrain ( w, s0, s1 ,s2, dx, dy, dz, WItrans, Wtrans, sdx, sdy )
5964 XmPictureWidget w;
5965 double *s0;
5966 double *s1;
5967 double *s2;
5968 double dx;
5969 double dy;
5970 double dz;
5971 double WItrans[4][4];
5972 double Wtrans[4][4];
5973 int sdx;
5974 int sdy;
5975 {
5976 double sxcoor;
5977 double sycoor;
5978 double szcoor;
5979 double original_dist;
5980 double new_dist;
5981 double normalize;
5982 double x, y, z;
5983 double sav_x, sav_y, sav_z;
5984 double old_x, old_y, old_z;
5985
5986 /*
5987 * Remember the old positions
5988 */
5989 old_x = *s0;
5990 old_y = *s1;
5991 old_z = *s2;
5992 original_dist = sqrt(sdx*sdx + sdy*sdy);
5993
5994 /* xform point back to cannonocal coords */
5995 perspective_divide_inverse(w, *s0, *s1, *s2, s0, s1);
5996 xform_coords( WItrans, *s0, *s1, *s2, &x, &y, &z);
5997
5998 sav_x = x;
5999 sav_y = y;
6000 sav_z = z;
6001
6002 /*
6003 * Start out by moving 1/100 of the distance in world coords.
6004 */
6005 x += dx*(w->picture.FacetXmax - w->picture.FacetXmin)/100;
6006 y += dy*(w->picture.FacetYmax - w->picture.FacetYmin)/100;
6007 z += dz*(w->picture.FacetZmax - w->picture.FacetZmin)/100;
6008
6009 /*
6010 * Now, xform back to screen coords to see how far we have moved.
6011 */
6012 xform_coords( w->picture.Wtrans, x, y, z, &sxcoor, &sycoor, &szcoor);
6013 perspective_divide(w, sxcoor, sycoor, szcoor, &sxcoor, &sycoor);
6014
6015 /*
6016 * See how far we have moved.
6017 */
6018 new_dist = sqrt((sxcoor - w->picture.pcx)*(sxcoor - w->picture.pcx) +
6019 (sycoor - w->picture.pcy)*(sycoor - w->picture.pcy));
6020
6021 if (new_dist != 0.0)
6022 {
6023 normalize = original_dist/new_dist;
6024 dx = dx * normalize;
6025 dy = dy * normalize;
6026 dz = dz * normalize;
6027 }
6028 /*
6029 * Modify the deltas as appropriate.
6030 */
6031 if (w->picture.cursor_speed == XmSLOW_CURSOR)
6032 {
6033 dx = dx*(w->picture.FacetXmax - w->picture.FacetXmin)/300;
6034 dy = dy*(w->picture.FacetYmax - w->picture.FacetYmin)/300;
6035 dz = dz*(w->picture.FacetZmax - w->picture.FacetZmin)/300;
6036 }
6037 if (w->picture.cursor_speed == XmMEDIUM_CURSOR)
6038 {
6039 dx = dx*(w->picture.FacetXmax - w->picture.FacetXmin)/100;
6040 dy = dy*(w->picture.FacetYmax - w->picture.FacetYmin)/100;
6041 dz = dz*(w->picture.FacetZmax - w->picture.FacetZmin)/100;
6042 }
6043 if (w->picture.cursor_speed == XmFAST_CURSOR)
6044 {
6045 dx = dx*(w->picture.FacetXmax - w->picture.FacetXmin)/33;
6046 dy = dy*(w->picture.FacetYmax - w->picture.FacetYmin)/33;
6047 dz = dz*(w->picture.FacetZmax - w->picture.FacetZmin)/33;
6048 }
6049
6050 /*
6051 * Apply the new deltas.
6052 */
6053 x = dx + sav_x;
6054 y = dy + sav_y;
6055 z = dz + sav_z;
6056
6057 /* adjust the point so it lies w/in the bounding box */
6058 if (x < 0.0)
6059 {
6060 x = 0.0;
6061 }
6062 if (y < 0.0)
6063 {
6064 y = 0.0;
6065 }
6066 if (z < 0.0)
6067 {
6068 z = 0.0;
6069 }
6070 if (x > w->picture.FacetXmax)
6071 {
6072 x = w->picture.FacetXmax;
6073 }
6074 if (y > w->picture.FacetYmax)
6075 {
6076 y = w->picture.FacetYmax;
6077 }
6078 if (z > w->picture.FacetZmax)
6079 {
6080 z = w->picture.FacetZmax;
6081 }
6082
6083 /* xform the point back to image coord system */
6084 xform_coords( Wtrans, x, y, z, s0, s1, s2);
6085 perspective_divide(w, *s0, *s1, *s2, s0, s1);
6086
6087 /*
6088 * If we have attempted to move out of the widow, throw away the
6089 * change by restoring the original position.
6090 */
6091 if ( (*s0 < 0.0) || (*s0 > w->core.width - w->picture.cursor_size) ||
6092 (*s1 < 0.0) || (*s1 > w->core.height - w->picture.cursor_size) )
6093 {
6094 *s0 = old_x;
6095 *s1 = old_y;
6096 *s2 = old_z;
6097 }
6098 return 0;
6099 }
6100 /*****************************************************************************/
6101 /* */
6102 /* Subroutine: save_cursors_in_canonical form */
6103 /* Effect: xform the cursor points to world coords and save */
6104 /* */
6105 /*****************************************************************************/
save_cursors_in_canonical_form(XmPictureWidget w,int i)6106 static void save_cursors_in_canonical_form (XmPictureWidget w, int i)
6107 {
6108 double x, y, z;
6109
6110 if (i >= 0)
6111 {
6112 perspective_divide_inverse(w, (double)w->picture.xbuff[i],
6113 (double)w->picture.ybuff[i],
6114 w->picture.zbuff[i],
6115 &x, &y);
6116 xform_coords( w->picture.PureWItrans,
6117 x, y, w->picture.zbuff[i], &x, &y, &z);
6118 w->picture.cxbuff[i] = x;
6119 w->picture.cybuff[i] = y;
6120 w->picture.czbuff[i] = z;
6121 }
6122 else
6123 {
6124 perspective_divide_inverse(w, (double)w->picture.roam_xbuff,
6125 (double)w->picture.roam_ybuff,
6126 w->picture.roam_zbuff,
6127 &x, &y);
6128 xform_coords( w->picture.PureWItrans,
6129 x, y, w->picture.roam_zbuff, &x, &y, &z);
6130 w->picture.roam_cxbuff = x;
6131 w->picture.roam_cybuff = y;
6132 w->picture.roam_czbuff = z;
6133 }
6134 }
6135
6136 /*****************************************************************************/
6137 /* */
6138 /* Subroutine: restore_cursors_from_canonical form */
6139 /* Effect: xform the cursor points from world to screen coords */
6140 /* */
6141 /*****************************************************************************/
restore_cursors_from_canonical_form(XmPictureWidget w)6142 static void restore_cursors_from_canonical_form (XmPictureWidget w)
6143 {
6144 int i;
6145 double x;
6146 double y;
6147 double z;
6148
6149 /* xform point back from canonical coords */
6150 for(i = 0; i < w->picture.n_cursors; i++)
6151 {
6152 xform_coords( w->picture.PureWtrans,
6153 w->picture.cxbuff[i],
6154 w->picture.cybuff[i],
6155 w->picture.czbuff[i],
6156 &x, &y, &z);
6157 perspective_divide(w, x, y, z, &x, &y);
6158 w->picture.xbuff[i] = (int) x;
6159 w->picture.ybuff[i] = (int) y;
6160 w->picture.zbuff[i] = z;
6161 }
6162
6163 xform_coords( w->picture.PureWtrans,
6164 w->picture.roam_cxbuff,
6165 w->picture.roam_cybuff,
6166 w->picture.roam_czbuff,
6167 &x, &y, &z);
6168 perspective_divide(w, x, y, z, &x, &y);
6169 w->picture.roam_xbuff = (int) x;
6170 w->picture.roam_ybuff = (int) y;
6171 w->picture.roam_zbuff = z;
6172 }
6173
6174 /*****************************************************************************/
6175 /* */
6176 /* Subroutine: line_of_sight */
6177 /* Effect: when the mouse is clicked on the bounding box, calculate where*/
6178 /* the intersection is and return z */
6179 /* */
6180 /*****************************************************************************/
line_of_sight(w,s0,s1,Wtrans,WItrans)6181 static double line_of_sight ( w, s0, s1, Wtrans, WItrans )
6182 XmPictureWidget w;
6183 double s0;
6184 double s1;
6185 double Wtrans[4][4];
6186 double WItrans[4][4];
6187
6188 {
6189 int i = -1, II;
6190 double x, y, z, lx, ly, lz, minz, maxz, t, xt, yt, zt;
6191 double xmark[8], ymark[8], zmark[8];
6192
6193 /* as far as possible from the box */
6194 z = (double)(w->picture.Zmax + 100);
6195 xform_coords( WItrans, s0, s1, z, &x, &y, &z);
6196
6197 lx = (0.0 * WItrans[0][Xaxis]) + (0.0 * WItrans[1][Xaxis]) +
6198 (-1.0 * WItrans[2][Xaxis]) ;
6199
6200 ly = (0.0 * WItrans[0][Yaxis]) + (0.0 * WItrans[1][Yaxis]) +
6201 (-1.0 * WItrans[2][Yaxis]);
6202
6203 lz = (0.0 * WItrans[0][Zaxis]) + (0.0 * WItrans[1][Zaxis]) +
6204 (-1.0 * WItrans[2][Zaxis]);
6205
6206 /* line of sight equation
6207 X = x + t*lx;
6208 Y = Y + t*ly;
6209 Z = z + t*ly;
6210 */
6211
6212
6213 if (ly != 0.0)
6214 {
6215 t = ((w->picture.Face1[0].ycoor - y) / ly) + 0.00001;
6216 xt = x + ( t * lx );
6217 yt = y + ( t * ly );
6218 zt = z + ( t * lz );
6219
6220 if ( (xt >= 0.0) && (xt <= w->picture.Face1[2].xcoor) &&
6221 (zt >= 0.0) && (zt <= w->picture.Face1[2].zcoor) )
6222 {
6223 i++;
6224 xform_coords( Wtrans, xt, yt, zt, &xmark[i], &ymark[i], &zmark[i]);
6225 }
6226 }
6227
6228
6229 if (ly != 0.0)
6230 {
6231 t = ((w->picture.Face2[0].ycoor - y) / ly) + 0.00001;
6232 xt = x + ( t * lx );
6233 yt = y + ( t * ly );
6234 zt = z + ( t * lz );
6235
6236 if ( (xt >= 0.0) && (xt <= w->picture.Face1[2].xcoor) &&
6237 (zt >= 0.0) && (zt <= w->picture.Face1[2].zcoor) )
6238 {
6239 i++;
6240 xform_coords( Wtrans, xt, yt, zt, &xmark[i], &ymark[i], &zmark[i]);
6241 }
6242 }
6243
6244
6245 if (lx != 0.0)
6246 {
6247 t = ((w->picture.Face2[0].xcoor - x) / lx) + 0.00001;
6248 xt = x + ( t * lx );
6249 yt = y + ( t * ly );
6250 zt = z + ( t * lz );
6251
6252 if ( (yt >= 0.0) && (yt <= w->picture.Face1[2].ycoor) &&
6253 (zt >= 0.0) && (zt <= w->picture.Face1[2].zcoor) )
6254 {
6255 i++;
6256 xform_coords( Wtrans, xt, yt, zt, &xmark[i], &ymark[i], &zmark[i]);
6257 }
6258 }
6259
6260
6261 if (lx != 0.0)
6262 {
6263 t = ((w->picture.Face2[3].xcoor - x) / lx) + 0.00001;
6264 xt = x + ( t * lx );
6265 yt = y + ( t * ly );
6266 zt = z + ( t * lz );
6267
6268 if ( (yt >= 0.0) && (yt <= w->picture.Face1[2].ycoor) &&
6269 (zt >= 0.0) && (zt <= w->picture.Face1[2].zcoor) )
6270 {
6271 i++;
6272 xform_coords( Wtrans, xt, yt, zt, &xmark[i], &ymark[i], &zmark[i]);
6273 }
6274 }
6275
6276
6277 if (lz != 0.0)
6278 {
6279 t = ((w->picture.Face1[1].zcoor - z) / lz) + 0.00001;
6280 xt = x + ( t * lx );
6281 yt = y + ( t * ly );
6282 zt = z + ( t * lz );
6283
6284 if ( (xt >= 0.0) && (xt <= w->picture.Face1[2].xcoor) &&
6285 (yt >= 0.0) && (yt <= w->picture.Face1[2].ycoor) )
6286 {
6287 i++;
6288 xform_coords( Wtrans, xt, yt, zt, &xmark[i], &ymark[i], &zmark[i]);
6289 }
6290 }
6291
6292
6293 if (lz != 0.0)
6294 {
6295 t = ((w->picture.Face1[0].zcoor - z) / lz) + 0.00001;
6296 xt = x + ( t * lx );
6297 yt = y + ( t * ly );
6298 zt = z + ( t * lz );
6299
6300 if ( (xt >= 0.0) && (xt <= w->picture.Face1[2].xcoor) &&
6301 (yt >= 0.0) && (yt <= w->picture.Face1[2].ycoor) )
6302 {
6303 i++;
6304 xform_coords( Wtrans, xt, yt, zt, &xmark[i], &ymark[i], &zmark[i]);
6305 }
6306 }
6307
6308 II = i;
6309
6310 maxz = -DBL_MAX;
6311 minz = DBL_MAX;
6312 for ( i = 0 ; i <= II ; i++ )
6313 {
6314 if ( zmark[i] > maxz )
6315 {
6316 maxz = zmark[i];
6317 }
6318 if ( zmark[i] < minz )
6319 {
6320 minz = zmark[i];
6321 }
6322 }
6323 if ( II == -1 )
6324 return ( -DBL_MAX );
6325
6326 z = minz + (maxz - minz)/2;
6327 return (z);
6328 }
6329
6330 /*****************************************************************************/
6331 /* */
6332 /* Subroutine: project */
6333 /* Effect: project the 3D cursor on to the 3 visible faces of the */
6334 /* bounding box */
6335 /* */
6336 /*****************************************************************************/
project(XmPictureWidget w,double s0,double s1,double s2,double Wtrans[4][4],double WItrans[4][4])6337 int project ( XmPictureWidget w, double s0, double s1 ,double s2,
6338 double Wtrans[4][4], double WItrans[4][4] )
6339 {
6340 int i = -1;
6341 double x, y, z;
6342
6343 perspective_divide_inverse(w, s0, s1, s2, &s0, &s1);
6344 xform_coords( WItrans, s0, s1, s2, &x, &y, &z);
6345
6346 if ( (w->picture.Face1[0].visible == True) &&
6347 (w->picture.Face1[1].visible == True) &&
6348 (w->picture.Face1[2].visible == True) &&
6349 (w->picture.Face1[3].visible == True) )
6350 {
6351 i++;
6352 xform_coords( Wtrans,
6353 x,
6354 w->picture.Face1[0].ycoor,
6355 z,
6356 &w->picture.Xmark[i],
6357 &w->picture.Ymark[i],
6358 &w->picture.Zmark[i]);
6359 perspective_divide(w, w->picture.Xmark[i], w->picture.Ymark[i],
6360 w->picture.Zmark[i], &w->picture.Xmark[i], &w->picture.Ymark[i]);
6361 }
6362
6363 if ( (w->picture.Face2[0].visible == True) &&
6364 (w->picture.Face2[1].visible == True) &&
6365 (w->picture.Face2[2].visible == True) &&
6366 (w->picture.Face2[3].visible == True) )
6367 {
6368 i++;
6369 xform_coords( Wtrans,
6370 x,
6371 0,
6372 z,
6373 &w->picture.Xmark[i],
6374 &w->picture.Ymark[i],
6375 &w->picture.Zmark[i]);
6376 perspective_divide(w, w->picture.Xmark[i], w->picture.Ymark[i],
6377 w->picture.Zmark[i], &w->picture.Xmark[i], &w->picture.Ymark[i]);
6378 }
6379
6380
6381 if ( (w->picture.Face1[0].visible == True) &&
6382 (w->picture.Face1[1].visible == True) &&
6383 (w->picture.Face2[1].visible == True) &&
6384 (w->picture.Face2[0].visible == True) )
6385 {
6386 i++;
6387 xform_coords( Wtrans,
6388 0,
6389 y,
6390 z,
6391 &w->picture.Xmark[i],
6392 &w->picture.Ymark[i],
6393 &w->picture.Zmark[i]);
6394 perspective_divide(w, w->picture.Xmark[i], w->picture.Ymark[i],
6395 w->picture.Zmark[i], &w->picture.Xmark[i], &w->picture.Ymark[i]);
6396 }
6397
6398 if ( (w->picture.Face1[2].visible == True) &&
6399 (w->picture.Face1[3].visible == True) &&
6400 (w->picture.Face2[2].visible == True) &&
6401 (w->picture.Face2[3].visible == True) )
6402 {
6403 i++;
6404 xform_coords( Wtrans,
6405 w->picture.Face2[3].xcoor,
6406 y,
6407 z,
6408 &w->picture.Xmark[i],
6409 &w->picture.Ymark[i],
6410 &w->picture.Zmark[i]);
6411 perspective_divide(w, w->picture.Xmark[i], w->picture.Ymark[i],
6412 w->picture.Zmark[i], &w->picture.Xmark[i], &w->picture.Ymark[i]);
6413 }
6414
6415 if ( (w->picture.Face1[1].visible == True) &&
6416 (w->picture.Face1[2].visible == True) &&
6417 (w->picture.Face2[1].visible == True) &&
6418 (w->picture.Face2[2].visible == True) )
6419 {
6420 i++;
6421 xform_coords( Wtrans,
6422 x,
6423 y,
6424 w->picture.Face2[1].zcoor,
6425 &w->picture.Xmark[i],
6426 &w->picture.Ymark[i],
6427 &w->picture.Zmark[i]);
6428 perspective_divide(w, w->picture.Xmark[i], w->picture.Ymark[i],
6429 w->picture.Zmark[i], &w->picture.Xmark[i], &w->picture.Ymark[i]);
6430 }
6431
6432 if ( (w->picture.Face1[0].visible == True) &&
6433 (w->picture.Face1[3].visible == True) &&
6434 (w->picture.Face2[0].visible == True) &&
6435 (w->picture.Face2[3].visible == True) )
6436 {
6437 i++;
6438 xform_coords( Wtrans,
6439 x,
6440 y,
6441 0.0,
6442 &w->picture.Xmark[i],
6443 &w->picture.Ymark[i],
6444 &w->picture.Zmark[i]);
6445 perspective_divide(w, w->picture.Xmark[i], w->picture.Ymark[i],
6446 w->picture.Zmark[i], &w->picture.Xmark[i], &w->picture.Ymark[i]);
6447 }
6448 w->picture.iMark = i + 1;
6449
6450 return 0;
6451 }
6452
6453 /*****************************************************************************/
6454 /* */
6455 /* Subroutine: add2historybuffer */
6456 /* Effect: record the (x,y) position of the cursor in the history buffer */
6457 /* */
6458 /*****************************************************************************/
add2historybuffer(XmPictureWidget w,int x,int y)6459 static int add2historybuffer(XmPictureWidget w, int x, int y)
6460 {
6461 /* Shuffle the points back */
6462 w->picture.pppx = w->picture.ppx;
6463 w->picture.pppy = w->picture.ppy;
6464
6465 w->picture.ppx = w->picture.px;
6466 w->picture.ppy = w->picture.py;
6467
6468 w->picture.px = x;
6469 w->picture.py = y;
6470 if (w->picture.K < 4) w->picture.K++;
6471
6472 return 0;
6473 }
6474
6475 /*****************************************************************************/
6476 /* */
6477 /* Subroutine: draw_marker */
6478 /* Effect: Draw the current markers */
6479 /* */
6480 /*****************************************************************************/
draw_marker(XmPictureWidget w)6481 int draw_marker ( XmPictureWidget w )
6482 {
6483
6484 int i;
6485 Display *dpy;
6486 Window dw;
6487 GC gc;
6488
6489 dpy = XtDisplay(w);
6490 if(!w->image.frame_buffer)
6491 {
6492 dw = XtWindow(w);
6493 gc = w->picture.gc;
6494 }
6495 else
6496 {
6497 dw = w->picture.overlay_wid;
6498 gc = w->picture.gcovl;
6499 }
6500
6501 for ( i = 0 ; i < w->picture.iMark ; i++ )
6502 {
6503 w->picture.pXmark[i] = w->picture.Xmark[i];
6504 w->picture.pYmark[i] = w->picture.Ymark[i];
6505 }
6506 w->picture.piMark = w->picture.iMark;
6507
6508
6509
6510 for ( i = 0 ; i < w->picture.iMark ; i++ )
6511 XCopyArea (dpy, w->picture.marker,
6512 dw, gc, 0, 0, 3, 3,
6513 (int)(w->picture.Xmark[i]) - 1,
6514 (int)(w->picture.Ymark[i]) - 1);
6515 XFlush(XtDisplay(w));
6516
6517 return 0;
6518 }
6519
6520 /* --------------- Geometry and rendering for globe rotation ---------- */
6521
6522 /*****************************************************************************/
6523 /* */
6524 /* Subroutine: generate_globe */
6525 /* Effect: generate x,y,z's for the facet verticies of the globe */
6526 /* */
6527 /*****************************************************************************/
6528 static void
generate_globe(XmPictureWidget w,double radi)6529 generate_globe ( XmPictureWidget w , double radi)
6530 {
6531 int i, j;
6532 struct point arc[ORBNUM];
6533 struct globe *globe;
6534 int screen;
6535 int depth;
6536
6537 radi += + w->core.width/15;
6538 globe = (struct globe *) XtCalloc(1, sizeof(struct globe));
6539
6540 globe->radi = radi;
6541 globe->circumference = M_PI*(radi + radi);
6542
6543 I44 ( globe->Wtrans );
6544
6545 /* make one half of an equator */
6546 for ( i = 0 ; i < ORBNUM ; i++ )
6547 {
6548 arc[i].xcoor = 0.0;
6549 arc[i].ycoor = globe->radi
6550 * cos(0.314 + (i * (M_PI - 0.624) / (double)(ORBNUM - 1 )) );
6551
6552 arc[i].zcoor = globe->radi
6553 * sin(0.314 + (i * (M_PI - 0.624) / (double)(ORBNUM - 1)) );
6554
6555 }
6556
6557 /* first generate the equators by rotating around Y axis */
6558 for ( i = 0 ; i < EQNUM ; i++ )
6559 {
6560 set_rot ( globe->Wtrans, M_PI * 2.0 / (double)(EQNUM) , Yaxis );
6561 for ( j = 0 ; j < ORBNUM ; j++ )
6562 {
6563 globe->equator[i][j].xcoor = (arc[j].xcoor *
6564 globe->Wtrans[0][Xaxis]) +
6565 (arc[j].ycoor *
6566 globe->Wtrans[1][Xaxis]) +
6567 (arc[j].zcoor *
6568 globe->Wtrans[2][Xaxis]) ;
6569
6570 globe->equator[i][j].ycoor = (arc[j].xcoor *
6571 globe->Wtrans[0][Yaxis]) +
6572 (arc[j].ycoor *
6573 globe->Wtrans[1][Yaxis]) +
6574 (arc[j].zcoor *
6575 globe->Wtrans[2][Yaxis]) ;
6576
6577 globe->equator[i][j].zcoor = (arc[j].xcoor *
6578 globe->Wtrans[0][Zaxis]) +
6579 (arc[j].ycoor *
6580 globe->Wtrans[1][Zaxis]) +
6581 (arc[j].zcoor *
6582 globe->Wtrans[2][Zaxis]) ;
6583 }
6584
6585 }
6586
6587 if (w->picture.globe)
6588 {
6589 for (i = 0; i < 4; i++)
6590 for (j = 0; j < 4; j++)
6591 globe->Wtrans[i][j] = w->picture.globe->Wtrans[i][j];
6592 globe->pixmap = w->picture.globe->pixmap;
6593 /* free(w->picture.globe); SHOULD be XtFree AJ */
6594 XtFree((char *)w->picture.globe);
6595 }
6596 w->picture.globe = globe;
6597
6598 w->picture.globe->x = 10;
6599 w->picture.globe->y = (int)((w->picture.PIXMAPHEIGHT -
6600 (2.0 * w->picture.globe->radi)) - 10);
6601 if (globe->pixmap)
6602 {
6603 XFreePixmap(XtDisplay(w), globe->pixmap);
6604 }
6605 screen = XScreenNumberOfScreen(XtScreen(w));
6606 if(!w->image.frame_buffer)
6607 depth = w->core.depth;
6608 else
6609 depth = 8;
6610 globe->pixmap = XCreatePixmap( XtDisplay(w),
6611 RootWindow(XtDisplay(w),screen),
6612 (int)w->picture.globe->radi*2,
6613 (int)w->picture.globe->radi*2,
6614 depth);
6615 }
6616
6617
6618 /*****************************************************************************/
6619 /* */
6620 /* Subroutine: XmDrawGlobe */
6621 /* Effect: */
6622 /* */
6623 /*****************************************************************************/
XmDrawGlobe(XmPictureWidget w)6624 static void XmDrawGlobe (XmPictureWidget w)
6625 {
6626
6627 int i,
6628 j,
6629 visible_orbit[EQNUM + 1];
6630 double x1,
6631 y1,
6632 x2,
6633 y2;
6634 XPoint arc[ORBNUM],
6635 orbit[EQNUM + 1];
6636 struct globe *globe;
6637 Display *dpy;
6638 Window dw;
6639 GC gc;
6640 Pixel white;
6641 Pixel black;
6642
6643 if(!w->picture.display_globe) return;
6644
6645 /*
6646 * Generate the globe on an as-needed basis instead of in the
6647 * realize method because the XtUnrealizeWidget call made by
6648 * MainWindow's window placment is causing us to lose track of
6649 * the 1st globe created.
6650 */
6651 if (!w->picture.globe) generate_globe(w, (double)w->picture.globe_radius);
6652 globe = w->picture.globe;
6653 dpy = XtDisplay(w);
6654 if(!w->image.frame_buffer)
6655 {
6656 gc = w->picture.gc;
6657 }
6658 else
6659 {
6660 gc = w->picture.gcovl;
6661 }
6662
6663 dw = globe->pixmap;
6664
6665 white = w->picture.white;
6666 black = w->picture.black;
6667
6668 /*
6669 * Erase the old globe by restoring the background image
6670 */
6671 if (!w->image.frame_buffer)
6672 {
6673 if (w->picture.pixmap != XmUNSPECIFIED_PIXMAP)
6674 {
6675 XCopyArea (dpy,
6676 w->picture.pixmap, globe->pixmap, w->picture.gc,
6677 (int)(w->picture.globe->x) ,
6678 (int)(w->picture.globe->y) ,
6679 (int)(2.0 * w->picture.globe->radi),
6680 (int)(2.0 * w->picture.globe->radi),
6681 (int)0,
6682 (int)0 );
6683 }
6684 else
6685 {
6686 XSetForeground( dpy, gc, black);
6687 XFillRectangle (dpy,
6688 globe->pixmap,
6689 gc,
6690 0 ,
6691 0 ,
6692 (int)(2.0 * w->picture.globe->radi),
6693 (int)(2.0 * w->picture.globe->radi));
6694 }
6695 }
6696 else if (w->image.frame_buffer)
6697 {
6698 XSetForeground(dpy, gc, white + 1);
6699 XFillRectangle (dpy,
6700 globe->pixmap,
6701 gc,
6702 (int)0,
6703 (int)0,
6704 (int)(2.0 * w->picture.globe->radi),
6705 (int)(2.0 * w->picture.globe->radi));
6706 }
6707 XSetForeground( dpy, gc, white);
6708
6709 /* let's first transform the equator and orbits */
6710
6711 for ( i = 0 ; i < EQNUM ; i++ )
6712 for ( j = 0 ; j < ORBNUM ; j++ )
6713 globe->visible[i][j] = False;
6714
6715 for ( i = 0 ; i < EQNUM ; i++ )
6716 for ( j = 0 ; j < ORBNUM ; j++ )
6717 {
6718 globe->tequator[i][j].xcoor = (globe->equator[i][j].xcoor *
6719 globe->Wtrans[0][Xaxis]) +
6720 (globe->equator[i][j].ycoor *
6721 globe->Wtrans[1][Xaxis]) +
6722 (globe->equator[i][j].zcoor *
6723 globe->Wtrans[2][Xaxis]) ;
6724
6725 globe->tequator[i][j].ycoor = (globe->equator[i][j].xcoor *
6726 globe->Wtrans[0][Yaxis]) +
6727 (globe->equator[i][j].ycoor *
6728 globe->Wtrans[1][Yaxis]) +
6729 (globe->equator[i][j].zcoor *
6730 globe->Wtrans[2][Yaxis]) ;
6731
6732 globe->tequator[i][j].zcoor = (globe->equator[i][j].xcoor *
6733 globe->Wtrans[0][Zaxis]) +
6734 (globe->equator[i][j].ycoor *
6735 globe->Wtrans[1][Zaxis]) +
6736 (globe->equator[i][j].zcoor *
6737 globe->Wtrans[2][Zaxis]) ;
6738 }
6739
6740 for ( i = 0 ; i < EQNUM ; i++ )
6741 for ( j = 0 ; j < ORBNUM ; j++ )
6742 if ( (j < (ORBNUM - 1)) && (i < (EQNUM - 1)) )
6743 {
6744 x2 = globe->tequator[i][j + 1].xcoor -
6745 globe->tequator[i][j].xcoor;
6746
6747 y2 = globe->tequator[i][j + 1].ycoor -
6748 globe->tequator[i][j].ycoor;
6749
6750 x1 = globe->tequator[i + 1][j].xcoor -
6751 globe->tequator[i][j].xcoor;
6752
6753 y1 = globe->tequator[i + 1][j].ycoor -
6754 globe->tequator[i][j].ycoor;
6755
6756 /* Cross Product in Z only */
6757 /* Negative Z ==> not visible */
6758 if ( ((x1 * y2) - (x2 * y1)) <= 0.0 )
6759 {
6760 globe->visible[i][j] = True;
6761 globe->visible[i + 1][j] = True;
6762 globe->visible[i][j + 1] = True;
6763 globe->visible[i + 1][j + 1] = True;
6764 }
6765
6766 }
6767
6768
6769
6770 /* Repeat where the two edges meet */
6771 for ( j = 0 ; j < ORBNUM - 1 ; j++)
6772 {
6773 x2 = globe->tequator[EQNUM - 1][j + 1].xcoor -
6774 globe->tequator[EQNUM - 1][j].xcoor;
6775
6776 y2 = globe->tequator[EQNUM - 1][j + 1].ycoor -
6777 globe->tequator[EQNUM - 1][j].ycoor;
6778
6779 x1 = globe->tequator[0][j].xcoor -
6780 globe->tequator[EQNUM - 1][j].xcoor;
6781
6782 y1 = globe->tequator[0][j].ycoor -
6783 globe->tequator[EQNUM - 1][j].ycoor;
6784
6785 if ( ((x1 * y2) - (x2 * y1)) <= 0.0 )
6786 {
6787 globe->visible[EQNUM - 1][j] = True;
6788 globe->visible[0][j] = True;
6789 globe->visible[EQNUM - 1][j + 1] = True;
6790 globe->visible[0][j + 1] = True;
6791 }
6792 }
6793
6794
6795 for ( i = 0 ; i < EQNUM ; i++ )
6796 {
6797 for ( j = 0 ; j < ORBNUM ; j++ )
6798 {
6799
6800 arc[j].x = (short)(globe->tequator[i][j].xcoor +
6801 w->picture.globe->radi);
6802 arc[j].y = (short)(globe->tequator[i][j].ycoor +
6803 w->picture.globe->radi);
6804
6805
6806 }
6807
6808
6809
6810 for (j = 0 ; j < ORBNUM - 1; j++ )
6811 if ((globe->visible[i][j] == True) &&
6812 (globe->visible[i][j + 1] == True) ) {
6813 XSetForeground( dpy, gc, black);
6814 XDrawLine ( dpy, dw, gc, arc[j].x-1, arc[j].y-1,
6815 arc[j + 1].x-1 , arc[j + 1].y-1 );
6816 XSetForeground( dpy, gc, white);
6817 XDrawLine ( dpy, dw, gc, arc[j].x, arc[j].y,
6818 arc[j + 1].x , arc[j + 1].y );
6819 }
6820 }
6821
6822 for ( i = 0 ; i < ORBNUM ; i++ )
6823 {
6824 for ( j = 0 ; j < EQNUM ; j++ )
6825 {
6826
6827
6828 orbit[j].x = (short)(globe->tequator[j][i].xcoor +
6829 w->picture.globe->radi);
6830 orbit[j].y = (short)(globe->tequator[j][i].ycoor +
6831 w->picture.globe->radi);
6832
6833
6834 if ( j == (EQNUM - 1) )
6835 {
6836 orbit[EQNUM].x = orbit[0].x;
6837 orbit[EQNUM].y = orbit[0].y;
6838 visible_orbit[EQNUM] = visible_orbit[0];
6839 }
6840 }
6841
6842 for (j = 0 ; j < EQNUM - 1 ; j++ )
6843 if ((globe->visible[j][i] == True) &&
6844 (globe->visible[j + 1][i] == True) ) {
6845 XSetForeground( dpy, gc, black);
6846 XDrawLine ( dpy, dw, gc, orbit[j].x-1, orbit[j].y-1,
6847 orbit[j + 1].x-1 , orbit[j + 1].y-1 );
6848 XSetForeground( dpy, gc, white);
6849 XDrawLine ( dpy, dw, gc, orbit[j].x, orbit[j].y,
6850 orbit[j + 1].x , orbit[j + 1].y );
6851 }
6852 if ((globe->visible[EQNUM - 1][i] == True) &&
6853 (globe->visible[0][i] == True) ) {
6854 XSetForeground( dpy, gc, black);
6855 XDrawLine ( dpy, dw, gc, orbit[0].x-1, orbit[0].y-1,
6856 orbit[EQNUM - 1].x-1 , orbit[EQNUM - 1].y-1 );
6857 XSetForeground( dpy, gc, white);
6858 XDrawLine ( dpy, dw, gc, orbit[0].x, orbit[0].y,
6859 orbit[EQNUM - 1].x , orbit[EQNUM - 1].y );
6860 }
6861
6862 } /* for */
6863
6864
6865 if(!w->image.frame_buffer)
6866 {
6867 dw = XtWindow(w);
6868 }
6869 else
6870 {
6871 dw = w->picture.overlay_wid;
6872 }
6873
6874 XCopyArea(XtDisplay(w), globe->pixmap, dw, gc, 0, 0,
6875 (int)w->picture.globe->radi*2, (int)w->picture.globe->radi*2,
6876 w->picture.globe->x, w->picture.globe->y);
6877 XFlush(dpy);
6878 }
6879
6880 /* Subroutine: calc_projected_axis
6881 * Purpose: For Cursor Mode 2 - calculate the angles of the projected
6882 * x, y, and x axes. The calculated angles represent the
6883 * angle off the screen X axis that is create while moving
6884 * along the associated axis in the positive direction
6885 */
calc_projected_axis(XmPictureWidget w)6886 static void calc_projected_axis(XmPictureWidget w)
6887 {
6888 double x1;
6889 double y1;
6890 double x2;
6891 double y2;
6892 double delta_x;
6893 double delta_y;
6894 double hyp_x;
6895 double hyp_y;
6896 double hyp_z;
6897 int i;
6898
6899 /* X axis */
6900 x1 = w->picture.Face2[0].sxcoor;
6901 y1 = w->picture.Face2[0].sycoor;
6902 x2 = w->picture.Face2[3].sxcoor;
6903 y2 = w->picture.Face2[3].sycoor;
6904 delta_x = x2 - x1;
6905 delta_y = y2 - y1;
6906 hyp_x = sqrt(delta_x*delta_x + delta_y*delta_y);
6907 if (hyp_x != 0)
6908 {
6909 w->picture.angle_posx = acos( delta_x/hyp_x);
6910 }
6911 else
6912 {
6913 w->picture.angle_posx = -100.0;
6914 }
6915 if( delta_y > 0 )
6916 {
6917 w->picture.angle_posx = 2*M_PI - w->picture.angle_posx;
6918 }
6919 if (w->picture.angle_posx < M_PI)
6920 {
6921 w->picture.angle_negx = w->picture.angle_posx + M_PI;
6922 }
6923 else
6924 {
6925 w->picture.angle_negx = w->picture.angle_posx - M_PI;
6926 }
6927
6928 /* Y axis */
6929 x1 = w->picture.Face2[0].sxcoor;
6930 y1 = w->picture.Face2[0].sycoor;
6931 x2 = w->picture.Face1[0].sxcoor;
6932 y2 = w->picture.Face1[0].sycoor;
6933 delta_x = x2 - x1;
6934 delta_y = y2 - y1;
6935 hyp_y = sqrt(delta_x*delta_x + delta_y*delta_y);
6936 if (hyp_y != 0)
6937 {
6938 w->picture.angle_posy = acos( delta_x/hyp_y);
6939 }
6940 else
6941 {
6942 w->picture.angle_posy = -100.0;
6943 }
6944 if( delta_y > 0 )
6945 {
6946 w->picture.angle_posy = 2*M_PI - w->picture.angle_posy;
6947 }
6948 if (w->picture.angle_posy < M_PI)
6949 {
6950 w->picture.angle_negy = w->picture.angle_posy + M_PI;
6951 }
6952 else
6953 {
6954 w->picture.angle_negy = w->picture.angle_posy - M_PI;
6955 }
6956
6957 /* Z axis */
6958 x1 = w->picture.Face2[0].sxcoor;
6959 y1 = w->picture.Face2[0].sycoor;
6960 x2 = w->picture.Face2[1].sxcoor;
6961 y2 = w->picture.Face2[1].sycoor;
6962 delta_x = x2 - x1;
6963 delta_y = y2 - y1;
6964 hyp_z = sqrt(delta_x*delta_x + delta_y*delta_y);
6965 if (hyp_z != 0)
6966 {
6967 w->picture.angle_posz = acos( delta_x/hyp_z);
6968 }
6969 else
6970 {
6971 w->picture.angle_posz = -100.0;
6972 }
6973 if( delta_y > 0 )
6974 {
6975 w->picture.angle_posz = 2*M_PI - w->picture.angle_posz;
6976 }
6977 if (w->picture.angle_posz < M_PI)
6978 {
6979 w->picture.angle_negz = w->picture.angle_posz + M_PI;
6980 }
6981 else
6982 {
6983 w->picture.angle_negz = w->picture.angle_posz - M_PI;
6984 }
6985
6986 /* Check to see if the projected axis have similar angles. If they are
6987 * very close, disable the one with the shortest projected length. Also,
6988 * disable movement along an axis if the length of the projected axis
6989 * is less than 10 pixels.
6990 */
6991 w->picture.x_movement_allowed = True;
6992 w->picture.y_movement_allowed = True;
6993 w->picture.z_movement_allowed = True;
6994
6995 if ( (fabs(w->picture.angle_posx - w->picture.angle_posy) < 0.2) ||
6996 (fabs(w->picture.angle_posx - w->picture.angle_negy) < 0.2) )
6997 {
6998 if ( hyp_x < hyp_y)
6999 {
7000 w->picture.x_movement_allowed = False;
7001 }
7002 else
7003 {
7004 w->picture.y_movement_allowed = False;
7005 }
7006 }
7007
7008 if ( (fabs(w->picture.angle_posx - w->picture.angle_posz) < 0.2) ||
7009 (fabs(w->picture.angle_posx - w->picture.angle_negz) < 0.2) )
7010 {
7011 if ( hyp_x < hyp_z)
7012 {
7013 w->picture.x_movement_allowed = False;
7014 }
7015 else
7016 {
7017 w->picture.z_movement_allowed = False;
7018 }
7019 }
7020
7021 if ( (fabs(w->picture.angle_posy - w->picture.angle_posz) < 0.2) ||
7022 (fabs(w->picture.angle_posy - w->picture.angle_negz) < 0.2) )
7023 {
7024 if ( hyp_y < hyp_z)
7025 {
7026 w->picture.y_movement_allowed = False;
7027 }
7028 else
7029 {
7030 w->picture.z_movement_allowed = False;
7031 }
7032 }
7033 if (hyp_x < 10)
7034 {
7035 w->picture.x_movement_allowed = False;
7036 }
7037 if (hyp_y < 10)
7038 {
7039 w->picture.y_movement_allowed = False;
7040 }
7041 if (hyp_z < 10)
7042 {
7043 w->picture.z_movement_allowed = False;
7044 }
7045
7046 for (i = 0; i < 4; i++)
7047 {
7048 if ((i == 0) || (i == 2))
7049 {
7050 if ( (w->picture.z_movement_allowed) &&
7051 ( (w->picture.constrain_cursor == XmCONSTRAIN_NONE) ||
7052 (w->picture.constrain_cursor == XmCONSTRAIN_Z) ) )
7053 {
7054 w->picture.box_line[i].greyed = False;
7055 w->picture.box_line[i+4].greyed = False;
7056 }
7057 else
7058 {
7059 w->picture.box_line[i].greyed = True;
7060 w->picture.box_line[i+4].greyed = True;
7061 }
7062 }
7063 else
7064 {
7065 if ( (w->picture.x_movement_allowed) &&
7066 ( (w->picture.constrain_cursor == XmCONSTRAIN_NONE) ||
7067 (w->picture.constrain_cursor == XmCONSTRAIN_X) ) )
7068 {
7069 w->picture.box_line[i].greyed = False;
7070 w->picture.box_line[i+4].greyed = False;
7071 }
7072 else
7073 {
7074 w->picture.box_line[i].greyed = True;
7075 w->picture.box_line[i+4].greyed = True;
7076 }
7077 }
7078 if ( (w->picture.y_movement_allowed) &&
7079 ( (w->picture.constrain_cursor == XmCONSTRAIN_NONE) ||
7080 (w->picture.constrain_cursor == XmCONSTRAIN_Y) ) )
7081 w->picture.box_line[i+8].greyed = False;
7082 else
7083 w->picture.box_line[i+8].greyed = True;
7084 }
7085
7086 }
7087
7088 /* Subroutine: setup_bounding_box
7089 * Purpose: Get the bounding box coordinates in canonical form
7090 * Note that Face1 and Face2 are parallel to the XZ plane
7091 *
7092 * The matrix Bw is assumed to be in the following format:
7093 *
7094 * Ux Uy Uz 0
7095 * Vx Vy Vz 0
7096 * Wx Wy Wz 0
7097 * Ox Oy Oz 1
7098 *
7099 * Where U, V and W are the endpoints of the axis of the bounding box
7100 * and O is the origin of the bounding box. To get the bounding box
7101 * in canonical form, it must be translated to the origin of the world
7102 * coordinate system. This is done by subtracting Ox, Oy and Oz from
7103 * the associated components of the other points.
7104 */
setup_bounding_box(XmPictureWidget w)7105 static void setup_bounding_box(XmPictureWidget w)
7106 {
7107 double x, y, z;
7108 double vdelta_x, vdelta_y, vdelta_z;
7109 double wdelta_x, wdelta_y, wdelta_z;
7110 double xmax, xmin, ymax, ymin, zmax, zmin;
7111 int i;
7112 int j;
7113 double xlen, ylen, zlen, maxlen;
7114 double cam_screen_x, cam_screen_y, cam_screen_z;
7115 double sod_width; /* S/D vis. a vis. Newman and Sproull */
7116 double sod_height; /* S/D vis. a vis. Newman and Sproull */
7117 double ho2; /* image_height/2 */
7118 double wo2; /* image_width/2 */
7119 double zscale;
7120 double new_x1, new_y1, new_z1;
7121 double new_x2, new_y2, new_z2;
7122
7123 w->picture.Zmax = -DBL_MAX;
7124 w->picture.Zmin = DBL_MAX;
7125 xmax = ymax = zmax = -DBL_MAX;
7126 xmin = ymin = zmin = DBL_MAX;
7127
7128 xmin = MIN(xmin, w->picture.basis.Bw[0][0]);
7129 xmin = MIN(xmin, w->picture.basis.Bw[1][0]);
7130 xmin = MIN(xmin, w->picture.basis.Bw[2][0]);
7131 xmin = MIN(xmin, w->picture.basis.Bw[3][0]);
7132
7133 ymin = MIN(ymin, w->picture.basis.Bw[0][1]);
7134 ymin = MIN(ymin, w->picture.basis.Bw[1][1]);
7135 ymin = MIN(ymin, w->picture.basis.Bw[2][1]);
7136 ymin = MIN(ymin, w->picture.basis.Bw[3][1]);
7137
7138 zmin = MIN(zmin, w->picture.basis.Bw[0][2]);
7139 zmin = MIN(zmin, w->picture.basis.Bw[1][2]);
7140 zmin = MIN(zmin, w->picture.basis.Bw[2][2]);
7141 zmin = MIN(zmin, w->picture.basis.Bw[3][2]);
7142
7143 xmax = MAX(xmax, w->picture.basis.Bw[0][0]);
7144 xmax = MAX(xmax, w->picture.basis.Bw[1][0]);
7145 xmax = MAX(xmax, w->picture.basis.Bw[2][0]);
7146 xmax = MAX(xmax, w->picture.basis.Bw[3][0]);
7147
7148 ymax = MAX(ymax, w->picture.basis.Bw[0][1]);
7149 ymax = MAX(ymax, w->picture.basis.Bw[1][1]);
7150 ymax = MAX(ymax, w->picture.basis.Bw[2][1]);
7151 ymax = MAX(ymax, w->picture.basis.Bw[3][1]);
7152
7153 zmax = MAX(zmax, w->picture.basis.Bw[0][2]);
7154 zmax = MAX(zmax, w->picture.basis.Bw[1][2]);
7155 zmax = MAX(zmax, w->picture.basis.Bw[2][2]);
7156 zmax = MAX(zmax, w->picture.basis.Bw[3][2]);
7157
7158 /*udelta_x = w->picture.basis.Bw[0][0] - w->picture.basis.Bw[3][0];*/
7159 /*udelta_y = w->picture.basis.Bw[0][1] - w->picture.basis.Bw[3][1];*/
7160 /*udelta_z = w->picture.basis.Bw[0][2] - w->picture.basis.Bw[3][2];*/
7161
7162 vdelta_x = w->picture.basis.Bw[1][0] - w->picture.basis.Bw[3][0];
7163 vdelta_y = w->picture.basis.Bw[1][1] - w->picture.basis.Bw[3][1];
7164 vdelta_z = w->picture.basis.Bw[1][2] - w->picture.basis.Bw[3][2];
7165
7166 wdelta_x = w->picture.basis.Bw[2][0] - w->picture.basis.Bw[3][0];
7167 wdelta_y = w->picture.basis.Bw[2][1] - w->picture.basis.Bw[3][1];
7168 wdelta_z = w->picture.basis.Bw[2][2] - w->picture.basis.Bw[3][2];
7169
7170 /*
7171 * U + V
7172 */
7173 xmin = MIN(xmin, w->picture.basis.Bw[0][0] + vdelta_x);
7174 xmax = MAX(xmax, w->picture.basis.Bw[0][0] + vdelta_x);
7175 ymin = MIN(ymin, w->picture.basis.Bw[0][1] + vdelta_y);
7176 ymax = MAX(ymax, w->picture.basis.Bw[0][1] + vdelta_y);
7177 zmin = MIN(zmin, w->picture.basis.Bw[0][2] + vdelta_z);
7178 zmax = MAX(zmax, w->picture.basis.Bw[0][2] + vdelta_z);
7179
7180 /*
7181 * U + W
7182 */
7183 xmin = MIN(xmin, w->picture.basis.Bw[0][0] + wdelta_x);
7184 xmax = MAX(xmax, w->picture.basis.Bw[0][0] + wdelta_x);
7185 ymin = MIN(ymin, w->picture.basis.Bw[0][1] + wdelta_y);
7186 ymax = MAX(ymax, w->picture.basis.Bw[0][1] + wdelta_y);
7187 zmin = MIN(zmin, w->picture.basis.Bw[0][2] + wdelta_z);
7188 zmax = MAX(zmax, w->picture.basis.Bw[0][2] + wdelta_z);
7189
7190 /*
7191 * V + W
7192 */
7193 xmin = MIN(xmin, w->picture.basis.Bw[1][0] + wdelta_x);
7194 xmax = MAX(xmax, w->picture.basis.Bw[1][0] + wdelta_x);
7195 ymin = MIN(ymin, w->picture.basis.Bw[1][1] + wdelta_y);
7196 ymax = MAX(ymax, w->picture.basis.Bw[1][1] + wdelta_y);
7197 zmin = MIN(zmin, w->picture.basis.Bw[1][2] + wdelta_z);
7198 zmax = MAX(zmax, w->picture.basis.Bw[1][2] + wdelta_z);
7199
7200 /*
7201 * U + V + W
7202 */
7203 xmin = MIN(xmin, w->picture.basis.Bw[0][0] + vdelta_x + wdelta_x);
7204 xmax = MAX(xmax, w->picture.basis.Bw[0][0] + vdelta_x + wdelta_x);
7205 ymin = MIN(ymin, w->picture.basis.Bw[0][1] + vdelta_y + wdelta_y);
7206 ymax = MAX(ymax, w->picture.basis.Bw[0][1] + vdelta_y + wdelta_y);
7207 zmin = MIN(zmin, w->picture.basis.Bw[0][2] + vdelta_z + wdelta_z);
7208 zmax = MAX(zmax, w->picture.basis.Bw[0][2] + vdelta_z + wdelta_z);
7209
7210 /*
7211 * Grow the bounding box to include the current set of cursors.
7212 */
7213 if (w->picture.mode == XmCURSOR_MODE)
7214 {
7215 for (i = 0; i < w->picture.n_cursors; i++)
7216 {
7217 xmin = MIN(xmin, w->picture.cxbuff[i]);
7218 xmax = MAX(xmax, w->picture.cxbuff[i]);
7219 ymin = MIN(ymin, w->picture.cybuff[i]);
7220 ymax = MAX(ymax, w->picture.cybuff[i]);
7221 zmin = MIN(zmin, w->picture.czbuff[i]);
7222 zmax = MAX(zmax, w->picture.czbuff[i]);
7223 }
7224 }
7225 else if (w->picture.mode == XmROAM_MODE)
7226 {
7227 xmin = MIN(xmin, w->picture.roam_cxbuff);
7228 xmax = MAX(xmax, w->picture.roam_cxbuff);
7229 ymin = MIN(ymin, w->picture.roam_cybuff);
7230 ymax = MAX(ymax, w->picture.roam_cybuff);
7231 zmin = MIN(zmin, w->picture.roam_czbuff);
7232 zmax = MAX(zmax, w->picture.roam_czbuff);
7233 }
7234
7235 /*
7236 * Handle 2D images by forcing a minimum value for each dimension
7237 */
7238 xlen = xmax - xmin;
7239 ylen = ymax - ymin;
7240 zlen = zmax - zmin;
7241 maxlen = MAX(xlen, ylen);
7242 maxlen = MAX(maxlen, zlen);
7243 if(maxlen == 0.0) XtWarning("Degenerate Bounding Box in Picture Widget");
7244
7245 if (xmin == xmax)
7246 {
7247 xmax = xmin + maxlen/2000;
7248 }
7249 if (ymin == ymax)
7250 {
7251 ymax = ymin + maxlen/2000;
7252 }
7253 if (zmin == zmax)
7254 {
7255 zmax = zmin + maxlen/2000;
7256 }
7257
7258 /*
7259 * Save the bounding box coords in cannonical form.
7260 */
7261 w->picture.FacetXmax = xmax - xmin;
7262 w->picture.FacetYmax = ymax - ymin;
7263 w->picture.FacetZmax = zmax - zmin;
7264
7265 w->picture.FacetXmin = 0.0;
7266 w->picture.FacetYmin = 0.0;
7267 w->picture.FacetZmin = 0.0;
7268
7269 w->picture.Face1[0].xcoor = 0.0;
7270 w->picture.Face1[0].ycoor = w->picture.FacetYmax;
7271 w->picture.Face1[0].zcoor = 0.0;
7272
7273 w->picture.Face1[1].xcoor = 0.0;
7274 w->picture.Face1[1].ycoor = w->picture.FacetYmax;
7275 w->picture.Face1[1].zcoor = w->picture.FacetZmax;
7276
7277 w->picture.Face1[2].xcoor = w->picture.FacetXmax;
7278 w->picture.Face1[2].ycoor = w->picture.FacetYmax;
7279 w->picture.Face1[2].zcoor = w->picture.FacetZmax;
7280
7281 w->picture.Face1[3].xcoor = w->picture.FacetXmax;
7282 w->picture.Face1[3].ycoor = w->picture.FacetYmax;
7283 w->picture.Face1[3].zcoor = 0.0;
7284
7285 w->picture.Face2[0].xcoor = 0.0;
7286 w->picture.Face2[0].ycoor = 0.0;
7287 w->picture.Face2[0].zcoor = 0.0;
7288
7289 w->picture.Face2[1].xcoor = 0.0;
7290 w->picture.Face2[1].ycoor = 0.0;
7291 w->picture.Face2[1].zcoor = w->picture.FacetZmax;
7292
7293 w->picture.Face2[2].xcoor = w->picture.FacetXmax;
7294 w->picture.Face2[2].ycoor = 0.0;
7295 w->picture.Face2[2].zcoor = w->picture.FacetZmax;
7296
7297 w->picture.Face2[3].xcoor = w->picture.FacetXmax;
7298 w->picture.Face2[3].ycoor = 0.0 ;
7299 w->picture.Face2[3].zcoor = 0.0;
7300
7301 /*
7302 * Save the origin of the bounding box for CallCursorCallbacks.
7303 */
7304 w->picture.Ox = xmin;
7305 w->picture.Oy = ymin;
7306 w->picture.Oz = zmin;
7307
7308
7309 /*
7310 * Build matrix for cannonical form transformations.
7311 */
7312 I44(w->picture.Wtrans);
7313
7314 /* Pre-concatonate the translation to canonical form */
7315 set_trans(w->picture.Wtrans, xmin, Xaxis);
7316 set_trans(w->picture.Wtrans, ymin, Yaxis);
7317 set_trans(w->picture.Wtrans, zmin, Zaxis);
7318
7319 mult44(w->picture.Wtrans, w->picture.PureWtrans);
7320
7321 inverse ( w->picture.Wtrans, w->picture.WItrans );
7322
7323 /* transform the canonical form into the SCREEN XYZ space */
7324 for ( i = 0 ; i < 4 ; i++ )
7325 {
7326 xform_coords( w->picture.Wtrans,
7327 w->picture.Face1[i].xcoor,
7328 w->picture.Face1[i].ycoor,
7329 w->picture.Face1[i].zcoor,
7330 &w->picture.Face1[i].txcoor,
7331 &w->picture.Face1[i].tycoor,
7332 &w->picture.Face1[i].tzcoor);
7333
7334 perspective_divide( w,
7335 w->picture.Face1[i].txcoor,
7336 w->picture.Face1[i].tycoor,
7337 w->picture.Face1[i].tzcoor,
7338 &w->picture.Face1[i].txcoor,
7339 &w->picture.Face1[i].tycoor);
7340
7341 w->picture.Face1[i].sxcoor = (int)(w->picture.Face1[i].txcoor);
7342 w->picture.Face1[i].sycoor = (int)(w->picture.Face1[i].tycoor);
7343
7344 if ( w->picture.Face1[i].tzcoor > w->picture.Zmax )
7345 {
7346 w->picture.Zmax = w->picture.Face1[i].tzcoor;
7347 }
7348 if ( w->picture.Face1[i].tzcoor < w->picture.Zmin )
7349 {
7350 w->picture.Zmin = w->picture.Face1[i].tzcoor;
7351 }
7352 }
7353
7354 for ( i = 0 ; i < 4 ; i++ )
7355 {
7356 xform_coords( w->picture.Wtrans,
7357 w->picture.Face2[i].xcoor,
7358 w->picture.Face2[i].ycoor,
7359 w->picture.Face2[i].zcoor,
7360 &w->picture.Face2[i].txcoor,
7361 &w->picture.Face2[i].tycoor,
7362 &w->picture.Face2[i].tzcoor);
7363
7364 perspective_divide( w,
7365 w->picture.Face2[i].txcoor,
7366 w->picture.Face2[i].tycoor,
7367 w->picture.Face2[i].tzcoor,
7368 &w->picture.Face2[i].txcoor,
7369 &w->picture.Face2[i].tycoor);
7370
7371 w->picture.Face2[i].sxcoor = (int)(w->picture.Face2[i].txcoor);
7372 w->picture.Face2[i].sycoor = (int)(w->picture.Face2[i].tycoor);
7373
7374 if ( w->picture.Face2[i].tzcoor > w->picture.Zmax )
7375 {
7376 w->picture.Zmax = w->picture.Face2[i].tzcoor;
7377 }
7378 if ( w->picture.Face2[i].tzcoor < w->picture.Zmin )
7379 {
7380 w->picture.Zmin = w->picture.Face2[i].tzcoor;
7381 }
7382 }
7383
7384 /* remove the hidden lines of the bounding box */
7385 /* Shoot a ray from the eye to a vertex. Use a z value that
7386 is slightly less than the vertex. Then, xform the point
7387 back into cannonical form. If the point is outside the box,
7388 then the vertex is visible */
7389 for ( i = 0 ; i < 4 ; i++ )
7390 {
7391
7392 /* see which vertex is visible */
7393 z = (double)(w->picture.Face1[i].tzcoor +
7394 ((w->picture.Zmax - w->picture.Zmin) / 5000.0));
7395 perspective_divide_inverse( w,
7396 w->picture.Face1[i].txcoor,
7397 w->picture.Face1[i].tycoor,
7398 z,
7399 &x,
7400 &y);
7401 xform_coords( w->picture.WItrans,
7402 x,
7403 y,
7404 z,
7405 &x, &y, &z);
7406
7407 if ( (x >= w->picture.FacetXmin) && (x <= w->picture.FacetXmax) &&
7408 (y >= w->picture.FacetYmin) && (y <= w->picture.FacetYmax) &&
7409 (z >= w->picture.FacetZmin) && (z <= w->picture.FacetZmax) )
7410 w->picture.Face1[i].visible = False;
7411 else
7412 w->picture.Face1[i].visible = True;
7413
7414 z = (double)(w->picture.Face2[i].tzcoor +
7415 ((w->picture.Zmax - w->picture.Zmin) / 5000.0));
7416
7417 perspective_divide_inverse( w,
7418 w->picture.Face2[i].txcoor,
7419 w->picture.Face2[i].tycoor,
7420 z,
7421 &x,
7422 &y);
7423 xform_coords( w->picture.WItrans,
7424 x,
7425 y,
7426 z,
7427 &x, &y, &z);
7428
7429 /* the x, y, z are now in the original coordinate system
7430 see if they are inside the box */
7431
7432 if ( (x >= w->picture.FacetXmin) && (x <= w->picture.FacetXmax) &&
7433 (y >= w->picture.FacetYmin) && (y <= w->picture.FacetYmax) &&
7434 (z >= w->picture.FacetZmin) && (z <= w->picture.FacetZmax) )
7435 w->picture.Face2[i].visible = False;
7436 else
7437 w->picture.Face2[i].visible = True;
7438 }
7439
7440 /* Clipping calcs. */
7441 /* transform the camera into 3D screen coords */
7442 xform_coords( w->picture.PureWtrans,
7443 w->picture.from_x,
7444 w->picture.from_y,
7445 w->picture.from_z,
7446 &cam_screen_x,
7447 &cam_screen_y,
7448 &cam_screen_z);
7449 /* S/D */
7450 sod_width = tan(M_PI*w->picture.view_angle/360.0);
7451 ho2 = (double)(w->picture.image_height)/2;
7452 wo2 = (double)(w->picture.image_width)/2;
7453 sod_height = sod_width*(ho2/wo2);
7454
7455 zscale = wo2/(sod_width*cam_screen_z);
7456 cam_screen_z *= zscale;
7457
7458 /*
7459 * Line array setup
7460 *
7461 * Line # Point1 Point2 Axis
7462 * --------------------------------------------
7463 * 0 Face1[0] Face1[1] Z
7464 * 1 Face1[1] Face1[2] X
7465 * 2 Face1[2] Face1[3] Z
7466 * 3 Face1[3] Face1[0] X
7467 *
7468 * 4 Face2[0] Face2[1] Z
7469 * 5 Face2[1] Face2[2] X
7470 * 6 Face2[2] Face2[3] Z
7471 * 7 Face2[3] Face2[0] X
7472 *
7473 * 8 Face1[0] Face2[0] Y
7474 * 9 Face1[1] Face2[1] Y
7475 * 10 Face1[2] Face2[2] Y
7476 * 11 Face1[3] Face2[3] Y
7477 */
7478
7479 for (i = 0; i < 4; i++)
7480 {
7481 xform_coords( w->picture.Wtrans,
7482 w->picture.Face1[i].xcoor,
7483 w->picture.Face1[i].ycoor,
7484 w->picture.Face1[i].zcoor,
7485 &w->picture.Face1[i].txcoor,
7486 &w->picture.Face1[i].tycoor,
7487 &w->picture.Face1[i].tzcoor);
7488 xform_coords( w->picture.Wtrans,
7489 w->picture.Face2[i].xcoor,
7490 w->picture.Face2[i].ycoor,
7491 w->picture.Face2[i].zcoor,
7492 &w->picture.Face2[i].txcoor,
7493 &w->picture.Face2[i].tycoor,
7494 &w->picture.Face2[i].tzcoor);
7495 w->picture.Face1[i].tzcoor = w->picture.Face1[i].tzcoor * zscale;
7496 w->picture.Face2[i].tzcoor = w->picture.Face2[i].tzcoor * zscale;
7497 }
7498
7499 /* 3D Screen coordinate system. The two diagonal lines are the top
7500 * and bottom of the viewing frustum. zdepth = (z - camera_z) is the
7501 * distance in z from the camera to the point in question.
7502
7503 \ y = image_height/2
7504 |\
7505 | \
7506 | \ y = -sod_height*(z - camera_z)
7507 | \
7508 |S \
7509 | \
7510 Z Axis | \
7511 ____________________|__D____\ camera z
7512 | /
7513 | /
7514 | /
7515 | /
7516 Y Axis | /y = sod_height*(z - camera_z)
7517 | /
7518 | /
7519 |/y = -image_height/2
7520 *
7521 */
7522
7523 for (i = 0; i < 4; i++)
7524 {
7525 j = (i+1)%4;
7526
7527 /*
7528 * Face1
7529 */
7530 w->picture.box_line[i].x1 = w->picture.Face1[i].sxcoor;
7531 w->picture.box_line[i].y1 = w->picture.Face1[i].sycoor;
7532 w->picture.box_line[i].x2 = w->picture.Face1[j].sxcoor;
7533 w->picture.box_line[i].y2 = w->picture.Face1[j].sycoor;
7534 if (w->picture.Face1[i].visible && w->picture.Face1[j].visible)
7535 w->picture.box_line[i].dotted = False;
7536 else
7537 w->picture.box_line[i].dotted = True;
7538
7539 w->picture.box_line[i].rejected =
7540 trivial_reject(w,
7541 w->picture.Face1[i].txcoor - wo2,
7542 w->picture.Face1[i].tycoor - ho2,
7543 w->picture.Face1[i].tzcoor - cam_screen_z,
7544 w->picture.Face1[j].txcoor - wo2,
7545 w->picture.Face1[j].tycoor - ho2,
7546 w->picture.Face1[j].tzcoor - cam_screen_z,
7547 sod_width, sod_height);
7548 if (!w->picture.box_line[i].rejected)
7549 {
7550 if (clip_line(w,
7551 w->picture.Face1[i].txcoor - wo2,
7552 w->picture.Face1[i].tycoor - ho2,
7553 w->picture.Face1[i].tzcoor - cam_screen_z,
7554 w->picture.Face1[j].txcoor - wo2,
7555 w->picture.Face1[j].tycoor - ho2,
7556 w->picture.Face1[j].tzcoor - cam_screen_z,
7557 sod_width, sod_height,
7558 &new_x1, &new_y1, &new_z1,
7559 &new_x2, &new_y2, &new_z2))
7560 {
7561 new_x1 += wo2; new_y1 += ho2; new_z1 += cam_screen_z;
7562 new_x2 += wo2; new_y2 += ho2; new_z2 += cam_screen_z;
7563 perspective_divide( w, new_x1, new_y1, new_z1/zscale, &x, &y);
7564 w->picture.box_line[i].x1 = x;
7565 w->picture.box_line[i].y1 = y;
7566 perspective_divide( w, new_x2, new_y2, new_z2/zscale, &x, &y);
7567 w->picture.box_line[i].x2 = x;
7568 w->picture.box_line[i].y2 = y;
7569 }
7570 }
7571 /*
7572 * Face2
7573 */
7574 w->picture.box_line[i+4].x1 = w->picture.Face2[i].sxcoor;
7575 w->picture.box_line[i+4].y1 = w->picture.Face2[i].sycoor;
7576 w->picture.box_line[i+4].x2 = w->picture.Face2[j].sxcoor;
7577 w->picture.box_line[i+4].y2 = w->picture.Face2[j].sycoor;
7578 if (w->picture.Face2[i].visible && w->picture.Face2[j].visible)
7579 w->picture.box_line[i+4].dotted = False;
7580 else
7581 w->picture.box_line[i+4].dotted = True;
7582
7583 w->picture.box_line[i+4].rejected =
7584 trivial_reject(w,
7585 w->picture.Face2[i].txcoor - wo2,
7586 w->picture.Face2[i].tycoor - ho2,
7587 w->picture.Face2[i].tzcoor - cam_screen_z,
7588 w->picture.Face2[j].txcoor - wo2,
7589 w->picture.Face2[j].tycoor - ho2,
7590 w->picture.Face2[j].tzcoor - cam_screen_z,
7591 sod_width, sod_height);
7592
7593 if (!w->picture.box_line[i+4].rejected)
7594 {
7595 if (clip_line(w,
7596 w->picture.Face2[i].txcoor - wo2,
7597 w->picture.Face2[i].tycoor - ho2,
7598 w->picture.Face2[i].tzcoor - cam_screen_z,
7599 w->picture.Face2[j].txcoor - wo2,
7600 w->picture.Face2[j].tycoor - ho2,
7601 w->picture.Face2[j].tzcoor - cam_screen_z,
7602 sod_width, sod_height,
7603 &new_x1, &new_y1, &new_z1,
7604 &new_x2, &new_y2, &new_z2))
7605 {
7606 new_x1 += wo2; new_y1 += ho2; new_z1 += cam_screen_z;
7607 new_x2 += wo2; new_y2 += ho2; new_z2 += cam_screen_z;
7608 perspective_divide( w, new_x1, new_y1, new_z1/zscale, &x, &y);
7609 w->picture.box_line[i+4].x1 = x;
7610 w->picture.box_line[i+4].y1 = y;
7611 perspective_divide( w, new_x2, new_y2, new_z2/zscale, &x, &y);
7612 w->picture.box_line[i+4].x2 = x;
7613 w->picture.box_line[i+4].y2 = y;
7614 }
7615 }
7616 /*
7617 * Face1 - Face2
7618 */
7619 w->picture.box_line[i+8].x1 = w->picture.Face1[i].sxcoor;
7620 w->picture.box_line[i+8].y1 = w->picture.Face1[i].sycoor;
7621 w->picture.box_line[i+8].x2 = w->picture.Face2[i].sxcoor;
7622 w->picture.box_line[i+8].y2 = w->picture.Face2[i].sycoor;
7623 if (w->picture.Face1[i].visible && w->picture.Face2[i].visible)
7624 w->picture.box_line[i+8].dotted = False;
7625 else
7626 w->picture.box_line[i+8].dotted = True;
7627
7628 w->picture.box_line[i+8].rejected =
7629 trivial_reject(w,
7630 w->picture.Face1[i].txcoor - wo2,
7631 w->picture.Face1[i].tycoor - ho2,
7632 w->picture.Face1[i].tzcoor - cam_screen_z,
7633 w->picture.Face2[i].txcoor - wo2,
7634 w->picture.Face2[i].tycoor - ho2,
7635 w->picture.Face2[i].tzcoor - cam_screen_z,
7636 sod_width, sod_height);
7637 if (!w->picture.box_line[i+8].rejected)
7638 {
7639 if (clip_line(w,
7640 w->picture.Face1[i].txcoor - wo2,
7641 w->picture.Face1[i].tycoor - ho2,
7642 w->picture.Face1[i].tzcoor - cam_screen_z,
7643 w->picture.Face2[i].txcoor - wo2,
7644 w->picture.Face2[i].tycoor - ho2,
7645 w->picture.Face2[i].tzcoor - cam_screen_z,
7646 sod_width, sod_height,
7647 &new_x1, &new_y1, &new_z1,
7648 &new_x2, &new_y2, &new_z2))
7649 {
7650 new_x1 += wo2; new_y1 += ho2; new_z1 += cam_screen_z;
7651 new_x2 += wo2; new_y2 += ho2; new_z2 += cam_screen_z;
7652 perspective_divide( w, new_x1, new_y1, new_z1/zscale, &x, &y);
7653 w->picture.box_line[i+8].x1 = x;
7654 w->picture.box_line[i+8].y1 = y;
7655 perspective_divide( w, new_x2, new_y2, new_z2/zscale, &x, &y);
7656 w->picture.box_line[i+8].x2 = x;
7657 w->picture.box_line[i+8].y2 = y;
7658 }
7659 }
7660 }
7661 }
7662
7663 /*****************************************************************************/
7664 /* */
7665 /* Subroutine: clip_line */
7666 /* Effect: clip the line segment to the viewing frustum */
7667 /*****************************************************************************/
clip_line(XmPictureWidget w,double x1,double y1,double z1,double x2,double y2,double z2,double sod_width,double sod_height,double * new_x1,double * new_y1,double * new_z1,double * new_x2,double * new_y2,double * new_z2)7668 static Boolean clip_line(XmPictureWidget w,
7669 double x1, double y1, double z1,
7670 double x2, double y2, double z2,
7671 double sod_width, double sod_height,
7672 double *new_x1, double *new_y1, double *new_z1,
7673 double *new_x2, double *new_y2, double *new_z2)
7674 {
7675 Boolean clipped = False;
7676 Boolean y1_above;
7677 Boolean y2_above;
7678 Boolean x1_left;
7679 Boolean x2_left;
7680 Boolean y1_below;
7681 Boolean y2_below;
7682 Boolean x1_right;
7683 Boolean x2_right;
7684 double m;
7685 double b;
7686 double new_x;
7687 double new_y;
7688 double new_z;
7689 double old_length_x;
7690 double old_length_y;
7691 double old_length_z=0;
7692 double new_length_x;
7693 double new_length_y;
7694 double new_length_z;
7695
7696 /*
7697 * No clipping in orthographic projections.
7698 */
7699 if (w->picture.projection == 0) return False;
7700
7701 /*
7702 * No need to clip if we are looking straight down the z axis
7703 */
7704 if(z1 == z2) return False;
7705
7706 /*
7707 * If both points are inside the of the viewing frustum,
7708 * the line is trivially accepted.
7709 */
7710 if ( ((y1 <= -sod_height * z1) && (y2 <= -sod_height * z2)) &&
7711 ((y1 >= sod_height * z1) && (y2 >= sod_height * z2)) &&
7712 ((x1 <= -sod_width * z1) && (x2 <= -sod_width * z2)) &&
7713 ((x1 >= sod_width * z1) && (x2 >= sod_width * z2)) )
7714 {
7715 return False;
7716 }
7717
7718 /*
7719 * If we get here, the line has not been trivially accepted or rejected.
7720 */
7721 y1_below = (y1 < sod_height * z1);
7722 y2_below = (y2 < sod_height * z2);
7723 y1_above = (y1 > -sod_height * z1);
7724 y2_above = (y2 > -sod_height * z2);
7725
7726 /*
7727 * Equation of the line segment --> y = m*z +b where b = y1 - m*z1
7728 */
7729 m = (y1 - y2)/(z1 - z2);
7730 b = y1 - m*z1;
7731
7732 /*
7733 * If the y value of a point is both above and below the viewing frustum,
7734 * it is behind the camera. In order to clip the point to the proper
7735 * plane, look at the y intercept. If it is greater than zero, clip
7736 * to the "above" plane, else clip to the "below" plane.
7737 */
7738 if (y1_above && y1_below)
7739 {
7740 if (b > 0.0) y1_below = False;
7741 if (b < 0.0) y1_above = False;
7742 }
7743 if (y2_above && y2_below)
7744 {
7745 if (b > 0.0) y2_below = False;
7746 if (b < 0.0) y2_above = False;
7747 }
7748 if ( (y1_above && !y2_above) || (!y1_above && y2_above) )
7749 {
7750 new_z = -b/(m + sod_height);
7751 new_y = m*new_z + b;
7752 old_length_y = y2 - y1;
7753 /*
7754 * If the old y length is 0.0, use z to recalc the clipped x.
7755 */
7756 if(old_length_y == 0.0)
7757 old_length_z = z2 - z1;
7758 old_length_x = x2 - x1;
7759 if (y1_above)
7760 {
7761 y1 = new_y; z1 = new_z;
7762 if(old_length_y != 0.0)
7763 {
7764 new_length_y = y2 - y1;
7765 x1 = x2 - old_length_x*(new_length_y/old_length_y);
7766 }
7767 else
7768 {
7769 new_length_z = z2 - z1;
7770 x1 = x2 - old_length_x*(new_length_z/old_length_z);
7771 }
7772 }
7773 else
7774 {
7775 y2 = new_y; z2 = new_z;
7776 if(old_length_y != 0.0)
7777 {
7778 new_length_y = y2 - y1;
7779 x2 = x1 + old_length_x*(new_length_y/old_length_y);
7780 }
7781 else
7782 {
7783 new_length_z = z2 - z1;
7784 x2 = x1 + old_length_x*(new_length_z/old_length_z);
7785 }
7786 }
7787 clipped = True;
7788 }
7789 if ( (y1_below && !y2_below) || (!y1_below && y2_below) )
7790 {
7791 new_z = b/(sod_height - m);
7792 new_y = m*new_z + b;
7793 old_length_y = y2 - y1;
7794 /*
7795 * If the old y length is 0.0, use z to recalc the clipped x.
7796 */
7797 if(old_length_y == 0.0)
7798 old_length_z = z2 - z1;
7799 old_length_x = x2 - x1;
7800 if (y1_below)
7801 {
7802 y1 = new_y; z1 = new_z;
7803 if(old_length_y != 0.0)
7804 {
7805 new_length_y = y2 - y1;
7806 x1 = x2 - old_length_x*(new_length_y/old_length_y);
7807 }
7808 else
7809 {
7810 new_length_z = z2 - z1;
7811 x1 = x2 - old_length_x*(new_length_z/old_length_z);
7812 }
7813 }
7814 else
7815 {
7816 y2 = new_y; z2 = new_z;
7817 if(old_length_y != 0.0)
7818 {
7819 new_length_y = y2 - y1;
7820 x2 = x1 + old_length_x*(new_length_y/old_length_y);
7821 }
7822 else
7823 {
7824 new_length_z = z2 - z1;
7825 x2 = x1 + old_length_x*(new_length_z/old_length_z);
7826 }
7827 }
7828 clipped = True;
7829 }
7830
7831 x1_left = (x1 < sod_width * z1);
7832 x2_left = (x2 < sod_width * z2);
7833 x1_right = (x1 > -sod_width * z1);
7834 x2_right = (x2 > -sod_width * z2);
7835
7836 /*
7837 * Equation of the line segment --> x = m*z +b where b = x1 - m*z1
7838 */
7839 m = (x1 - x2)/(z1 - z2);
7840 b = x1 - m*z1;
7841
7842 /*
7843 * If the x value of a point is both to the left and right of the viewing
7844 *frustum, it is behind the camera. In order to clip the point to the
7845 * proper plane, look at the x intercept. If it is greater than zero, clip
7846 * to the "left" plane, else clip to the "right" plane.
7847 */
7848 if (x1_left && x1_right)
7849 {
7850 if (b > 0.0) x1_right = False;
7851 if (b < 0.0) x1_left = False;
7852 }
7853 if (x2_left && x2_right)
7854 {
7855 if (b > 0.0) x2_right = False;
7856 if (b < 0.0) x2_left = False;
7857 }
7858 if ( (x1_left && !x2_left) || (!x1_left && x2_left) )
7859 {
7860 new_z = b/(sod_width - m);
7861 new_x = m*new_z + b;
7862 old_length_y = y2 - y1;
7863 old_length_x = x2 - x1;
7864 /*
7865 * If the old x length is 0.0, use z to recalc the clipped y.
7866 */
7867 if(old_length_x == 0.0)
7868 old_length_z = z2 - z1;
7869 if (x1_left)
7870 {
7871 x1 = new_x; z1 = new_z;
7872 if(old_length_x != 0.0)
7873 {
7874 new_length_x = x2 - x1;
7875 y1 = y2 - old_length_y * (new_length_x / old_length_x);
7876 }
7877 else
7878 {
7879 new_length_z = z2 - z1;
7880 y1 = y2 - old_length_y * (new_length_z / old_length_z);
7881 }
7882 }
7883 else
7884 {
7885 x2 = new_x; z2 = new_z;
7886 if(old_length_x != 0.0)
7887 {
7888 new_length_x = x2 - x1;
7889 y2 = y1 + old_length_y * (new_length_x / old_length_x);
7890 }
7891 else
7892 {
7893 new_length_z = z2 - z1;
7894 y2 = y1 + old_length_y * (new_length_z / old_length_z);
7895 }
7896 }
7897 clipped = True;
7898 }
7899 if ( (x1_right && !x2_right) || (!x1_right && x2_right) )
7900 {
7901 new_z = -b/(m + sod_width);
7902 new_x = m*new_z + b;
7903 old_length_y = y2 - y1;
7904 old_length_x = x2 - x1;
7905 /*
7906 * If the old x length is 0.0, use z to recalc the clipped y.
7907 */
7908 if(old_length_x == 0.0)
7909 old_length_z = z2 - z1;
7910 if (x1_right)
7911 {
7912 x1 = new_x; z1 = new_z;
7913 if(old_length_x != 0.0)
7914 {
7915 new_length_x = x2 - x1;
7916 y1 = y2 - old_length_y * (new_length_x / old_length_x);
7917 }
7918 else
7919 {
7920 new_length_z = z2 - z1;
7921 y1 = y2 - old_length_y * (new_length_z / old_length_z);
7922 }
7923 }
7924 else
7925 {
7926 x2 = new_x; z2 = new_z;
7927 if(old_length_x != 0.0)
7928 {
7929 new_length_x = x2 - x1;
7930 y2 = y1 + old_length_y * (new_length_x / old_length_x);
7931 }
7932 else
7933 {
7934 new_length_z = z2 - z1;
7935 y2 = y1 + old_length_y * (new_length_z / old_length_z);
7936 }
7937 }
7938 clipped = True;
7939 }
7940
7941 *new_x1 = x1; *new_y1 = y1; *new_z1 = z1;
7942 *new_x2 = x2; *new_y2 = y2; *new_z2 = z2;
7943
7944 return clipped;
7945 }
7946 /*****************************************************************************/
7947 /* */
7948 /* Subroutine: trivial_reject */
7949 /* Effect: See if the line is completely outside the viewing frustum */
7950 /*****************************************************************************/
trivial_reject(XmPictureWidget w,double x1,double y1,double z1,double x2,double y2,double z2,double sod_width,double sod_height)7951 static Boolean trivial_reject(XmPictureWidget w,
7952 double x1, double y1, double z1,
7953 double x2, double y2, double z2,
7954 double sod_width, double sod_height)
7955 {
7956
7957 /*
7958 * No clipping in orthographic projections.
7959 */
7960 if (w->picture.projection == 0) return False;
7961
7962 /*
7963 * If both points are behind the camera, the line is trivially rejected.
7964 */
7965 if ( (z1 > 0.0) && (z2 > 0.0) )
7966 {
7967 return True;
7968 }
7969
7970 /*
7971 * If both points are outside the same plane of the viewing frustum,
7972 * the line is trivially rejected.
7973 */
7974 if ( ((y1 >= -sod_height * z1) && (y2 >= -sod_height * z2)) ||
7975 ((y1 <= sod_height * z1) && (y2 <= sod_height * z2)) ||
7976 ((x1 >= -sod_width * z1) && (x2 >= -sod_width * z2)) ||
7977 ((x1 <= sod_width * z1) && (x2 <= sod_width * z2)) )
7978 {
7979 return True;
7980 }
7981
7982 return False;
7983 }
7984 /*****************************************************************************/
7985 /* */
7986 /* Subroutine: setup_gnomon */
7987 /* Effect: Calculate the screen coords of the gnomon (to be drawn later) */
7988 /*****************************************************************************/
setup_gnomon(XmPictureWidget w,Boolean rotate)7989 static void setup_gnomon(XmPictureWidget w, Boolean rotate)
7990 {
7991 double angle;
7992 double delta_x;
7993 double delta_y;
7994 double length;
7995
7996 double origin_sxcoor;
7997 double origin_sycoor;
7998 double origin_szcoor;
7999 double xaxis_sxcoor;
8000 double xaxis_sycoor;
8001 double xaxis_szcoor;
8002 double yaxis_sxcoor;
8003 double yaxis_sycoor;
8004 double yaxis_szcoor;
8005 double zaxis_sxcoor;
8006 double zaxis_sycoor;
8007 double zaxis_szcoor;
8008
8009 double xaxis_length;
8010 double yaxis_length;
8011 double zaxis_length;
8012 double total_length;
8013 int direction;
8014 int ascent;
8015 int descent;
8016 XCharStruct overall;
8017 char string[10];
8018 int origin_offset_x;
8019 int origin_offset_y;
8020
8021 if (!w->picture.camera_defined) return;
8022 string[0] = 'Z';
8023 string[1] = '\0';
8024 XTextExtents(w->picture.font, string, 1,
8025 &direction, &ascent, &descent, &overall);
8026
8027 /*
8028 * Set up gnomon
8029 */
8030 if (rotate)
8031 {
8032 xform_coords( w->picture.globe->Wtrans,
8033 0.0, 0.0, 0.0,
8034 &origin_sxcoor, &origin_sycoor, &origin_szcoor);
8035
8036 xform_coords( w->picture.globe->Wtrans,
8037 1.0, 0.0, 0.0,
8038 &xaxis_sxcoor, &xaxis_sycoor, &xaxis_szcoor);
8039
8040 xform_coords( w->picture.globe->Wtrans,
8041 0.0, -1.0, 0.0,
8042 &yaxis_sxcoor, &yaxis_sycoor, &yaxis_szcoor);
8043
8044 xform_coords( w->picture.globe->Wtrans,
8045 0.0, 0.0, 1.0,
8046 &zaxis_sxcoor, &zaxis_sycoor, &zaxis_szcoor);
8047 }
8048 else
8049 {
8050 xform_coords( w->picture.PureWtrans,
8051 0.0, 0.0, 0.0,
8052 &origin_sxcoor, &origin_sycoor, &origin_szcoor);
8053
8054 xform_coords( w->picture.PureWtrans,
8055 1.0, 0.0, 0.0,
8056 &xaxis_sxcoor, &xaxis_sycoor, &xaxis_szcoor);
8057
8058 xform_coords( w->picture.PureWtrans,
8059 0.0, 1.0, 0.0,
8060 &yaxis_sxcoor, &yaxis_sycoor, &yaxis_szcoor);
8061
8062 xform_coords( w->picture.PureWtrans,
8063 0.0, 0.0, 1.0,
8064 &zaxis_sxcoor, &zaxis_sycoor, &zaxis_szcoor);
8065 }
8066
8067 xaxis_length = sqrt( (xaxis_sxcoor-origin_sxcoor) *
8068 (xaxis_sxcoor-origin_sxcoor) +
8069 (xaxis_sycoor-origin_sycoor) *
8070 (xaxis_sycoor-origin_sycoor) );
8071 yaxis_length = sqrt( (yaxis_sxcoor-origin_sxcoor) *
8072 (yaxis_sxcoor-origin_sxcoor) +
8073 (yaxis_sycoor-origin_sycoor) *
8074 (yaxis_sycoor-origin_sycoor) );
8075 zaxis_length = sqrt( (zaxis_sxcoor-origin_sxcoor) *
8076 (zaxis_sxcoor-origin_sxcoor) +
8077 (zaxis_sycoor-origin_sycoor) *
8078 (zaxis_sycoor-origin_sycoor) );
8079
8080 total_length = xaxis_length + yaxis_length + zaxis_length;
8081
8082 origin_offset_x = (w->core.width - 60) - origin_sxcoor;
8083 origin_offset_y = (w->core.height - 60) - origin_sycoor;
8084
8085 /*
8086 * Calc the projected X axis
8087 */
8088 length = 80 * (xaxis_length/total_length);
8089 if (xaxis_length > 0)
8090 {
8091 angle = acos((xaxis_sxcoor - origin_sxcoor)/xaxis_length);
8092 }
8093 else
8094 {
8095 angle = 0.0;
8096 }
8097 if (xaxis_sycoor > origin_sycoor) angle = 2*M_PI - angle;
8098 delta_x = length * cos(angle);
8099 delta_y = -length * sin(angle);
8100
8101 w->picture.gnomon_center_x = origin_sxcoor + origin_offset_x;
8102 w->picture.gnomon_center_y = origin_sycoor + origin_offset_y;
8103 w->picture.gnomon_xaxis_x = w->picture.gnomon_center_x + delta_x;
8104 w->picture.gnomon_xaxis_y = w->picture.gnomon_center_y + delta_y;
8105
8106 /*
8107 * Calc the placement of the gnomon label
8108 */
8109 length = length + 5;
8110 delta_x = length * cos(angle);
8111 delta_y = -length * sin(angle);
8112 w->picture.gnomon_xaxis_label_x = w->picture.gnomon_center_x + delta_x;
8113 w->picture.gnomon_xaxis_label_y = w->picture.gnomon_center_y + delta_y;
8114 if (delta_x < 0) w->picture.gnomon_xaxis_label_x -= overall.width;
8115 if (delta_y > 0) w->picture.gnomon_xaxis_label_y += (ascent+descent);
8116
8117 /*
8118 * Calc the projected Y axis
8119 */
8120 length = 80 * (yaxis_length/total_length);
8121 if (yaxis_length > 0)
8122 {
8123 angle = acos((yaxis_sxcoor - origin_sxcoor)/yaxis_length);
8124 }
8125 else
8126 {
8127 angle = 0.0;
8128 }
8129 if (yaxis_sycoor > origin_sycoor) angle = 2*M_PI - angle;
8130 delta_x = length * cos(angle);
8131 delta_y = -length * sin(angle);
8132 w->picture.gnomon_yaxis_x = w->picture.gnomon_center_x + delta_x;
8133 w->picture.gnomon_yaxis_y = w->picture.gnomon_center_y + delta_y;
8134
8135 /*
8136 * Calc the placement of the gnomon label
8137 */
8138 length = length + 5;
8139 delta_x = length * cos(angle);
8140 delta_y = -length * sin(angle);
8141 w->picture.gnomon_yaxis_label_x = w->picture.gnomon_center_x + delta_x;
8142 w->picture.gnomon_yaxis_label_y = w->picture.gnomon_center_y + delta_y;
8143 if (delta_x < 0) w->picture.gnomon_yaxis_label_x -= overall.width;
8144 if (delta_y > 0) w->picture.gnomon_yaxis_label_y += (ascent+descent);
8145
8146 /*
8147 * Calc the projected Z axis
8148 */
8149 length = 80 * (zaxis_length/total_length);
8150 if (zaxis_length > 0)
8151 {
8152 angle = acos((zaxis_sxcoor - origin_sxcoor)/zaxis_length);
8153 }
8154 else
8155 {
8156 angle = 0.0;
8157 }
8158 if (zaxis_sycoor > origin_sycoor) angle = 2*M_PI - angle;
8159 delta_x = length * cos(angle);
8160 delta_y = -length * sin(angle);
8161 w->picture.gnomon_zaxis_x = w->picture.gnomon_center_x + delta_x;
8162 w->picture.gnomon_zaxis_y = w->picture.gnomon_center_y + delta_y;
8163
8164 /*
8165 * Calc the placement of the gnomon label
8166 */
8167 length = length + 5;
8168 delta_x = length * cos(angle);
8169 delta_y = -length * sin(angle);
8170 w->picture.gnomon_zaxis_label_x = w->picture.gnomon_center_x + delta_x;
8171 w->picture.gnomon_zaxis_label_y = w->picture.gnomon_center_y + delta_y;
8172 if (delta_x < 0) w->picture.gnomon_zaxis_label_x -= overall.width;
8173 if (delta_y > 0) w->picture.gnomon_zaxis_label_y += (ascent+descent);
8174
8175 }
8176
8177
8178
8179 /*****************************************************************************/
8180 /* */
8181 /* Subroutine: CallCursorCallbacks */
8182 /* Effect: xform screen x,y,z back to world coords and callback */
8183 /* application. */
8184 /*****************************************************************************/
CallCursorCallbacks(XmPictureWidget w,int reason,int cursor_num,double screen_x,double screen_y,double screen_z)8185 static void CallCursorCallbacks(XmPictureWidget w, int reason, int cursor_num,
8186 double screen_x, double screen_y, double screen_z)
8187 {
8188 XmPictureCallbackStruct cb;
8189 char text[256];
8190 Arg wargs[20];
8191 XmString xmstring;
8192 int height;
8193 int dest_x;
8194 int dest_y;
8195 Widget child;
8196
8197 cb.reason = reason;
8198 cb.cursor_num = cursor_num;
8199
8200 if (w->picture.mode == XmPICK_MODE)
8201 {
8202 cb.x = screen_x;
8203 cb.y = w->core.height - screen_y;
8204 XtCallCallbacks ((Widget)w, XmNpickCallback, &cb);
8205 return;
8206 }
8207 perspective_divide_inverse(w, screen_x, screen_y, screen_z,
8208 &screen_x, &screen_y);
8209 xform_coords( w->picture.WItrans, screen_x, screen_y, screen_z,
8210 &cb.x, &cb.y, &cb.z);
8211
8212 /*
8213 * Correct for the fact that we have xformed back to cannonical coords.
8214 */
8215 cb.x += w->picture.Ox;
8216 cb.y += w->picture.Oy;
8217 cb.z += w->picture.Oz;
8218
8219 sprintf(text, "( %8g, %8g, %8g )", cb.x, cb.y, cb.z);
8220 if ( (reason == XmPCR_CREATE) ||
8221 (reason == XmPCR_SELECT) )
8222 {
8223 xmstring = XmStringCreate(text, XmSTRING_DEFAULT_CHARSET);
8224 XtSetArg(wargs[0], XmNlabelString, xmstring);
8225 XtSetValues((Widget)w->picture.pb, wargs, 1);
8226
8227 /*
8228 * Find a good place to put the popup.
8229 */
8230 XTranslateCoordinates
8231 (XtDisplay(w),
8232 XtWindow(w),
8233 XRootWindowOfScreen(XtScreen(w)),
8234 w->core.width - 350,
8235 -35,
8236 &dest_x,
8237 &dest_y,
8238 (Window*)&child);
8239 XtMoveWidget(w->picture.popup,
8240 dest_x,
8241 dest_y);
8242 XtPopup(w->picture.popup, XtGrabNone);
8243 w->picture.popped_up = True;
8244 XmStringFree(xmstring);
8245 }
8246 if ( (reason == XmPCR_DELETE) ||
8247 (reason == XmPCR_MOVE) )
8248 {
8249 XtPopdown(w->picture.popup);
8250 w->picture.popped_up = False;
8251 }
8252 if (XtIsRealized((Widget)w->picture.pb))
8253 {
8254 XClearArea( XtDisplay(w),
8255 XtWindow(w->picture.pb),
8256 w->picture.pb->primitive.shadow_thickness,
8257 w->picture.pb->primitive.shadow_thickness,
8258 w->picture.pb->core.width -
8259 2*w->picture.pb->primitive.shadow_thickness,
8260 w->picture.pb->core.height -
8261 2*w->picture.pb->primitive.shadow_thickness,
8262 False);
8263 height = (w->picture.pb->core.height +
8264 (w->picture.font->descent + w->picture.font->ascent))/2 - 3;
8265 XDrawString(XtDisplay(w),
8266 XtWindow(w->picture.pb),
8267 w->picture.fontgc,
8268 10,
8269 height,
8270 text,
8271 text != NULL? strlen(text): 0);
8272 }
8273 XFlush(XtDisplay(w));
8274
8275 if (w->picture.mode == XmCURSOR_MODE)
8276 {
8277 XtCallCallbacks ((Widget)w, XmNcursorCallback, &cb);
8278 }
8279 else if (w->picture.mode == XmROAM_MODE)
8280 {
8281 /*
8282 * Save the current camera in case the user wants to undo this
8283 * interaction, if this is a "Move".
8284 */
8285 if (reason == XmPCR_MOVE)
8286 {
8287 push_undo_camera(w);
8288 XtCallCallbacks ((Widget)w, XmNroamCallback, &cb);
8289 }
8290 if (reason == XmPCR_MOVE)
8291 {
8292 w->picture.disable_temp = True;
8293 }
8294 }
8295 }
8296 /*****************************************************************************/
8297 /* */
8298 /* Subroutine: CallNavigateCallbacks */
8299 /* Effect: */
8300 /*****************************************************************************/
CallNavigateCallbacks(XmPictureWidget w,int screen_x,int screen_y,int reason)8301 static void CallNavigateCallbacks(XmPictureWidget w,
8302 int screen_x, int screen_y, int reason)
8303 {
8304 XmPictureCallbackStruct cb;
8305 double dx;
8306 double dy;
8307 double dz;
8308 double length;
8309 double orig_length;
8310 double ratio;
8311 double tmp;
8312 double dxs;
8313 double dys;
8314 double dzs;
8315 double sfx; /* Screen from x */
8316 double sfy; /* Screen from y */
8317 double sfz; /* Screen from z */
8318 double stx; /* Screen to x */
8319 double sty; /* Screen to y */
8320 double stz; /* Screen to z */
8321 double dir_x;
8322 double dir_y;
8323 double dir_z;
8324 double dir_xp;
8325 double dir_yp;
8326 double dir_zp;
8327 double up_xp;
8328 double up_yp;
8329 double up_zp;
8330 double up_xpp;
8331 double up_ypp;
8332 double up_zpp;
8333 double up_xppp;
8334 double up_yppp;
8335 double up_zppp;
8336 double xform[4][4];
8337 double angle1;
8338 double angle2;
8339 double angle3;
8340
8341 cb.reason = reason;
8342
8343 /*
8344 * Adjust the direction the camera is pointed towards the indicated
8345 * screen (x,y) postition.
8346 */
8347 if(w->picture.look_at_direction == XmLOOK_FORWARD)
8348 {
8349 dxs = (w->picture.navigate_to_x - w->picture.navigate_from_x)*
8350 (w->picture.navigate_to_x - w->picture.navigate_from_x);
8351 dys = (w->picture.navigate_to_y - w->picture.navigate_from_y)*
8352 (w->picture.navigate_to_y - w->picture.navigate_from_y);
8353 dzs = (w->picture.navigate_to_z - w->picture.navigate_from_z)*
8354 (w->picture.navigate_to_z - w->picture.navigate_from_z);
8355 orig_length = sqrt(dxs + dys + dzs);
8356
8357 dx = (double)screen_x - (double)w->core.width/2;
8358 dy = (double)w->core.height/2 - (double)screen_y;
8359
8360 /*
8361 * Do this in screen coords, it's much simpler.
8362 */
8363 xform_coords(w->picture.PureWtrans,
8364 w->picture.navigate_from_x,
8365 w->picture.navigate_from_y,
8366 w->picture.navigate_from_z,
8367 &sfx, &sfy, &sfz);
8368 xform_coords(w->picture.PureWtrans,
8369 w->picture.navigate_to_x,
8370 w->picture.navigate_to_y,
8371 w->picture.navigate_to_z,
8372 &stx, &sty, &stz);
8373 length = fabs(sfz - stz);
8374
8375 tmp = ((double)(w->picture.rotate_speed_factor)*
8376 (double)(w->picture.rotate_speed_factor)*
8377 (double)(w->picture.rotate_speed_factor))/1000000.0;
8378
8379 stx += (dx * tmp);
8380 sty -= (dy * tmp);
8381
8382 /*
8383 * Back to the real world (coords)
8384 */
8385 xform_coords(w->picture.PureWItrans,
8386 stx, sty, stz,
8387 &w->picture.navigate_to_x,
8388 &w->picture.navigate_to_y,
8389 &w->picture.navigate_to_z);
8390
8391 /*
8392 * Length of vector between from and (new)to points
8393 */
8394 dxs = (w->picture.navigate_to_x - w->picture.navigate_from_x)*
8395 (w->picture.navigate_to_x - w->picture.navigate_from_x);
8396 dys = (w->picture.navigate_to_y - w->picture.navigate_from_y)*
8397 (w->picture.navigate_to_y - w->picture.navigate_from_y);
8398 dzs = (w->picture.navigate_to_z - w->picture.navigate_from_z)*
8399 (w->picture.navigate_to_z - w->picture.navigate_from_z);
8400 length = sqrt(dxs + dys + dzs);
8401
8402 /*
8403 * We have to adjust the z position of the "to" point so
8404 * the length of the vector(from-to) does not change from the original.
8405 */
8406 ratio = orig_length/length;
8407 dx = ratio*(w->picture.navigate_to_x -
8408 w->picture.navigate_from_x);
8409 dy = ratio*(w->picture.navigate_to_y -
8410 w->picture.navigate_from_y);
8411 dz = ratio*(w->picture.navigate_to_z -
8412 w->picture.navigate_from_z);
8413 w->picture.navigate_to_x = w->picture.navigate_from_x + dx;
8414 w->picture.navigate_to_y = w->picture.navigate_from_y + dy;
8415 w->picture.navigate_to_z = w->picture.navigate_from_z + dz;
8416 }
8417
8418 /*
8419 * If we are navigating w/ button 2, do not move the camera (x,y,z).
8420 */
8421 if (w->picture.button_pressed != 2)
8422 {
8423 /*
8424 * Translate the to and from points along the vector
8425 */
8426 length = orig_length;
8427
8428 tmp = ((double)(w->picture.translate_speed_factor)*
8429 (double)(w->picture.translate_speed_factor)*
8430 (double)(w->picture.translate_speed_factor))/1000000.0;
8431
8432 dx=tmp*(w->picture.navigate_to_x - w->picture.navigate_from_x);
8433 dy=tmp*(w->picture.navigate_to_y - w->picture.navigate_from_y);
8434 dz=tmp*(w->picture.navigate_to_z - w->picture.navigate_from_z);
8435 if (w->picture.navigate_direction == XmBACKWARD)
8436 {
8437 dx = -dx;
8438 dy = -dy;
8439 dz = -dz;
8440 }
8441 w->picture.navigate_from_x += dx;
8442 w->picture.navigate_from_y += dy;
8443 w->picture.navigate_from_z += dz;
8444 w->picture.navigate_to_x += dx;
8445 w->picture.navigate_to_y += dy;
8446 w->picture.navigate_to_z += dz;
8447 }
8448
8449 dir_x = w->picture.navigate_from_x - w->picture.navigate_to_x;
8450 dir_y = w->picture.navigate_from_y - w->picture.navigate_to_y;
8451 dir_z = w->picture.navigate_from_z - w->picture.navigate_to_z;
8452
8453 /*
8454 * Adjust the up vector to be strait up in screen space
8455 * General stategy:
8456 * 1) Rotate the direction vector about the Y axis
8457 * so it is aligned with the Z axis.
8458 * 2) Rotate the direction vector so it lies on the
8459 * XZ plane.
8460 * 3) Apply these rotations to the up vector.
8461 * 4) Rotate the resulting up vector so it lies in
8462 * the YZ plane.
8463 * 5) Zero out the z component of the resulting up
8464 * vector, and apply the inverse rotations.
8465 */
8466 /*
8467 * Rotation about the y axis
8468 */
8469 length = sqrt(dir_x*dir_x + dir_z*dir_z);
8470 if (length != 0.0)
8471 {
8472 angle1 = acos(dir_z/length);
8473 }
8474 else
8475 {
8476 angle1 = 0.0;
8477 }
8478 if (dir_x > 0)
8479 {
8480 angle1 = -angle1;
8481 }
8482 I44(xform);
8483 set_rot(xform, angle1, Yaxis);
8484 xform_coords( xform,
8485 w->picture.navigate_up_x,
8486 w->picture.navigate_up_y,
8487 w->picture.navigate_up_z,
8488 &up_xp, &up_yp, &up_zp);
8489 xform_coords( xform, dir_x, dir_y, dir_z, &dir_xp, &dir_yp, &dir_zp);
8490
8491 /*
8492 * Rotation about the x axis
8493 */
8494 length = sqrt(dir_yp*dir_yp + dir_zp*dir_zp);
8495 if (length != 0.0)
8496 {
8497 angle2 = acos(dir_zp/length);
8498 }
8499 else
8500 {
8501 angle2 = 0.0;
8502 }
8503 if (dir_yp < 0)
8504 {
8505 angle2 = -angle2;
8506 }
8507
8508 I44(xform);
8509 set_rot(xform, angle2, Xaxis);
8510 xform_coords(xform, up_xp, up_yp, up_zp, &up_xpp, &up_ypp, &up_zpp);
8511
8512 /*
8513 * Rotate about the z axis so that the up vector is aligned w/ the y axis
8514 */
8515 length = sqrt(up_xpp*up_xpp+ up_ypp*up_ypp);
8516 if (length != 0.0)
8517 {
8518 angle3 = acos(up_ypp/length);
8519 }
8520 else
8521 {
8522 angle3 = 0.0;
8523 }
8524 if (up_xpp < 0)
8525 {
8526 angle3 = -angle3;
8527 }
8528
8529 I44(xform);
8530 set_rot(xform, angle3, Zaxis);
8531 xform_coords(xform, up_xpp, up_ypp, up_zpp, &up_xppp, &up_yppp, &up_zppp);
8532
8533 I44(xform);
8534 set_rot(xform, -angle3, Zaxis);
8535 xform_coords(xform, up_xppp, up_yppp, 0.0, &up_xpp, &up_ypp, &up_zpp);
8536
8537 I44(xform);
8538 set_rot(xform, -angle2, Xaxis);
8539 xform_coords(xform, up_xpp, up_ypp, 0.0, &up_xp, &up_yp, &up_zp);
8540
8541 I44(xform);
8542 set_rot(xform, -angle1, Yaxis);
8543 xform_coords(xform, up_xp, up_yp, up_zp, &w->picture.navigate_up_x,
8544 &w->picture.navigate_up_y, &w->picture.navigate_up_z);
8545
8546 /*
8547 * Re-normalize the up vector
8548 */
8549 length = sqrt(w->picture.navigate_up_x * w->picture.navigate_up_x +
8550 w->picture.navigate_up_y * w->picture.navigate_up_y +
8551 w->picture.navigate_up_z * w->picture.navigate_up_z);
8552 w->picture.navigate_up_x = w->picture.navigate_up_x/length;
8553 w->picture.navigate_up_y = w->picture.navigate_up_y/length;
8554 w->picture.navigate_up_z = w->picture.navigate_up_z/length;
8555
8556 /*
8557 * Now that we have the new navigation camera parameters, calculate the
8558 * actual camera params (based on the current "look at" direction and
8559 * angle.
8560 */
8561 set_camera_from_nav_camera(w);
8562
8563 cb.x = w->picture.to_x;
8564 cb.y = w->picture.to_y;
8565 cb.z = w->picture.to_z;
8566
8567 cb.from_x = w->picture.from_x;
8568 cb.from_y = w->picture.from_y;
8569 cb.from_z = w->picture.from_z;
8570
8571 cb.up_x = w->picture.up_x;
8572 cb.up_y = w->picture.up_y;
8573 cb.up_z = w->picture.up_z;
8574
8575 cb.autocamera_width = w->picture.autocamera_width;
8576
8577 XtCallCallbacks ((Widget)w, XmNnavigateCallback, &cb);
8578 }
8579 /*****************************************************************************/
8580 /* */
8581 /* Subroutine: keyboard_grab */
8582 /* Effect: */
8583 /*****************************************************************************/
keyboard_grab(XmPictureWidget w,Boolean grab)8584 static void keyboard_grab(XmPictureWidget w, Boolean grab)
8585 {
8586 if (grab)
8587 {
8588 w->picture.grab_keyboard_count++;
8589 if (w->picture.grab_keyboard_count == 1)
8590 {
8591 XtGrabKeyboard((Widget)w, False, GrabModeAsync, GrabModeAsync, CurrentTime);
8592 }
8593 }
8594 else
8595 {
8596 if (w->picture.grab_keyboard_count != 0)
8597 w->picture.grab_keyboard_count--;
8598 if (w->picture.grab_keyboard_count == 0)
8599 {
8600 XtUngrabKeyboard((Widget)w, CurrentTime);
8601 }
8602 }
8603 }
8604
8605 /*****************************************************************************/
8606 /* */
8607 /* Subroutine: alloc_drawing_colors */
8608 /* Effect: allocate black and white from the colormap associated with this win*/
8609 /*****************************************************************************/
alloc_drawing_colors(XmPictureWidget new)8610 static void alloc_drawing_colors(XmPictureWidget new)
8611 {
8612 XWindowAttributes win_att;
8613 XColor white;
8614 XColor black;
8615 XColor rgb_db_def;
8616
8617 if(new->image.frame_buffer)
8618 {
8619 new->picture.white = WhitePixel(XtDisplay(new), 0);
8620 new->picture.black = BlackPixel(XtDisplay(new), 0);
8621 }
8622 else
8623 {
8624 XGetWindowAttributes(XtDisplay(new), XtWindow(new), &win_att);
8625 if(win_att.colormap != None)
8626 {
8627 if(win_att.depth == 8)
8628 {
8629 if (!XAllocNamedColor(XtDisplay(new), win_att.colormap, "white",
8630 &white, &rgb_db_def))
8631 find_color((Widget)new, &white);
8632 new->picture.white = white.pixel;
8633
8634 if (!XAllocNamedColor(XtDisplay(new), win_att.colormap, "black",
8635 &black, &rgb_db_def))
8636 find_color((Widget)new, &black);
8637 new->picture.black = black.pixel;
8638 }
8639 else
8640 {
8641 white.red = white.green = white.blue = 0xffff;
8642 black.red = black.green = black.blue = 0x0;
8643 if(!XAllocColor(XtDisplay(new), win_att.colormap, &white))
8644 find_color((Widget)new, &white);
8645 if(!XAllocColor(XtDisplay(new), win_att.colormap, &black))
8646 find_color((Widget)new, &white);
8647 new->picture.white = white.pixel;
8648 new->picture.black = black.pixel;
8649 }
8650 }
8651 else
8652 {
8653 new->picture.white = WhitePixel(XtDisplay(new), 0);
8654 new->picture.black = BlackPixel(XtDisplay(new), 0);
8655 }
8656 }
8657 }
8658 /*****************************************************************************/
8659 /* */
8660 /* Subroutine: convert color */
8661 /* Effect: Converts a pixel value from the default colormap to the current cm*/
8662 /*****************************************************************************/
convert_color(XmPictureWidget w,XColor * color)8663 static void convert_color(XmPictureWidget w, XColor *color)
8664 {
8665 int screen;
8666 Colormap cm;
8667 XWindowAttributes att;
8668
8669 color->flags = DoRed | DoGreen | DoBlue;
8670 if(w->image.frame_buffer)
8671 {
8672 screen = DefaultScreen(XtDisplay(w));
8673 cm = DefaultColormap(XtDisplay(w), screen);
8674
8675 XGetWindowAttributes(XtDisplay(w), w->picture.overlay_wid, &att);
8676 if(att.colormap != None)
8677 {
8678 cm = att.colormap;
8679 }
8680 if (!XAllocColor(XtDisplay(w), cm, color))
8681 {
8682 find_color((Widget)w, color);
8683 }
8684 }
8685 else
8686 {
8687 screen = XScreenNumberOfScreen(XtScreen(w));
8688 cm = DefaultColormap(XtDisplay(w), screen);
8689
8690 XGetWindowAttributes(XtDisplay(w), XtWindow(w), &att);
8691 if(att.colormap != None)
8692 {
8693 cm = att.colormap;
8694 }
8695 if (!XAllocColor(XtDisplay(w), cm, color))
8696 {
8697 find_color((Widget)w, color);
8698 }
8699 }
8700 }
8701
8702 /* -------------------------- Transformation library ----------------------- */
8703
8704 static int
set_trans(double res[4][4],double s0,short s1)8705 set_trans ( double res[4][4] , double s0, short s1 )
8706
8707 {
8708 int i, j;
8709 double w[4][4];
8710
8711 for ( i = 0 ; i < 4 ; i++ )
8712 for ( j = 0 ; j < 4 ; j++ )
8713 if ( i == j ) w[i][i] = 1.0;
8714 else w[i][j] = 0.0;
8715
8716
8717
8718 switch ( s1 )
8719 {
8720 case Xaxis : w[3][0] = s0;
8721 break;
8722
8723 case Yaxis : w[3][1] = s0;
8724 break;
8725
8726 case Zaxis : w[3][2] = s0;
8727 break;
8728 }
8729
8730 mult44 ( res, w );
8731 return 0;
8732 }
8733
8734
set_rot(double res[4][4],double s0,short s1)8735 static int set_rot ( double res[4][4], double s0, short s1 )
8736
8737 {
8738 int i, j;
8739 double w[4][4];
8740
8741 for ( i = 0 ; i < 4 ; i++ )
8742 for ( j = 0 ; j < 4 ; j++ )
8743 if ( i == j ) w[i][i] = 1.0;
8744 else w[i][j] = 0.0;
8745
8746
8747
8748 switch ( s1 )
8749 {
8750 case Xaxis : w[1][1] = cos ( s0 );
8751 w[1][2] = sin ( s0 );
8752 w[2][1] = -sin ( s0 );
8753 w[2][2] = cos ( s0 );
8754 break;
8755
8756 case Yaxis : w[0][0] = cos ( s0 );
8757 w[2][0] = sin ( s0 );
8758 w[0][2] = -sin ( s0 );
8759 w[2][2] = cos ( s0 );
8760 break;
8761
8762 case Zaxis : w[0][0] = cos ( s0 );
8763 w[0][1] = sin ( s0 );
8764 w[1][0] = -sin ( s0 );
8765 w[1][1] = cos ( s0 );
8766 break;
8767 }
8768
8769 mult44 ( res, w );
8770
8771 return 0;
8772 }
8773
8774
8775 /* --------------------------------- linear Algebra ------------------------ */
8776
8777
8778
8779
8780 static int
mult44(s0,s1)8781 mult44 ( s0, s1 )
8782 double s0[4][4];
8783 double s1[4][4];
8784
8785 {
8786
8787 int i, j, k;
8788 double res[4][4];
8789
8790 for ( i = 0 ; i < 4 ; i++ )
8791 for ( j = 0 ; j < 4 ; j++ )
8792 res[i][j] = 0.0;
8793
8794 for ( i = 0 ; i < 4 ; i++ )
8795 for ( j = 0 ; j < 4 ; j++ )
8796 for ( k = 0 ; k < 4 ; k++ )
8797 res[i][j] += (s0[i][k] * s1[k][j]);
8798
8799
8800 for ( i = 0 ; i < 4 ; i++ )
8801 for ( j = 0 ; j < 4 ; j++ )
8802 s0[i][j] = res[i][j];
8803
8804 return 0;
8805 }
8806
8807
8808 static double
det33(s0)8809 det33 ( s0 )
8810 double s0[4][4];
8811
8812 {
8813
8814 double det;
8815
8816 det = ( s0[0][0] * ((s0[1][1] * s0[2][2]) - (s0[2][1] * s0[1][2])) ) +
8817 (-s0[0][1] * ((s0[1][0] * s0[2][2]) - (s0[2][0] * s0[1][2])) ) +
8818 ( s0[0][2] * ((s0[1][0] * s0[2][1]) - (s0[2][0] * s0[1][1])) );
8819
8820
8821 return det;
8822
8823 }
8824
8825
8826
8827 static double
cofac(s0,s1,s2)8828 cofac ( s0 , s1, s2 )
8829 double s0[4][4];
8830 int s1;
8831 int s2;
8832
8833 {
8834
8835 int i, j, I = -1, J = 0;
8836 double cofac[4][4];
8837
8838 for ( i = 0 ; i < 4 ; i++ )
8839 if ( i != s1 )
8840 {
8841 I++;
8842 J = 0;
8843 for ( j = 0 ; j < 4 ; j++ )
8844 {
8845 if ( j != s2 )
8846 {
8847 cofac[I][J] = s0[i][j];
8848 J++;
8849 }
8850 }
8851 }
8852
8853 return ( det33( cofac ) );
8854 }
8855
8856
8857
8858 static int
inverse(s0,s1)8859 inverse ( s0, s1 )
8860 double s0[4][4];
8861 double s1[4][4];
8862
8863 {
8864
8865 int i, j;
8866 double det;
8867
8868 det = (s0[0][0] * cofac(s0, 0, 0)) + (-s0[0][1] * cofac(s0, 0, 1)) +
8869 (s0[0][2] * cofac(s0, 0, 2)) + (-s0[0][3] * cofac(s0, 0, 3));
8870
8871 det = 1.0 / det;
8872
8873 for ( i = 0 ; i < 4 ; i++ )
8874 for ( j = 0 ; j < 4 ; j++ )
8875 s1[j][i] = ( (((i + j + 1) % 2) * 2) - 1 ) * cofac(s0, i, j ) * det;
8876
8877 return 0;
8878
8879 }
8880
8881
8882 static int
I44(double w[4][4])8883 I44 (double w[4][4] )
8884 {
8885 int i, j;
8886
8887 for ( i = 0 ; i < 4 ; i++ )
8888 for ( j = 0 ; j < 4 ; j++ )
8889 if ( i == j ) w[i][j] = 1.0;
8890 else
8891 w[i][j] = 0.0;
8892 return 0;
8893 }
8894
8895 /* Subroutine: XmCreatePicture
8896 * Purpose: This function creates and returns a Picture widget.
8897 */
XmCreatePicture(Widget parent,String name,ArgList args,Cardinal num_args)8898 Widget XmCreatePicture( Widget parent, String name,
8899 ArgList args, Cardinal num_args )
8900 {
8901 return XtCreateWidget(name, xmPictureWidgetClass, parent, args, num_args);
8902 }
8903
8904
8905 /*
8906 * Subroutine: XmSetNavigateMode
8907 * Purpose: set up Picture widget so that first image software
8908 * rendered in Navigate mode initializes the navigation camera
8909 */
8910
8911 Boolean
XmPictureInitializeNavigateMode(XmPictureWidget w)8912 XmPictureInitializeNavigateMode(XmPictureWidget w)
8913 {
8914 w->picture.first_step = True;
8915 w->picture.ignore_new_camera = 0;
8916 return True;
8917 }
8918
8919