1 //
2 
3 package dx.net;
4 import dx.client.AppletClient;
5 import java.util.*;
6 import java.applet.*;
7 import java.awt.*;
8 import java.awt.event.*;
9 import java.net.*;
10 import java.lang.Math;
11 
12 public abstract class ImageWindow extends AppletClient
13 	implements Runnable, KeyListener, MouseListener, MouseMotionListener
14 {
15 
16     public static final int NO_MODE = 0;
17     public static final int ROTATE_MODE = 1;
18     public static final int ORBIT_MODE = 2;
19     public static final int PAN_MODE = 3;
20     public static final int ZOOM_MODE = 4;
21     public static final int LOOP_MODE = 5;
22     public static final int PICK_MODE = 6;
23     public static final int RESET_CAMERA = 7;
24     public static final int LAST_MODE = 7;
25 
26     public static final int FRONT = 0;
27     public static final int BACK = 1;
28     public static final int TOP = 2;
29     public static final int BOTTOM = 3;
30     public static final int RIGHT = 4;
31     public static final int LEFT = 5;
32     public static final int DIAGONAL = 6;
33     public static final int OFF_FRONT = 7;
34     public static final int OFF_BACK = 8;
35     public static final int OFF_TOP = 9;
36     public static final int OFF_BOTTOM = 10;
37     public static final int OFF_RIGHT = 11;
38     public static final int OFF_LEFT = 12;
39     public static final int OFF_DIAGONAL = 13;
40 
41     private static final int GRID_SIZE = 2;
42 
43     private final static double COS05 = 0.996;
44     private final static double SIN15 = 0.259;
45     private final static double COS15 = 0.966;
46     private final static double SIN25 = 0.423;
47     private final static double COS25 = 0.906;
48     private final static double SIN45 = 0.707;
49     private final static double SIN35 = 0.574;
50     public final static double PI = 3.1415926;
51 
52     public static final int XAXIS = 1;
53     public static final int YAXIS = 2;
54     public static final int ZAXIS = 3;
55 
56     private String initial_node_name;
57 
58     //
59     // Animation
60     //
61     private Thread animation = null;
62     private long start_time;
63 
64     private ImageNode node = null;
associate( ImageNode n )65     public void associate( ImageNode n )
66     {
67         this.node = n;
68     }
69 
70     public Vector pick_list;
71 
72     private int interactionMode;
73     private Point start_point;
74     private Point pan_point;
75     private Gnomon gnomon;
76     private Point edge;
77     private double aspect;
78 
getInitialNodeName( Network n )79     public String getInitialNodeName( Network n )
80     {
81         DXApplication dxapp = n.getApplet();
82         //System.out.println("ImageWindow::getInitialNodeName - " + this.initial_node_name);
83         return dxapp.getMacroName() + "_" + this.initial_node_name;
84     }
85 
getName()86 	public String getName() {
87 		return this.initial_node_name;
88 	}
89 
IsGroupInteraction( int mode )90     public static boolean IsGroupInteraction( int mode )
91     {
92         switch ( mode ) {
93         case ImageWindow.NO_MODE:
94         case ImageWindow.LOOP_MODE:
95             return true;
96         }
97 
98         return false;
99     }
100 
mouseClicked(MouseEvent me)101 	public void mouseClicked(MouseEvent me) {
102 	}
103 
mouseEntered(MouseEvent me)104 	public void mouseEntered(MouseEvent me) {
105 	}
106 
mouseExited(MouseEvent me)107 	public void mouseExited(MouseEvent me) {
108 	}
109 
mouseMoved(MouseEvent me)110 	public void mouseMoved(MouseEvent me) {
111 	}
112 
mouseDragged( MouseEvent evt )113     public void mouseDragged( MouseEvent evt )
114     {
115     	int x = evt.getX();
116     	int y = evt.getY();
117 
118     	//System.out.println("Drag event");
119         if ( this.interactionMode == ImageWindow.ORBIT_MODE ) {
120             this.orbitDrag( x, y );
121             return;
122         }
123 
124         else if ( this.interactionMode == ImageWindow.ROTATE_MODE ) {
125             this.gnomon.doDrag( x, y );
126             return;
127         }
128 
129         else if ( this.interactionMode == ImageWindow.ZOOM_MODE ) {
130             if ( this.node == null ) return;
131 
132             if ( x > this.edge.x ) return;
133 
134             if ( x < ( this.edge.x >> 1 ) ) return;
135 
136             this.rubberBand ( this.start_point );
137 
138             int newy = ( int ) ( this.aspect * x );
139 
140             this.start_point.setLocation( x, newy );
141 
142             this.rubberBand ( this.start_point );
143 
144             return;
145         }
146 
147         else if ( this.interactionMode == ImageWindow.PAN_MODE ) {
148             if ( this.node == null ) return;
149 
150             if ( x > this.edge.x ) return;
151 
152             if ( x < 0 ) return;
153 
154             if ( y > this.edge.y ) return;
155 
156             if ( y < 0 ) return;
157 
158             this.crosshair ( this.start_point );
159 
160             this.start_point.setLocation( x, y );
161 
162             this.crosshair ( this.start_point );
163 
164             return;
165         }
166     }
167 
mouseReleased( MouseEvent evt )168     public void mouseReleased( MouseEvent evt )
169     {
170     	//System.out.println("mouseReleased");
171     	int x = evt.getX();
172     	int y = evt.getY();
173 
174         if ( this.interactionMode == ImageWindow.ROTATE_MODE ) {
175             this.gnomon.doneDrag ();
176             return;
177         }
178 
179         else if ( this.interactionMode == ImageWindow.ZOOM_MODE ) {
180             if ( this.node == null ) return;
181 
182             this.rubberBand ( this.start_point );
183 
184             int w = ( this.start_point.x - ( this.edge.x - this.start_point.x ) );
185 
186             float percent = ( float ) w / ( float ) this.edge.x;
187 
188             if ( ( evt.getModifiers() & InputEvent.CTRL_MASK ) != 0 )
189                 percent = ( float ) 1.0 + percent;
190 
191             if ( this.node.isPerspective() == false ) {
192                 double width = this.node.getWidth();
193                 width *= percent;
194                 this.node.setWidth( width, true );
195             }
196 
197             else {
198                 double angle = this.node.getAngle();
199                 angle *= percent;
200                 this.node.setTo( this.node.getTo(), false );
201                 this.node.setFrom( this.node.getFrom(), false );
202                 this.node.setAngle( angle, true );
203             }
204 
205             return;
206         }
207 
208         else if ( this.interactionMode == ImageWindow.PAN_MODE ) {
209             if ( this.node == null ) return;
210 
211             float percent = ( float ) 1.0 + ( float ) ( y - this.pan_point.y ) / ( float ) this.edge.y;
212 
213             double[] topt = this.node.getTo();
214             double[] frompt = this.node.getFrom();
215             double[] upvec = this.node.getUp();
216 
217             //
218             // Pan along the upvector
219             //
220             double width = this.node.getWidth();
221             double[] fullup = new double[ 3 ];
222             double height = width * this.aspect;
223 
224             fullup[ 0 ] = upvec[ 0 ] * height;
225             fullup[ 1 ] = upvec[ 1 ] * height;
226             fullup[ 2 ] = upvec[ 2 ] * height;
227             frompt[ 0 ] = ( frompt[ 0 ] - fullup[ 0 ] ) + ( fullup[ 0 ] * percent );
228             frompt[ 1 ] = ( frompt[ 1 ] - fullup[ 1 ] ) + ( fullup[ 1 ] * percent );
229             frompt[ 2 ] = ( frompt[ 2 ] - fullup[ 2 ] ) + ( fullup[ 2 ] * percent );
230             topt[ 0 ] = ( topt[ 0 ] - fullup[ 0 ] ) + ( fullup[ 0 ] * percent );
231             topt[ 1 ] = ( topt[ 1 ] - fullup[ 1 ] ) + ( fullup[ 1 ] * percent );
232             topt[ 2 ] = ( topt[ 2 ] - fullup[ 2 ] ) + ( fullup[ 2 ] * percent );
233 
234             percent = ( float ) 1.0 + ( float ) ( x - this.pan_point.x ) / ( float ) this.edge.x;
235 
236             //
237             // Pan along the horizontal axis which we manufacture
238             // by crossing up and from
239             //
240             double[] fromvec = new double[ 4 ];
241 
242             fromvec[ 0 ] = frompt[ 0 ] - topt[ 0 ];
243             fromvec[ 1 ] = frompt[ 1 ] - topt[ 1 ];
244             fromvec[ 2 ] = frompt[ 2 ] - topt[ 2 ];
245             fromvec[ 3 ] = ( double ) 0.0;
246 
247             double[] perp = ImageWindow.cross( upvec, fromvec );
248 
249             double[] fullover = new double[ 3 ];
250 
251             //
252             // Normalize perp
253             //
254             double div = ( double ) ( Math.pow( perp[ 0 ], 2 ) +
255                                       Math.pow( perp[ 1 ], 2 ) +
256                                       Math.pow( perp[ 2 ], 2 ) );
257             div = ( double ) Math.sqrt( div );
258             perp[ 0 ] = perp[ 0 ] / div;
259             perp[ 1 ] = perp[ 1 ] / div;
260             perp[ 2 ] = perp[ 2 ] / div;
261             fullover[ 0 ] = perp[ 0 ] * width;
262             fullover[ 1 ] = perp[ 1 ] * width;
263             fullover[ 2 ] = perp[ 2 ] * width;
264             frompt[ 0 ] = ( frompt[ 0 ] + fullover[ 0 ] ) - ( fullover[ 0 ] * percent );
265             frompt[ 1 ] = ( frompt[ 1 ] + fullover[ 1 ] ) - ( fullover[ 1 ] * percent );
266             frompt[ 2 ] = ( frompt[ 2 ] + fullover[ 2 ] ) - ( fullover[ 2 ] * percent );
267             topt[ 0 ] = ( topt[ 0 ] + fullover[ 0 ] ) - ( fullover[ 0 ] * percent );
268             topt[ 1 ] = ( topt[ 1 ] + fullover[ 1 ] ) - ( fullover[ 1 ] * percent );
269             topt[ 2 ] = ( topt[ 2 ] + fullover[ 2 ] ) - ( fullover[ 2 ] * percent );
270 
271             this.node.setTo( topt, false );
272             this.node.setFrom( frompt, true );
273         }
274     }
275 
276 
mousePressed( MouseEvent evt )277     public void mousePressed( MouseEvent evt )
278     {
279     	//System.out.println("mousePressed");
280     	int x = evt.getX();
281     	int y = evt.getY();
282 
283         Dimension d = this.getSize();
284         this.edge.setLocation ( d.width, d.height );
285         this.aspect = ( double ) d.height / ( double ) d.width;
286 
287         if ( ( evt.getModifiers() & InputEvent.SHIFT_MASK ) != 0 ) {
288             try {
289                 this.getAppletContext().showDocument( new URL( this.getImageUrl() ), "temp" );
290             }
291             catch ( Exception e ) {}
292             return;
293         }
294 
295         else if ( this.interactionMode == ImageWindow.ORBIT_MODE ) {
296             this.orbitDown ( x, y );
297             return;
298         }
299 
300         else if ( this.interactionMode == ImageWindow.PICK_MODE ) {
301             if ( this.node == null ) return;
302 
303             //Dimension d = this.size();
304             int actual_y = d.height - y;
305 
306             this.node.addPickLocation ( x, actual_y );
307 
308             return;
309         }
310 
311         else if ( this.interactionMode == ImageWindow.ZOOM_MODE ) {
312             if ( this.node == null ) return;
313 
314             int newy = ( int ) ( this.aspect * x );
315 
316             this.start_point.setLocation( x, newy );
317             this.rubberBand ( this.start_point );
318 
319             return;
320         }
321 
322         else if ( this.interactionMode == ImageWindow.ROTATE_MODE ) {
323             if ( this.node == null ) return;
324 
325             this.gnomon.initDrag( evt.getModifiers() & InputEvent.CTRL_MASK, x, y );
326 
327             return;
328         }
329 
330         else if ( this.interactionMode == ImageWindow.PAN_MODE ) {
331             if ( this.node == null ) return;
332 
333             this.start_point.setLocation( x, y );
334             this.pan_point = new Point( x, y );
335             this.crosshair ( this.start_point );
336 
337         }
338 
339     }
340 
341 
getInteractionMode()342     public int getInteractionMode()
343     {
344         return this.interactionMode;
345     }
346 
setInteractionMode( int mode, long time )347     public void setInteractionMode ( int mode, long time )
348     {
349         int old_mode = this.interactionMode;
350 
351         if ( ( mode >= ImageWindow.NO_MODE ) && ( mode <= ImageWindow.LAST_MODE ) )
352             this.interactionMode = mode;
353 
354         if ( old_mode == ImageWindow.ROTATE_MODE )
355             this.setRotateMode( false );
356 
357         if ( old_mode == ImageWindow.LOOP_MODE )
358             this.setLoopMode( false, time );
359 
360         if ( mode == ImageWindow.ROTATE_MODE )
361             this.setRotateMode( true );
362 
363         if ( mode == ImageWindow.LOOP_MODE )
364             this.setLoopMode( true, time );
365 
366     }
367 
crosshair( Point p )368     private void crosshair ( Point p )
369     {
370         Graphics g = this.getGraphics();
371         g.setXORMode( Color.black );
372         g.setColor( Color.white );
373         g.drawLine ( p.x - 6, p.y, p.x + 6, p.y );
374         g.drawLine ( p.x, p.y - 6, p.x, p.y + 6 );
375     }
376 
rubberBand( Point p )377     private void rubberBand ( Point p )
378     {
379         Graphics g = this.getGraphics();
380         int x = this.edge.x - p.x;
381         int y = this.edge.y - p.y;
382         int w = ( p.x - x );
383         int h = ( p.y - y );
384         g.setXORMode( Color.black );
385         g.setColor( Color.white );
386         g.drawRect ( x, y, w, h );
387     }
388 
389 
showImage( String path )390     public void showImage ( String path )
391     {
392         this.requestImage( path );
393     }
394 
395     //
396     // In order to implement orbits
397     //
398     private int orbit_seq;
399     private Vector images;
400     private boolean using_image;
401     private int orbit_x;
402     private int orbit_y;
403     private int orbit_frame;
404 
405 
ImageWindow()406     public ImageWindow()
407     {
408         super();
409         this.orbit_seq = -1;
410         this.images = null;
411         this.using_image = false;
412         this.initial_node_name = null;
413         this.pick_list = null;
414         this.interactionMode = ImageWindow.NO_MODE;
415         this.gnomon = null;
416         Date now = new Date();
417         this.start_time = now.getTime();
418         this.start_point = new Point();
419         this.edge = new Point();
420         this.aspect = 0.0;
421     }
422 
setCurrentImage( int i )423     public void setCurrentImage( int i )
424     {
425         try {
426             Image img = ( Image ) this.images.elementAt( i );
427             super.setCurrentImage ( img, this.getCurrentSequence(), this.getCurrentLoop() );
428 
429             if ( this.interactionMode == ImageWindow.ROTATE_MODE )
430                 if ( this.gnomon != null )
431                     this.gnomon.setImage( img );
432         }
433 
434     catch ( ArrayIndexOutOfBoundsException aibe ) {}
435         catch ( NullPointerException npe ) {}
436 
437     }
438 
clearImageCache()439     public synchronized void clearImageCache()
440     {
441         if ( this.images != null ) {
442             images.removeAllElements();
443             images = null;
444         }
445     }
446 
getCacheSize()447     public synchronized int getCacheSize()
448     {
449         if ( this.images == null ) return 0;
450 
451         return this.images.size();
452     }
453 
setCurrentImage( Image i, int seq, int loop )454     protected void setCurrentImage( Image i, int seq, int loop )
455     {
456         if ( this.interactionMode == ImageWindow.ORBIT_MODE ) {
457             this.setOrbitImage ( i, seq, loop );
458         }
459 
460         else {
461             int cache_count = 0;
462             boolean caching_enabled = false;
463 
464             if ( this.loadNextImage() == true ) {
465                 cache_count = loop + 1;
466                 caching_enabled = true;
467             }
468 
469             else {
470                 try {
471                     DXApplication dxapp = this.node.getNetwork().getApplet();
472                     caching_enabled = dxapp.getCachingMode();
473                 }
474 
475                 catch ( Exception npe ) {}
476 
477                 if ( this.node != null ) {
478                     cache_count = this.node.getCacheCount();
479                 }
480             }
481 
482             if ( ( cache_count > 0 ) && ( caching_enabled ) ) {
483                 if ( this.images == null )
484                     this.images = new Vector( cache_count );
485 
486                 this.images.addElement( i );
487 
488                 while ( cache_count < this.images.size() )
489                     this.images.removeElementAt( 0 );
490             }
491 
492             super.setCurrentImage( i, seq, loop );
493 
494             if ( this.interactionMode == ImageWindow.ROTATE_MODE )
495                 if ( this.gnomon != null )
496                     this.gnomon.setImage( i );
497         }
498     }
499 
setOrbitImage( Image i, int seq, int loop )500     private void setOrbitImage( Image i, int seq, int loop )
501     {
502         if ( seq < this.orbit_seq ) return ;
503 
504         if ( seq > this.orbit_seq ) {
505             if ( images != null )
506                 images.removeAllElements();
507 
508             images = null;
509 
510             this.orbit_frame = 0;
511 
512             super.setCurrentImage( i, seq, loop );
513         }
514 
515         if ( images == null ) {
516             images = new Vector( 10 );
517         }
518 
519         images.addElement( ( Object ) i );
520         this.orbit_seq = seq;
521     }
522 
orbitDown( int x, int y )523     private boolean orbitDown( int x, int y )
524     {
525         this.orbit_x = x;
526         this.orbit_y = y;
527         return true;
528     }
529 
orbitDrag( int x, int y )530     private boolean orbitDrag( int x, int y )
531     {
532         int f = this.orbit_frame;
533 
534         if ( Math.abs( x - this.orbit_x ) > 10 ) {
535             if ( ( x > this.orbit_x ) && ( f % 3 != 2 ) )
536                 f = f + 1;
537             else if ( ( x < this.orbit_x ) && ( f % 3 != 0 ) )
538                 f = f - 1;
539 
540             this.orbit_x = x;
541         }
542 
543         if ( Math.abs( y - this.orbit_y ) > 10 ) {
544             if ( ( y > this.orbit_y ) && ( f / 3 != 2 ) )
545                 f = f + 3;
546             else if ( ( y < this.orbit_y ) && ( f / 3 != 0 ) )
547                 f = f - 3;
548 
549             this.orbit_y = y;
550         }
551 
552         if ( ( f != this.orbit_frame ) ) {
553             try {
554                 Image im = ( Image ) images.elementAt( f );
555                 super.setCurrentImage ( im, this.orbit_seq, f );
556                 this.orbit_frame = f;
557                 repaint();
558             }
559 
560             catch ( ArrayIndexOutOfBoundsException obe ) {}
561             catch ( NullPointerException npe ) {}
562 
563         }
564 
565         return true;
566     }
567 
568     //
569     // If our ImageNode is known at compile time, then we connect to it
570     // right away in order to update its resolution and aspect based on
571     // our size.
572     //
init()573     public void init()
574     {
575     	addKeyListener( this );
576     	addMouseListener( this );
577     	addMouseMotionListener( this );
578         super.init();
579         this.initial_node_name = this.getParameter( "IMAGE_NODE" );
580         String orbitstr = this.getParameter( "OPEN_IN_ORBIT_MODE" );
581 
582         if ( orbitstr != null ) {
583             if ( Boolean.valueOf( orbitstr ).booleanValue() )
584                 this.setInteractionMode( ImageWindow.ORBIT_MODE, 0 );
585         }
586     }
587 
getAnimateSpeed()588     protected synchronized int getAnimateSpeed()
589     {
590         if ( this.node != null ) return this.node.getCacheSpeed();
591 
592         return 250;
593     }
594 
setLoopMode( boolean onoroff, long start_time )595     protected void setLoopMode ( boolean onoroff, long start_time )
596     {
597         if ( onoroff ) {
598             this.animate ( start_time );
599         }
600 
601         else {
602             if ( this.animation != null ) {
603                 this.animation.interrupt();
604                 this.animation = null;
605             }
606 
607             try {
608                 Image i = ( Image ) this.images.lastElement();
609                 int s = this.getCurrentSequence();
610                 super.setCurrentImage ( i, s, this.getCurrentLoop() );
611                 repaint();
612             }
613 
614             catch ( NullPointerException npe ) {}
615             catch ( ArrayIndexOutOfBoundsException obe ) {}
616 
617         }
618 
619     }
620 
animate( long start )621     protected void animate( long start )
622     {
623         if ( this.animation != null ) {
624             this.animation.interrupt();
625             this.animation = null;
626         }
627 
628         if ( this.images == null ) return ;
629 
630         this.start_time = start;
631 
632         this.animation = new Thread( this );
633 
634         this.animation.start();
635     }
636 
interrupt()637     public void interrupt()
638     {
639         if ( this.animation != null ) {
640             this.animation.interrupt();
641             this.animation = null;
642         }
643     }
644 
run()645     public void run()
646     {
647         boolean error = false;
648 
649         try {
650             long target = this.start_time + this.getAnimateSpeed();
651 
652             while ( ( !error ) && ( this.images != null ) && ( this.images.size() > 1 ) ) {
653                 if ( this.node.getPalindromeMode() ) {
654                     int i;
655                     int size = this.images.size();
656 
657                     for ( i = size - 2; i >= 1; i-- ) {
658                         Image im = ( Image ) this.images.elementAt( i );
659                         super.setCurrentImage( im, getCurrentSequence(), 0 );
660                         repaint();
661 
662                         try {
663                             long now = ( new Date() ).getTime();
664                             int time_to_wait = ( int ) ( target - now );
665 
666                             if ( time_to_wait > 0 )
667                                 Thread.sleep( time_to_wait );
668                             else if ( time_to_wait < -10000 ) {
669                                 error = true;
670                                 break;
671                             }
672                         }
673 
674                         catch ( InterruptedException ie ) {
675                             error = true;
676                             break;
677                         }
678 
679                         target += this.getAnimateSpeed();
680                     }
681                 }
682 
683                 Enumeration enum1 = this.images.elements();
684 
685                 while ( ( !error ) && ( enum1.hasMoreElements() ) ) {
686                     Image im = ( Image ) enum1.nextElement();
687                     super.setCurrentImage( im, getCurrentSequence(), 0 );
688                     repaint();
689 
690                     try {
691                         long now = ( new Date() ).getTime();
692                         int time_to_wait = ( int ) ( target - now );
693 
694                         if ( time_to_wait > 0 )
695                             Thread.sleep( time_to_wait );
696                         else if ( time_to_wait < -10000 ) {
697                             error = true;
698                             break;
699                         }
700                     }
701 
702                     catch ( InterruptedException ie ) {
703                         error = true;
704                         break;
705                     }
706 
707                     target += this.getAnimateSpeed();
708                 }
709             }
710         }
711 
712         catch ( Exception e ) {
713             //
714             // We'll fall thru here if the user unchecks the
715             // "Enable Animation" toggle while we're animating.
716             //
717         }
718     }
719 
720     //
721     // Should be called only from ImageNode.  There are 2 representations
722     // of the set of picks: 1 is the spots in the image, the other is the
723     // list in the node.  They must be in sync.
724     //
addPickLocation( int x, int y )725     public void addPickLocation( int x, int y )
726     {
727         if ( this.pick_list == null )
728             this.pick_list = new Vector( 4 );
729 
730         Dimension d = this.getSize();
731 
732         int actual_y = d.height - y;
733 
734         Point p = new Point( x, actual_y );
735 
736         this.pick_list.addElement( p );
737 
738         repaint();
739     }
740 
paint( Graphics g )741     public void paint( Graphics g )
742     {
743         super.paint( g );
744 
745         if ( this.interactionMode == ImageWindow.PICK_MODE ) {
746             if ( this.pick_list == null ) return ;
747 
748             Enumeration enum1 = this.pick_list.elements();
749 
750             g.setColor( Color.white );
751 
752             while ( enum1.hasMoreElements() ) {
753                 Point p = ( Point ) enum1.nextElement();
754                 g.fill3DRect( p.x - 2, p.y - 2, 4, 4, true );
755             }
756         }
757 
758         else if ( this.interactionMode == ImageWindow.ROTATE_MODE ) {
759             this.gnomon.repaint();
760         }
761     }
762 
resetPickList()763     public void resetPickList()
764     {
765         this.pick_list = null;
766         repaint();
767     }
768 
setRotateMode( boolean onoroff )769     protected void setRotateMode( boolean onoroff )
770     {
771         if ( this.gnomon == null ) {
772             if ( onoroff )
773                 this.createGnomon();
774         }
775 
776         if ( onoroff ) {
777             this.gnomon.setImage ( this.getCurrentImage() );
778             this.add( this.gnomon );
779         }
780 
781         else
782             if ( this.gnomon != null )
783                 this.remove( this.gnomon );
784     }
785 
createGnomon()786     private void createGnomon()
787     {
788         this.setLayout( null );
789         Dimension dim = this.getSize();
790         this.gnomon = new Gnomon ( this.node, dim.width, dim.height );
791         int x = dim.width - 95;
792         int y = dim.height - 95;
793         this.gnomon.setBounds ( x, y, 90, 90 );
794         this.gnomon.setImage( this.getCurrentImage() );
795     }
796 
797 
normalize( double[] f, double[] t )798     public static double[] normalize ( double[] f, double[] t )
799     {
800         double dist = Math.pow( ( f[ 0 ] - t[ 0 ] ), 2 );
801         dist += Math.pow( ( f[ 1 ] - t[ 1 ] ), 2 );
802         dist += Math.pow( ( f[ 2 ] - t[ 2 ] ), 2 );
803         dist = Math.sqrt( dist );
804         double[] norm = new double[ 3 ];
805 
806         norm[ 0 ] = ( f[ 0 ] - t[ 0 ] ) / dist;
807         norm[ 1 ] = ( f[ 1 ] - t[ 1 ] ) / dist;
808         norm[ 2 ] = ( f[ 2 ] - t[ 2 ] ) / dist;
809         return norm;
810     }
811 
812     //    private static void printMat(double[][] mat) {
813     //
814     // int i;
815     // for (i=0; i<4; i++) {
816     //     System.out.println
817     //     ("   | " +mat[0][i]+ " " +mat[1][i]+ " " +mat[2][i]+ " " +mat[3][i]+ " |");
818     // }
819     //    }
820 
821     //
822     // L I N E A R    A L G E B R A
823     // L I N E A R    A L G E B R A
824     // L I N E A R    A L G E B R A
825     //
826 
827     //
828     // The Rolling Ball algorithm from Graphics Gems.
829     // N.B.  Always translate a point towards 0,0,0 before applying
830     // a transformation matrix.  Otherwise you get big rounding problems.
831     //
getTransform( double[] f, double[] t, double theta )832     public static double[][] getTransform( double[] f, double[] t, double theta )
833     {
834         double[] ndir = ImageWindow.normalize ( f, t );
835 
836         double[][] T = new double[ 4 ][ 4 ];
837         ImageWindow.I44( T );
838 
839         double cost = ( double ) Math.cos( theta );
840         double sint = ( double ) Math.sin( theta );
841 
842         T[ 0 ][ 0 ] = cost + ( Math.pow( ndir[ 0 ], 2 ) * ( 1.0 - cost ) );
843         T[ 1 ][ 1 ] = cost + ( Math.pow( ndir[ 1 ], 2 ) * ( 1.0 - cost ) );
844         T[ 2 ][ 2 ] = cost + ( Math.pow( ndir[ 2 ], 2 ) * ( 1.0 - cost ) );
845 
846         T[ 0 ][ 1 ] = ( ndir[ 0 ] * ndir[ 1 ] * ( 1.0 - cost ) ) + ( ndir[ 2 ] * sint );
847         T[ 1 ][ 0 ] = ( ndir[ 0 ] * ndir[ 1 ] * ( 1.0 - cost ) ) - ( ndir[ 2 ] * sint );
848 
849         T[ 2 ][ 1 ] = ( ndir[ 1 ] * ndir[ 2 ] * ( 1.0 - cost ) ) - ( ndir[ 0 ] * sint );
850         T[ 1 ][ 2 ] = ( ndir[ 1 ] * ndir[ 2 ] * ( 1.0 - cost ) ) + ( ndir[ 0 ] * sint );
851 
852         T[ 2 ][ 0 ] = ( ndir[ 0 ] * ndir[ 2 ] * ( 1.0 - cost ) ) + ( ndir[ 1 ] * sint );
853         T[ 0 ][ 2 ] = ( ndir[ 0 ] * ndir[ 2 ] * ( 1.0 - cost ) ) - ( ndir[ 1 ] * sint );
854 
855         return T;
856     }
857 
858     //
859     // Multiply a 4-vector and a 4x4 matrix
860     //
Rotate( double vec[], double mat[][] )861     public static double[] Rotate( double vec[], double mat[][] )
862     {
863         int i, j, k;
864         double result[] = new double[ 4 ];
865 
866         for ( i = 0; i < 4; i++ ) result[ i ] = ( double ) 0.0;
867 
868         for ( k = 0; k < 4; k++ ) {
869             for ( i = 0; i < 4; i++ ) {
870                 result[ k ] += vec[ i ] * mat[ i ][ k ];
871             }
872         }
873 
874         return result;
875     }
876 
I44( double w[][] )877     private static void I44 ( double w[][] )
878     {
879         int i, j;
880 
881         for ( i = 0; i < 4; i++ )
882             for ( j = 0; j < 4; j++ )
883                 if ( i == j ) w[ i ][ j ] = ( double ) 1.0;
884                 else w[ i ][ j ] = ( double ) 0.0;
885     }
886 
cross( double v[], double w[] )887     public static double[] cross ( double v[], double w[] )
888     {
889         double[] res = new double[ 4 ];
890         res[ 0 ] = ( v[ 1 ] * w[ 2 ] ) - ( v[ 2 ] * w[ 1 ] );
891         res[ 1 ] = ( v[ 2 ] * w[ 0 ] ) - ( v[ 0 ] * w[ 2 ] );
892         res[ 2 ] = ( v[ 0 ] * w[ 1 ] ) - ( v[ 1 ] * w[ 0 ] );
893         res[ 3 ] = ( double ) 1.0;
894         return res;
895     }
896 
dot( float v[], double w[] )897     public static double dot ( float v[], double w[] )
898     {
899         int i = v.length;
900 
901         if ( i != w.length ) return 0.0;
902 
903         double res = 0.0;
904 
905         int j;
906 
907         for ( j = 0; j < i; j++ )
908             res += ( v[ j ] * w[ j ] );
909 
910         return res;
911     }
912 
keyPressed( KeyEvent e )913     public void keyPressed ( KeyEvent e )
914     {
915     	int key = e.getKeyCode();
916     	int m = e.getModifiers();
917 
918         if ( ( this.node != null ) ) {
919             boolean retval = false;
920 
921 	        if ( key == KeyEvent.VK_E && ( m & InputEvent.CTRL_MASK ) > 0 ) {
922     	        retval = true;
923     	    }
924     	    else if ( key == KeyEvent.VK_R && ( m & InputEvent.CTRL_MASK ) > 0 ) {
925     	        retval = true;
926     	    }
927     	    else if ( key == KeyEvent.VK_F && ( m & InputEvent.CTRL_MASK ) > 0 ) {
928 				retval = true;
929 			}
930     	    else if ( key == KeyEvent.VK_TAB && ( m & InputEvent.CTRL_MASK ) > 0 ) {
931     	        retval = true;
932     	    }
933     	    else if ( key == KeyEvent.VK_SPACE && ( m & InputEvent.CTRL_MASK ) > 0 ) {
934     	        retval = true;
935     	    }
936     	    else if ( key == KeyEvent.VK_C && ( m & InputEvent.CTRL_MASK ) > 0 ) {
937     	        retval = true;
938     	    }
939 
940             if ( retval ) {
941                 DXApplication dxapp = this.node.getNetwork().getApplet();
942                 dxapp.updateSelectedImageNode( e, this.node );
943             }
944         }
945     }
946 
keyReleased( KeyEvent e )947     public void keyReleased ( KeyEvent e ) {
948     }
949 
keyTyped( KeyEvent e )950     public void keyTyped ( KeyEvent e ) {
951     }
952 
setView( int direction, boolean send )953     public void setView ( int direction, boolean send )
954     {
955         double[] frompt = this.node.getFrom();
956         double[] up = this.node.getUp();
957         double[] topt = this.node.getTo();
958         double[] dir = new double[ 3 ];
959         int X = 0;
960         int Y = 1;
961         int Z = 2;
962         dir[ X ] = frompt[ 0 ] - topt[ 0 ];
963         dir[ Y ] = frompt[ 1 ] - topt[ 1 ];
964         dir[ Z ] = frompt[ 2 ] - topt[ 2 ];
965         double length = Math.sqrt ( dir[ X ] * dir[ X ] + dir[ Y ] * dir[ Y ] + dir[ Z ] * dir[ Z ] );
966         up[ X ] = 0.0;
967         up[ Y ] = 1.0;
968         up[ Z ] = 0.0;
969 
970         switch ( direction ) {
971         case ImageWindow.FRONT:
972             dir[ X ] = 0.0; dir[ Y ] = 0.0; dir[ Z ] = 1.0;
973             break;
974         case ImageWindow.OFF_FRONT:
975             dir[ X ] = dir[ Y ] = ImageWindow.SIN15; dir[ Z ] = ImageWindow.COS15;
976             break;
977         case ImageWindow.BACK:
978             dir[ X ] = 0.0; dir[ Y ] = 0.0; dir[ Z ] = -1.0;
979             break;
980         case ImageWindow.OFF_BACK:
981             dir[ X ] = dir[ Y ] = ImageWindow.SIN15; dir[ Z ] = -ImageWindow.COS15;
982             break;
983         case ImageWindow.TOP:
984             dir[ X ] = 0.0; dir[ Y ] = 1.0; dir[ Z ] = 0.0;
985             up[ X ] = up[ Y ] = 0.0; up[ Z ] = -1.0;
986             break;
987         case ImageWindow.OFF_TOP:
988             dir[ X ] = dir[ Z ] = -ImageWindow.SIN15; dir[ Y ] = ImageWindow.COS15;
989             up[ X ] = up[ Y ] = 0.0; up[ Z ] = -1.0;
990             break;
991         case ImageWindow.BOTTOM:
992             dir[ X ] = 0.0; dir[ Y ] = -1.0; dir[ Z ] = 0.0;
993             up[ X ] = up[ Y ] = 0.0; up[ Z ] = 1.0;
994             break;
995         case ImageWindow.OFF_BOTTOM:
996             dir[ X ] = dir[ Z ] = ImageWindow.SIN15; dir[ Y ] = -ImageWindow.COS15;
997             up[ X ] = up[ Y ] = 0.0; up[ Z ] = 1.0;
998             break;
999         case ImageWindow.RIGHT:
1000             dir[ X ] = 1.0; dir[ Y ] = 0.0; dir[ Z ] = 0.0;
1001             break;
1002         case ImageWindow.OFF_RIGHT:
1003             dir[ X ] = ImageWindow.COS05; dir[ Y ] = dir[ Z ] = ImageWindow.SIN15;
1004             break;
1005         case ImageWindow.LEFT:
1006             dir[ X ] = -1.0; dir[ Y ] = 0.0; dir[ Z ] = 0.0;
1007             break;
1008         case ImageWindow.OFF_LEFT:
1009             dir[ X ] = -ImageWindow.COS05; dir[ Y ] = dir[ Z ] = ImageWindow.SIN15;
1010             break;
1011         case ImageWindow.DIAGONAL:
1012             dir[ X ] = dir[ Y ] = dir[ Z ] = ImageWindow.SIN45;
1013             break;
1014         case ImageWindow.OFF_DIAGONAL:
1015             dir[ X ] = dir[ Y ] = dir[ Z ] = ImageWindow.SIN35;
1016             break;
1017         }
1018 
1019         double tmp_length = Math.sqrt ( dir[ X ] * dir[ X ] + dir[ Y ] * dir[ Y ] + dir[ Z ] * dir[ Z ] );
1020         dir[ X ] = dir[ X ] / tmp_length;
1021         dir[ Y ] = dir[ Y ] / tmp_length;
1022         dir[ Z ] = dir[ Z ] / tmp_length;
1023 
1024         dir[ X ] *= length;
1025         dir[ Y ] *= length;
1026         dir[ Z ] *= length;
1027 
1028         frompt[ X ] = dir[ X ] + topt[ X ];
1029         frompt[ Y ] = dir[ Y ] + topt[ Y ];
1030         frompt[ Z ] = dir[ Z ] + topt[ Z ];
1031 
1032         this.node.setFrom( frompt, false );
1033         this.node.setUp( up, send );
1034     }
1035 
1036 } // end ImageWindow
1037