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