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