001 //$HeadURL: svn+ssh://mschneider@svn.wald.intevation.org/deegree/base/trunk/resources/eclipse/svn_classfile_header_template.xml $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036
037 package org.deegree.tools.app3d;
038
039 import java.awt.BorderLayout;
040 import java.awt.Color;
041 import java.awt.Dimension;
042 import java.awt.GraphicsConfigTemplate;
043 import java.awt.GridBagConstraints;
044 import java.awt.GridBagLayout;
045 import java.awt.Insets;
046 import java.awt.event.ActionEvent;
047 import java.awt.event.ActionListener;
048 import java.awt.event.KeyEvent;
049 import java.awt.event.KeyListener;
050 import java.awt.event.WindowAdapter;
051 import java.awt.event.WindowEvent;
052 import java.io.File;
053 import java.io.FileWriter;
054 import java.io.IOException;
055 import java.security.InvalidParameterException;
056 import java.util.ArrayList;
057 import java.util.Enumeration;
058 import java.util.List;
059 import java.util.prefs.Preferences;
060
061 import javax.media.j3d.Appearance;
062 import javax.media.j3d.Background;
063 import javax.media.j3d.BoundingBox;
064 import javax.media.j3d.BoundingSphere;
065 import javax.media.j3d.Bounds;
066 import javax.media.j3d.BranchGroup;
067 import javax.media.j3d.Canvas3D;
068 import javax.media.j3d.ColoringAttributes;
069 import javax.media.j3d.DirectionalLight;
070 import javax.media.j3d.GraphicsConfigTemplate3D;
071 import javax.media.j3d.Group;
072 import javax.media.j3d.Light;
073 import javax.media.j3d.Material;
074 import javax.media.j3d.RenderingAttributes;
075 import javax.media.j3d.Texture;
076 import javax.media.j3d.Transform3D;
077 import javax.media.j3d.TransformGroup;
078 import javax.media.j3d.View;
079 import javax.swing.BorderFactory;
080 import javax.swing.JButton;
081 import javax.swing.JDialog;
082 import javax.swing.JFileChooser;
083 import javax.swing.JFrame;
084 import javax.swing.JLabel;
085 import javax.swing.JOptionPane;
086 import javax.swing.JPanel;
087 import javax.swing.JProgressBar;
088 import javax.swing.JRadioButton;
089 import javax.swing.SwingConstants;
090 import javax.swing.WindowConstants;
091 import javax.swing.border.BevelBorder;
092 import javax.swing.border.Border;
093 import javax.swing.filechooser.FileFilter;
094 import javax.vecmath.Color3f;
095 import javax.vecmath.Point3d;
096 import javax.vecmath.Vector3d;
097 import javax.vecmath.Vector3f;
098
099 import org.deegree.framework.log.ILogger;
100 import org.deegree.framework.log.LoggerFactory;
101 import org.j3d.renderer.java3d.geom.Sphere;
102 import org.w3c.dom.Node;
103
104 import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
105 import com.sun.j3d.utils.geometry.ColorCube;
106 import com.sun.j3d.utils.universe.SimpleUniverse;
107
108 /**
109 * The <code>View3DFile</code> class can display shape and gml/citygml file in 3D.
110 *
111 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
112 *
113 * @author last edited by: $Author:$
114 *
115 * @version $Revision:$, $Date:$
116 *
117 */
118
119 public class View3DFile extends JFrame implements ActionListener, KeyListener {
120 /**
121 *
122 */
123 private static final long serialVersionUID = 7698388852544865855L;
124
125 private static ILogger LOG = LoggerFactory.getLogger( View3DFile.class );
126
127 private SimpleUniverse simpleUniverse;
128
129 private Canvas3D canvas;
130
131 private MouseRotate trackBall;
132
133 private BranchGroup scene;
134
135 private TransformGroup rotationGroup;
136
137 private Light firstLight, secondLight, thirdLight;
138
139 private Point3d centroid;
140
141 private Preferences prefs;
142
143 private final static String OPEN_KEY = "lastOpenLocation";
144
145 private final static String LAST_EXTENSION = "lastFileExtension";
146
147 private final static String WIN_TITLE = "Deegree 3D Object viewer: ";
148
149 private Background backGround;
150
151 private double zoomX = 1;
152
153 private double zoomY = 1;
154
155 private double zoomZ = 1;
156
157 private final Vector3d upVector = new Vector3d( 0, 1, 0 );
158
159 private List<CustomFileFilter> supportedOpenFilter = new ArrayList<CustomFileFilter>();
160
161 /**
162 * A panel showing some key stroke helps
163 */
164 JPanel helpLister;
165
166 /**
167 * Creates a frame with the menus and the canvas3d set and tries to load the file from given location.
168 *
169 * @param fileName
170 * to be loaded.
171 */
172 public View3DFile( String fileName ) {
173 this( false );
174 readFile( fileName );
175 }
176
177 /**
178 * Creates a new frame with the menus and the canvas3d set.
179 *
180 * @param testSphere
181 * true if a sphere should be displayed.
182 */
183 public View3DFile( boolean testSphere ) {
184 super( WIN_TITLE );
185 prefs = Preferences.userNodeForPackage( View3DFile.class );
186 setupGUI();
187
188 // openFileChooser();
189
190 setupJava3D( testSphere );
191 ArrayList<String> extensions = new ArrayList<String>();
192
193 extensions.add( "gml" );
194 extensions.add( "xml" );
195 supportedOpenFilter.add( new CustomFileFilter( extensions, "(*.gml, *.xml) GML or CityGML-Files" ) );
196
197 extensions.clear();
198 extensions.add( "shp" );
199 supportedOpenFilter.add( new CustomFileFilter( extensions, "(*.shp) Esri ShapeFiles" ) );
200
201 extensions.clear();
202 extensions.add( "vrml" );
203 extensions.add( "wrl" );
204 supportedOpenFilter.add( new CustomFileFilter( extensions,
205 "(*.vrml, *.wrl) VRML97 - Virtual Reality Modelling Language" ) );
206
207 pack();
208 }
209
210 /**
211 * GUI stuff
212 */
213 private void setupGUI() {
214 // add listener for closing the frame/application
215 addWindowListener( new WindowAdapter() {
216 @Override
217 public void windowClosing( WindowEvent evt ) {
218 System.exit( 0 );
219 }
220 } );
221 setLayout( new BorderLayout() );
222 setMinimumSize( new Dimension( 600, 600 ) );
223 setPreferredSize( new Dimension( 600, 600 ) );
224 setVisible( true );
225 // Adding the button panel
226 JPanel totalPanel = new JPanel( new BorderLayout() );
227 // JPanel buttonPanel = new JPanel( new FlowLayout() );
228 // createButtons( buttonPanel );
229 totalPanel.add( createButtons(), BorderLayout.NORTH );
230 addKeyListener( this );
231 helpLister = new JPanel( new GridBagLayout() );
232 Border border = BorderFactory.createTitledBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED ),
233 "Instant help" );
234 helpLister.setBorder( border );
235 GridBagConstraints gb = new GridBagConstraints();
236 gb.ipadx = 10;
237 gb.gridx = 0;
238 gb.gridy = 0;
239 JLabel tmp = new JLabel( "x: move postive X-axis" );
240 helpLister.add( tmp, gb );
241
242 gb.gridx++;
243 tmp = new JLabel( "X: move negative X-axis" );
244 helpLister.add( tmp, gb );
245
246 gb.gridx = 0;
247 gb.gridy++;
248 tmp = new JLabel( "y: move positve Y-axis" );
249 helpLister.add( tmp, gb );
250
251 gb.gridx++;
252 tmp = new JLabel( "Y: move negative Y-axis" );
253 helpLister.add( tmp, gb );
254
255 gb.gridy++;
256 gb.gridx = 0;
257 tmp = new JLabel( "z: move positve Z-axis" );
258 helpLister.add( tmp, gb );
259 gb.gridx++;
260
261 tmp = new JLabel( "Z: move negative Z-axis" );
262 helpLister.add( tmp, gb );
263 helpLister.setVisible( false );
264
265 totalPanel.add( helpLister, BorderLayout.SOUTH );
266 getContentPane().add( totalPanel, BorderLayout.SOUTH );
267
268 }
269
270 private JFileChooser createFileChooser( List<CustomFileFilter> fileFilter ) {
271 // Setting up the fileChooser.
272
273 String lastLoc = prefs.get( OPEN_KEY, System.getProperty( "user.home" ) );
274
275 File lastFile = new File( lastLoc );
276 if ( !lastFile.exists() ) {
277 lastFile = new File( System.getProperty( "user.home" ) );
278 }
279 JFileChooser fileChooser = new JFileChooser( lastFile );
280 fileChooser.setMultiSelectionEnabled( false );
281 if ( fileFilter != null && fileFilter.size() > 0 ) {
282 // the *.* file fileter is off
283 fileChooser.setAcceptAllFileFilterUsed( false );
284 String lastExtension = prefs.get( LAST_EXTENSION, "*" );
285 FileFilter selected = fileFilter.get( 0 );
286 for ( CustomFileFilter filter : fileFilter ) {
287 fileChooser.setFileFilter( filter );
288 if ( filter.accepts( lastExtension ) ) {
289 selected = filter;
290 }
291 }
292
293 fileChooser.setFileFilter( selected );
294 }
295
296 return fileChooser;
297 }
298
299 private void setupJava3D( boolean testSphere ) {
300 // setting up Java3D
301 GraphicsConfigTemplate3D configTemplate = new GraphicsConfigTemplate3D();
302 configTemplate.setSceneAntialiasing( GraphicsConfigTemplate.PREFERRED );
303 configTemplate.setDoubleBuffer( GraphicsConfigTemplate.REQUIRED );
304 canvas = new Canvas3D( SimpleUniverse.getPreferredConfiguration() );
305 canvas.setDoubleBufferEnable( true );
306 simpleUniverse = new SimpleUniverse( canvas );
307 if ( canvas != null ) {
308 getContentPane().add( canvas, BorderLayout.CENTER );
309 }
310
311 View view = simpleUniverse.getViewer().getView();
312
313 // view parameters
314 view.setSceneAntialiasingEnable( true );
315 view.setUserHeadToVworldEnable( true );
316
317 centroid = new Point3d( 0.3, 0.3, 0.3 );
318 scene = new BranchGroup();
319 firstLight = createDirectionalLight( new Vector3f( 0, 0, 1 ) );
320 secondLight = createDirectionalLight( new Vector3f( 0, -1, -1 ) );
321 thirdLight = createDirectionalLight( new Vector3f( -1, 0, 0 ) );
322
323 scene.addChild( firstLight );
324 scene.addChild( secondLight );
325 scene.addChild( thirdLight );
326
327 // is handled by the mouse rotater, all objects will be added to it.
328 rotationGroup = new TransformGroup();
329 rotationGroup.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE );
330 rotationGroup.setCapability( TransformGroup.ALLOW_TRANSFORM_READ );
331 rotationGroup.setCapability( BranchGroup.ALLOW_DETACH );
332 rotationGroup.setCapability( Group.ALLOW_CHILDREN_EXTEND );
333 rotationGroup.setCapability( Group.ALLOW_CHILDREN_READ );
334 rotationGroup.setCapability( Group.ALLOW_CHILDREN_WRITE );
335 scene.addChild( rotationGroup );
336
337 backGround = new Background( new Color3f( Color.LIGHT_GRAY ) );
338 backGround.setCapability( javax.media.j3d.Node.ALLOW_BOUNDS_WRITE );
339 backGround.setCapability( javax.media.j3d.Node.ALLOW_BOUNDS_READ );
340 backGround.setCapability( Background.ALLOW_APPLICATION_BOUNDS_READ );
341 backGround.setCapability( Background.ALLOW_APPLICATION_BOUNDS_WRITE );
342
343 scene.addChild( backGround );
344
345 trackBall = new MouseRotate( rotationGroup );
346 scene.addChild( trackBall );
347
348 simpleUniverse.addBranchGraph( scene );
349
350 // adding the key listeners
351 canvas.addKeyListener( this );
352
353 if ( testSphere ) {
354 BranchGroup sphere = createStartScene( null );
355 addBranchGroupToScene( sphere );
356 }
357 }
358
359 /**
360 * Create a directional light, with color.WHITE.
361 */
362 private DirectionalLight createDirectionalLight( Vector3f lightDir ) {
363 // create the color for the light
364 Color3f color = new Color3f( Color.WHITE );
365 // create the directional light with the color and direction
366 DirectionalLight light = new DirectionalLight( color, lightDir );
367 light.setCapability( Light.ALLOW_INFLUENCING_BOUNDS_READ );
368 light.setCapability( Light.ALLOW_INFLUENCING_BOUNDS_WRITE );
369 return light;
370 }
371
372 /**
373 * Add the given branch group to the scene and set the appropriate distance etc. After adding the branch group to
374 * the rotation group which is controlled by the mouse rotator.
375 *
376 * @param b
377 */
378 private void addBranchGroupToScene( BranchGroup b ) {
379 rotationGroup.removeAllChildren();
380 // translationGroup.removeAllChildren();
381 // System.out.println( b.getBounds() );
382 Bounds bounds = b.getBounds();
383 BranchGroup wrapper = new BranchGroup();
384 wrapper.setCapability( BranchGroup.ALLOW_DETACH );
385 wrapper.setCapability( Group.ALLOW_CHILDREN_READ );
386 wrapper.setCapability( Texture.ALLOW_ENABLE_READ );
387 wrapper.setCapability( Texture.ALLOW_IMAGE_READ );
388 if ( bounds != null ) {
389 LOG.logDebug( "Old centroid: " + centroid );
390 BoundingSphere bs = new BoundingSphere( bounds );
391 bs.getCenter( centroid );
392 LOG.logDebug( "New centroid: " + centroid );
393
394 TransformGroup viewToWorld = simpleUniverse.getViewingPlatform().getViewPlatformTransform();
395 Transform3D trans = new Transform3D();
396
397 BoundingBox bbox = new BoundingBox( bounds );
398 Point3d lower = new Point3d();
399 bbox.getLower( lower );
400 Point3d upper = new Point3d();
401 bbox.getUpper( upper );
402 double lengthX = Math.abs( upper.x - lower.x );
403 double lengthY = Math.abs( upper.y - lower.y );
404 double lengthZ = Math.abs( upper.z - lower.z );
405
406 zoomX = lengthX * 0.1;
407 zoomY = lengthY * 0.1;
408 zoomZ = lengthZ * 0.1;
409
410 double radius = ( lengthX > lengthY ) ? ( ( lengthX > lengthZ ) ? lengthX
411 : ( ( lengthY > lengthZ ) ? lengthY
412 : lengthZ ) )
413 : ( ( lengthY > lengthZ ) ? lengthY : lengthZ );
414 Point3d eye = new Point3d();
415 eye.z += ( ( lower.z - upper.z < 0 ) ? -1 : 1 ) * ( radius * 1.5 );
416 if ( Math.abs( eye.z ) < 0.00001 && Math.abs( centroid.z ) < 0.00001 ) {
417 eye.z = 1;
418 }
419 trans.lookAt( eye, centroid, upVector );
420
421 LOG.logDebug( "Trans Matrix after lookat:\n" + trans );
422 LOG.logDebug( "BBox lower: " + lower );
423 LOG.logDebug( "BBox upper: " + upper );
424 LOG.logDebug( "Center: " + centroid );
425 LOG.logDebug( "eye: " + eye );
426 LOG.logDebug( "up: " + upVector );
427 LOG.logDebug( "radius: " + bs.getRadius() );
428 LOG.logDebug( "used radius (of largest axis): " + radius );
429 LOG.logDebug( "zoomX: " + zoomX );
430 LOG.logDebug( "zoomY: " + zoomY );
431 LOG.logDebug( "zoomZ: " + zoomZ );
432 viewToWorld.setTransform( trans );
433 View view = simpleUniverse.getViewer().getView();
434
435 // view parameters
436 view.setBackClipDistance( radius * 100 );
437 // the near clippingplane is one hundereth of the far.
438 view.setFrontClipDistance( radius * 0.001 );
439
440 BoundingSphere influence = new BoundingSphere( eye, radius * 4 );
441
442 firstLight.setInfluencingBounds( influence );
443 secondLight.setInfluencingBounds( influence );
444 thirdLight.setInfluencingBounds( influence );
445 trackBall.setSchedulingBounds( influence );
446 backGround.setApplicationBounds( influence );
447
448 // add the negativ translation for the mouse tracker to work.
449 TransformGroup resultTrans = new TransformGroup();
450 Transform3D negativTranslation = new Transform3D();
451 negativTranslation.setTranslation( new Vector3d( -centroid.x, -centroid.y, -centroid.z ) );
452 resultTrans.setTransform( negativTranslation );
453 resultTrans.addChild( b );
454 wrapper.addChild( resultTrans );
455 } else {
456 wrapper.addChild( b );
457 }
458 rotationGroup.addChild( wrapper );
459 }
460
461 /**
462 * @return a shere and a cube
463 */
464 private BranchGroup createStartScene( Point3d translation ) {
465 Appearance app = new Appearance();
466 RenderingAttributes ra = new RenderingAttributes();
467 ra.setDepthBufferEnable( true );
468 ra.setDepthBufferWriteEnable( true );
469 app.setRenderingAttributes( ra );
470
471 ColoringAttributes ca = new ColoringAttributes();
472 ca.setShadeModel( ColoringAttributes.SHADE_GOURAUD );
473 ca.setCapability( ColoringAttributes.NICEST );
474 app.setColoringAttributes( ca );
475
476 Material material = new Material();
477 material.setAmbientColor( new Color3f( Color.WHITE ) );
478 material.setDiffuseColor( new Color3f( Color.RED ) );
479 material.setSpecularColor( new Color3f( Color.ORANGE ) );
480 app.setMaterial( material );
481 TransformGroup tg = new TransformGroup();
482 Transform3D trans = new Transform3D();
483 if ( translation != null ) {
484 trans.setTranslation( new Vector3d( translation ) );
485 tg.setTransform( trans );
486 }
487 tg.setCapability( BranchGroup.ALLOW_DETACH );
488 tg.setCapability( Group.ALLOW_CHILDREN_READ );
489 tg.addChild( new ColorCube( 0.2f ) );
490 BranchGroup b = new BranchGroup();
491 b.setCapability( BranchGroup.ALLOW_DETACH );
492 b.addChild( tg );
493
494 tg.addChild( new Sphere( 0.3f, app ) );
495
496 return b;
497 }
498
499 private JPanel createButtons() {
500 JPanel buttonPanel = new JPanel( new GridBagLayout() );
501 GridBagConstraints gb = new GridBagConstraints();
502 gb.gridx = 0;
503 gb.gridy = 0;
504
505 JRadioButton help = new JRadioButton( "Activate help" );
506 help.addActionListener( new ActionListener() {
507 public void actionPerformed( ActionEvent e ) {
508 if ( helpLister.isVisible() ) {
509 helpLister.setVisible( false );
510 ( (JRadioButton) e.getSource() ).setText( "Activate help" );
511 } else {
512 helpLister.setVisible( true );
513 ( (JRadioButton) e.getSource() ).setText( "De-Activate help" );
514
515 }
516 }
517 } );
518 buttonPanel.add( help, gb );
519
520 gb.insets = new Insets( 10, 10, 10, 10 );
521 gb.gridx++;
522 JButton button = new JButton( "Open File" );
523 button.setMnemonic( KeyEvent.VK_O );
524 button.addActionListener( this );
525 buttonPanel.add( button, gb );
526
527 gb.gridx++;
528 button = new JButton( "Export File" );
529 button.setMnemonic( KeyEvent.VK_O );
530 button.addActionListener( this );
531 buttonPanel.add( button, gb );
532
533 return buttonPanel;
534 }
535
536 private void readFile( String fileName ) {
537
538 if ( fileName == null || "".equals( fileName.trim() ) ) {
539 throw new InvalidParameterException( "the file name may not be null or empty" );
540 }
541 fileName = fileName.trim();
542
543 final Open3DFile openFile = new Open3DFile( fileName, this );
544
545 final JDialog dialog = new JDialog( this, "Loading", true );
546
547 dialog.getContentPane().setLayout( new BorderLayout() );
548 dialog.getContentPane().add(
549 new JLabel( "<HTML>Loading file:<br>" + fileName + "<br>Please wait!</HTML>",
550 SwingConstants.CENTER ), BorderLayout.NORTH );
551 final JProgressBar progressBar = new JProgressBar();
552 progressBar.setStringPainted( true );
553 progressBar.setIndeterminate( false );
554 dialog.getContentPane().add( progressBar, BorderLayout.CENTER );
555
556 dialog.pack();
557 dialog.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );
558 dialog.setResizable( false );
559 dialog.setLocationRelativeTo( this );
560
561 final Thread openThread = new Thread() {
562 /**
563 * Opens the file in a separate thread.
564 */
565 @Override
566 public void run() {
567 openFile.openFile( progressBar );
568 if ( dialog.isDisplayable() ) {
569 dialog.setVisible( false );
570 dialog.dispose();
571 }
572 }
573 };
574 openThread.start();
575
576 dialog.setVisible( true );
577 BranchGroup result = openFile.getOpenedFile();
578 //
579 if ( result != null ) {
580 addBranchGroupToScene( result );
581 File f = new File( fileName );
582 setTitle( WIN_TITLE + f.getName() );
583 } else {
584 showExceptionDialog( "The file: " + fileName
585 + " could not be read,\nSee error log for detailed information." );
586 }
587
588 }
589
590 /**
591 * Shows an export dialog to the user.
592 */
593 @SuppressWarnings("unchecked")
594 private void doExport() {
595
596 Export3DFile exportEvaluater = new Export3DFile( this );
597 // find the scene graph to export
598 Enumeration<Node> en = rotationGroup.getAllChildren();
599 BranchGroup toExport = null;
600 if ( en.hasMoreElements() ) {
601 toExport = (BranchGroup) en.nextElement();
602 }
603 if ( toExport == null ) {
604 showExceptionDialog( "Could not get the scene to export." );
605 return;
606 }
607 StringBuilder sb = exportEvaluater.exportBranchgroup( toExport );
608 if ( sb.length() == 0 ) {
609 showExceptionDialog( "Exporting failed, see error log for details." );
610 return;
611 }
612 addBranchGroupToScene( toExport );
613 JFileChooser chooser = createFileChooser( null );
614 int result = chooser.showSaveDialog( this );
615 if ( JFileChooser.APPROVE_OPTION == result ) {
616 File f = chooser.getSelectedFile();
617 FileFilter ff = chooser.getFileFilter();
618 if ( ff instanceof CustomFileFilter ) {
619 prefs.put( LAST_EXTENSION, ( (CustomFileFilter) ff ).getExtension( f ) );
620 prefs.put( OPEN_KEY, f.getParent() );
621 }
622 try {
623 FileWriter output = new FileWriter( f );
624 output.write( sb.toString() );
625 output.flush();
626 output.close();
627 } catch ( IOException e ) {
628 LOG.logError( e.getMessage(), e );
629 showExceptionDialog( "Exporting failed, see error log for details." );
630 }
631
632 }
633 }
634
635 /**
636 * @param errorMessage
637 * to display
638 */
639 public void showExceptionDialog( String errorMessage ) {
640 JOptionPane.showMessageDialog( this, errorMessage );
641 }
642
643 /*
644 * (non-Javadoc)
645 *
646 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
647 */
648 public void actionPerformed( ActionEvent e ) {
649 Object source = e.getSource();
650 if ( source instanceof JButton ) {
651 JButton clicked = (JButton) source;
652 if ( clicked.getText().startsWith( "Export" ) ) {
653 doExport();
654 } else {
655 JFileChooser fileChooser = createFileChooser( supportedOpenFilter );
656 int result = fileChooser.showOpenDialog( this );
657 if ( JFileChooser.APPROVE_OPTION == result ) {
658 File f = fileChooser.getSelectedFile();
659 if ( f != null ) {
660 String path = f.getAbsolutePath();
661 prefs.put( LAST_EXTENSION, ( (CustomFileFilter) fileChooser.getFileFilter() ).getExtension( f ) );
662 prefs.put( OPEN_KEY, f.getParent() );
663 readFile( path );
664 }
665
666 }
667 }
668 }
669 }
670
671 /*
672 * (non-Javadoc)
673 *
674 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
675 */
676 public void keyPressed( KeyEvent arg0 ) {
677 // nottin
678 }
679
680 /*
681 * (non-Javadoc)
682 *
683 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
684 */
685 public void keyReleased( KeyEvent arg0 ) {
686 // nottin
687 }
688
689 /*
690 * (non-Javadoc)
691 *
692 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
693 */
694 public void keyTyped( KeyEvent e ) {
695 double x = 0;
696 double y = 0;
697 double z = 0;
698 if ( e.getKeyChar() == 'q' ) {
699 System.exit( 0 );
700 } else if ( e.getKeyChar() == 'x' ) {
701 x = zoomX;
702 } else if ( e.getKeyChar() == 'X' ) {
703 x = -zoomX;
704 } else if ( e.getKeyChar() == 'y' ) {
705 y = zoomY;
706 } else if ( e.getKeyChar() == 'Y' ) {
707 y = -zoomY;
708 } else if ( e.getKeyChar() == 'z' ) {
709 z = zoomZ;
710 } else if ( e.getKeyChar() == 'Z' ) {
711 z = -zoomZ;
712 }
713
714 TransformGroup viewToWorld = simpleUniverse.getViewingPlatform().getViewPlatformTransform();
715 Transform3D trans = new Transform3D();
716 viewToWorld.getTransform( trans );
717 trans.invert();
718 Vector3d translation = new Vector3d();
719 trans.get( translation );
720
721 x += translation.x;
722 y += translation.y;
723 z += translation.z;
724
725 Point3d eye = new Point3d( x, y, z );
726 trans.lookAt( eye, centroid, upVector );
727 LOG.logDebug( "Trans after:\n" + trans + "\ncentroid: " + centroid );
728 LOG.logDebug( "Center: " + centroid );
729 LOG.logDebug( "eye: " + eye );
730
731 Vector3d dist = new Vector3d( centroid );
732 dist.sub( eye );
733 // trackBall.setSchedulingBounds( new BoundingSphere( centroid, dist.length() ) );
734 viewToWorld.setTransform( trans );
735
736 }
737
738 /**
739 * @param args
740 */
741 public static void main( String[] args ) {
742 View3DFile viewer = new View3DFile( true );
743 viewer.toFront();
744
745 }
746
747 /**
748 *
749 * The <code>CustomFileFilter</code> class adds functionality to the filefilter mechanism of the JFileChooser.
750 *
751 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
752 *
753 * @author last edited by: $Author:$
754 *
755 * @version $Revision:$, $Date:$
756 *
757 */
758 private class CustomFileFilter extends FileFilter {
759
760 private List<String> acceptedExtensions;
761
762 private String desc;
763
764 /**
765 * @param acceptedExtensions
766 * list of extensions this filter accepts.
767 * @param description
768 * to show
769 */
770 CustomFileFilter( List<String> acceptedExtensions, String description ) {
771 this.acceptedExtensions = new ArrayList<String>( acceptedExtensions.size() );
772 StringBuilder sb = new StringBuilder();
773 if ( acceptedExtensions.size() > 0 ) {
774
775 sb.append( "(" );
776 int i = 0;
777 for ( String ext : acceptedExtensions ) {
778 if ( ext.startsWith( "." ) ) {
779 ext = ext.substring( 1 );
780 } else if ( ext.startsWith( "*." ) ) {
781 ext = ext.substring( 2 );
782 } else if ( ext.startsWith( "*" ) ) {
783 ext = ext.substring( 1 );
784 }
785
786 this.acceptedExtensions.add( ext.trim().toUpperCase() );
787 sb.append( "*." );
788 sb.append( ext );
789 if ( ++i < acceptedExtensions.size() ) {
790 sb.append( ", " );
791 }
792 }
793 sb.append( ")" );
794 }
795 sb.append( description );
796 desc = sb.toString();
797 }
798
799 /**
800 * @param extension
801 * @return true if the extension is accepted
802 */
803 public boolean accepts( String extension ) {
804 return extension != null && acceptedExtensions.contains( extension.toUpperCase() );
805 }
806
807 @Override
808 public boolean accept( File pathname ) {
809 if ( pathname.isDirectory() ) {
810 return true;
811 }
812
813 String extension = getExtension( pathname );
814 if ( extension != null ) {
815 if ( acceptedExtensions.contains( extension.trim().toUpperCase() ) ) {
816 return true;
817 }
818 }
819 return false;
820 }
821
822 /**
823 * @param f
824 * @return the file extension (e.g. gml/shp/xml etc.)
825 */
826 String getExtension( File f ) {
827 String ext = null;
828 String s = f.getName();
829 int i = s.lastIndexOf( '.' );
830
831 if ( i > 0 && i < s.length() - 1 ) {
832 ext = s.substring( i + 1 ).toLowerCase();
833 }
834 return ext;
835 }
836
837 @Override
838 public String getDescription() {
839 return desc;
840 }
841 }
842
843 }