001 //$HeadURL: svn+ssh://mschneider@svn.wald.intevation.org/deegree/base/trunk/resources/eclipse/svn_classfile_header_template.xml $
002 /*---------------- FILE HEADER ------------------------------------------
003 This file is part of deegree.
004 Copyright (C) 2001-2008 by:
005 Department of Geography, University of Bonn
006 http://www.giub.uni-bonn.de/deegree/
007 lat/lon GmbH
008 http://www.lat-lon.de
009
010 This library is free software; you can redistribute it and/or
011 modify it under the terms of the GNU Lesser General Public
012 License as published by the Free Software Foundation; either
013 version 2.1 of the License, or (at your option) any later version.
014 This library is distributed in the hope that it will be useful,
015 but WITHOUT ANY WARRANTY; without even the implied warranty of
016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 Lesser General Public License for more details.
018 You should have received a copy of the GNU Lesser General Public
019 License along with this library; if not, write to the Free Software
020 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021 Contact:
022
023 Andreas Poth
024 lat/lon GmbH
025 Aennchenstr. 19
026 53177 Bonn
027 Germany
028 E-Mail: poth@lat-lon.de
029
030 Prof. Dr. Klaus Greve
031 Department of Geography
032 University of Bonn
033 Meckenheimer Allee 166
034 53115 Bonn
035 Germany
036 E-Mail: greve@giub.uni-bonn.de
037 ---------------------------------------------------------------------------*/
038
039 package org.deegree.tools.app3d;
040
041 import java.awt.BorderLayout;
042 import java.awt.Color;
043 import java.awt.Dimension;
044 import java.awt.FlowLayout;
045 import java.awt.GraphicsConfigTemplate;
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.IOException;
054 import java.net.MalformedURLException;
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.BoundingSphere;
064 import javax.media.j3d.Bounds;
065 import javax.media.j3d.BranchGroup;
066 import javax.media.j3d.Canvas3D;
067 import javax.media.j3d.ColoringAttributes;
068 import javax.media.j3d.DirectionalLight;
069 import javax.media.j3d.GeometryArray;
070 import javax.media.j3d.GraphicsConfigTemplate3D;
071 import javax.media.j3d.Group;
072 import javax.media.j3d.Light;
073 import javax.media.j3d.LineArray;
074 import javax.media.j3d.Material;
075 import javax.media.j3d.PointArray;
076 import javax.media.j3d.PolygonAttributes;
077 import javax.media.j3d.RenderingAttributes;
078 import javax.media.j3d.Shape3D;
079 import javax.media.j3d.Transform3D;
080 import javax.media.j3d.TransformGroup;
081 import javax.media.j3d.View;
082 import javax.swing.JButton;
083 import javax.swing.JFileChooser;
084 import javax.swing.JFrame;
085 import javax.swing.JOptionPane;
086 import javax.swing.JPanel;
087 import javax.swing.filechooser.FileFilter;
088 import javax.vecmath.Color3f;
089 import javax.vecmath.Matrix3d;
090 import javax.vecmath.Point3d;
091 import javax.vecmath.Vector3d;
092 import javax.vecmath.Vector3f;
093 import javax.xml.transform.TransformerException;
094
095 import org.deegree.framework.log.ILogger;
096 import org.deegree.framework.log.LoggerFactory;
097 import org.deegree.framework.xml.XMLFragment;
098 import org.deegree.framework.xml.XMLParsingException;
099 import org.deegree.framework.xml.XSLTDocument;
100 import org.deegree.io.dbaseapi.DBaseException;
101 import org.deegree.io.shpapi.shape_new.ShapeFile;
102 import org.deegree.io.shpapi.shape_new.ShapeFileReader;
103 import org.deegree.model.feature.Feature;
104 import org.deegree.model.feature.FeatureCollection;
105 import org.deegree.model.feature.GMLFeatureCollectionDocument;
106 import org.deegree.model.spatialschema.Curve;
107 import org.deegree.model.spatialschema.CurveSegment;
108 import org.deegree.model.spatialschema.Envelope;
109 import org.deegree.model.spatialschema.Geometry;
110 import org.deegree.model.spatialschema.GeometryException;
111 import org.deegree.model.spatialschema.MultiSurface;
112 import org.deegree.model.spatialschema.Point;
113 import org.deegree.model.spatialschema.Position;
114 import org.deegree.model.spatialschema.Ring;
115 import org.deegree.model.spatialschema.Surface;
116 import org.deegree.ogcbase.CommonNamespaces;
117 import org.jdesktop.j3d.loaders.vrml97.VrmlLoader;
118 import org.w3c.dom.Node;
119 import org.w3c.dom.NodeList;
120 import org.xml.sax.SAXException;
121
122 import com.sun.j3d.loaders.IncorrectFormatException;
123 import com.sun.j3d.loaders.ParsingErrorException;
124 import com.sun.j3d.loaders.Scene;
125 import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
126 import com.sun.j3d.utils.geometry.ColorCube;
127 import com.sun.j3d.utils.geometry.GeometryInfo;
128 import com.sun.j3d.utils.geometry.NormalGenerator;
129 import com.sun.j3d.utils.universe.SimpleUniverse;
130
131 /**
132 * The <code>View3DFile</code> class can display shape and gml/citygml file in 3D.
133 *
134 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
135 *
136 * @author last edited by: $Author:$
137 *
138 * @version $Revision:$, $Date:$
139 *
140 */
141
142 public class View3DFile extends JFrame implements ActionListener, KeyListener {
143 /**
144 *
145 */
146 private static final long serialVersionUID = 7698388852544865855L;
147
148 private static ILogger LOG = LoggerFactory.getLogger( View3DFile.class );
149
150 private SimpleUniverse simpleUniverse;
151
152 // private JCanvas3D canvas;
153 // private TrackBall trackBall;
154
155 private Canvas3D canvas;
156
157 private MouseRotate trackBall;
158
159 private BranchGroup scene;
160
161 private TransformGroup rotationGroup;
162
163 private Light firstLight, secondLight, thirdLight;
164
165 private Point3d centroid;
166
167 private JFileChooser fileChooser;
168
169 private Preferences prefs;
170
171 private final static String PREF_KEY = "lastlocation";
172
173 private final static String WIN_TITLE = "Deegree 3D Object viewer: ";
174
175 private Background backGround;
176
177 /**
178 * Creates a frame with the menus and the canvas3d set and tries to load the file from given location.
179 *
180 * @param fileName
181 * to be loaded.
182 * @throws DBaseException
183 * @throws IOException
184 */
185 public View3DFile( String fileName ) {
186 this( false );
187 readFile( fileName );
188 }
189
190 /**
191 * Creates a new frame with the menus and the canvas3d set.
192 *
193 * @param testSphere
194 * true if a sphere should be displayed.
195 */
196 public View3DFile( boolean testSphere ) {
197 super( WIN_TITLE );
198
199 setupGUI();
200
201 setupFileChooser();
202
203 setupJava3D( testSphere );
204
205 pack();
206 }
207
208 /**
209 * GUI stuff
210 */
211 private void setupGUI() {
212 // add listener for closing the frame/application
213 addWindowListener( new WindowAdapter() {
214 @Override
215 public void windowClosing( WindowEvent evt ) {
216 System.exit( 0 );
217 }
218 } );
219 setLayout( new BorderLayout() );
220 setMinimumSize( new Dimension( 400, 400 ) );
221 setPreferredSize( new Dimension( 400, 400 ) );
222 setVisible( true );
223 // Adding the button panel
224 JPanel buttonPanel = new JPanel( new FlowLayout() );
225 createButtons( buttonPanel );
226 getContentPane().add( buttonPanel, BorderLayout.SOUTH );
227 addKeyListener( this );
228
229 }
230
231 private void setupFileChooser() {
232 // Setting up the fileChooser.
233 prefs = Preferences.userNodeForPackage( View3DFile.class );
234 String lastLoc = prefs.get( PREF_KEY, System.getProperty( "user.home" ) );
235 File lastFile = new File( lastLoc );
236 if ( !lastFile.exists() ) {
237 lastFile = new File( System.getProperty( "user.home" ) );
238 }
239 fileChooser = new JFileChooser( lastFile );
240
241 ArrayList<String> extensions = new ArrayList<String>();
242 extensions.add( "gml" );
243 extensions.add( "xml" );
244 CustomFileFilter fileFilter = new CustomFileFilter( extensions, "(*.gml, *.xml) GML or CityGML-Files" );
245 fileChooser.setFileFilter( fileFilter );
246
247 extensions.clear();
248 extensions.add( "shp" );
249 fileFilter = new CustomFileFilter( extensions, "(*.shp) Esri ShapeFiles" );
250 fileChooser.setFileFilter( fileFilter );
251
252 extensions.clear();
253 extensions.add( "vrml" );
254 extensions.add( "wrl" );
255 fileFilter = new CustomFileFilter( extensions, "(*.vrml, *.wrl) VRML97 - Virtual Reality Modelling Language" );
256 fileChooser.setFileFilter( fileFilter );
257
258 // The *.* filter is off.
259 fileChooser.setAcceptAllFileFilterUsed( false );
260
261 fileChooser.setMultiSelectionEnabled( false );
262 }
263
264 private void setupJava3D( boolean testSphere ) {
265 // setting up Java3D
266 GraphicsConfigTemplate3D configTemplate = new GraphicsConfigTemplate3D();
267 configTemplate.setSceneAntialiasing( GraphicsConfigTemplate.PREFERRED );
268 configTemplate.setDoubleBuffer( GraphicsConfigTemplate.REQUIRED );
269 canvas = new Canvas3D( SimpleUniverse.getPreferredConfiguration() );
270 simpleUniverse = new SimpleUniverse( canvas );
271 if ( canvas != null ) {
272 getContentPane().add( canvas, BorderLayout.CENTER );
273 }
274
275 View view = simpleUniverse.getViewer().getView();
276
277 // view parameters
278 view.setBackClipDistance( 10000 );
279 view.setFrontClipDistance( 0.1 );
280 view.setWindowEyepointPolicy( View.RELATIVE_TO_FIELD_OF_VIEW );
281 view.setSceneAntialiasingEnable( true );
282
283 centroid = new Point3d();
284 scene = new BranchGroup();
285 firstLight = createDirectionalLight( new Vector3f( 0, 0, 1 ) );
286 secondLight = createDirectionalLight( new Vector3f( 0, -1, -1 ) );
287 thirdLight = createDirectionalLight( new Vector3f( -1, 0, 0 ) );
288
289 scene.addChild( firstLight );
290 scene.addChild( secondLight );
291 scene.addChild( thirdLight );
292
293 // is handled by the mouse rotater, all objects will be added to it.
294 rotationGroup = new TransformGroup();
295 rotationGroup.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE );
296 rotationGroup.setCapability( TransformGroup.ALLOW_TRANSFORM_READ );
297 rotationGroup.setCapability( BranchGroup.ALLOW_DETACH );
298 rotationGroup.setCapability( Group.ALLOW_CHILDREN_EXTEND );
299 rotationGroup.setCapability( Group.ALLOW_CHILDREN_READ );
300 rotationGroup.setCapability( Group.ALLOW_CHILDREN_WRITE );
301 scene.addChild( rotationGroup );
302
303 backGround = new Background ( new Color3f( Color.LIGHT_GRAY ) );
304 backGround.setCapability( Background.ALLOW_BOUNDS_WRITE );
305 backGround.setCapability( Background.ALLOW_BOUNDS_READ );
306 backGround.setCapability( Background.ALLOW_APPLICATION_BOUNDS_READ);
307 backGround.setCapability( Background.ALLOW_APPLICATION_BOUNDS_WRITE);
308
309 scene.addChild( backGround );
310
311 trackBall = new MouseRotate();
312 trackBall.setTransformGroup( rotationGroup );
313 trackBall.setSchedulingBounds( new BoundingSphere() );
314 scene.addChild( trackBall );
315
316 simpleUniverse.addBranchGraph( scene );
317
318 // adding the key listeners
319 canvas.addKeyListener( this );
320
321 if ( testSphere ) {
322 BranchGroup sphere = createJ3DSphere( new Point3d( 0, 0, 0 ) );
323 addBranchGroupToScene( sphere );
324 }
325 }
326
327 /**
328 * Create a directional light, with color.WHITE.
329 */
330 private DirectionalLight createDirectionalLight( Vector3f lightDir ) {
331 // create the color for the light
332 Color3f color = new Color3f( Color.WHITE );
333 // create the directional light with the color and direction
334 DirectionalLight light = new DirectionalLight( color, lightDir );
335 light.setCapability( Light.ALLOW_INFLUENCING_BOUNDS_READ );
336 light.setCapability( Light.ALLOW_INFLUENCING_BOUNDS_WRITE );
337 return light;
338 }
339
340 private void addBranchGroupToScene( BranchGroup b ) {
341 LOG.logInfo( "Setting the branchgroup to : " + b.getName() );
342 rotationGroup.removeAllChildren();
343 // translationGroup.removeAllChildren();
344 // System.out.println( b.getBounds() );
345 Bounds bounds = b.getBounds();
346 if ( bounds != null ) {
347
348 LOG.logDebug( "Old centroid: " + centroid );
349 BoundingSphere bs = new BoundingSphere( bounds );
350 bs.getCenter( centroid );
351 LOG.logDebug( "New centroid: " + centroid );
352
353 double radius = bs.getRadius();
354
355 View view = simpleUniverse.getViewer().getView();
356 // view parameters
357 view.setBackClipDistance( radius * 10 );
358 // the near clippingplane is one hundereth of the far.
359 view.setFrontClipDistance( ( radius * 4 ) * 0.001 );
360
361 TransformGroup viewToWorld = simpleUniverse.getViewingPlatform().getViewPlatformTransform();
362 Transform3D trans = new Transform3D();
363 trans.lookAt( new Point3d( centroid.x,centroid.y, centroid.z -(radius*2) ), centroid, new Vector3d( 0, 1, 0 ) );
364 LOG.logDebug( "Trans Matrix after lookat:\n" + trans );
365 viewToWorld.setTransform( trans );
366
367 LOG.logDebug( "Center: " + centroid );
368 LOG.logDebug( "radius: " + bs.getRadius() );
369
370 firstLight.setInfluencingBounds( new BoundingSphere( centroid, radius * 100 ) );
371 secondLight.setInfluencingBounds( new BoundingSphere( centroid, radius * 100 ) );
372 thirdLight.setInfluencingBounds( new BoundingSphere( centroid, radius * 100 ) );
373 trackBall.setSchedulingBounds( new BoundingSphere( centroid, radius * 60 ) );
374 backGround.setApplicationBounds( new BoundingSphere( centroid, radius * 100 ) );
375 }
376 rotationGroup.addChild( b );
377 }
378
379 /**
380 * @return a brand new sphere
381 */
382 private BranchGroup createJ3DSphere( Point3d translation ) {
383 Appearance app = new Appearance();
384 RenderingAttributes ra = new RenderingAttributes();
385 ra.setDepthBufferEnable( true );
386 ra.setDepthBufferWriteEnable( true );
387 app.setRenderingAttributes( ra );
388
389 ColoringAttributes ca = new ColoringAttributes();
390 ca.setShadeModel( ColoringAttributes.SHADE_GOURAUD );
391 ca.setCapability( ColoringAttributes.NICEST );
392 app.setColoringAttributes( ca );
393
394 Material material = new Material();
395 material.setAmbientColor( new Color3f( Color.WHITE ) );
396 material.setDiffuseColor( new Color3f( Color.RED ) );
397 material.setSpecularColor( new Color3f( Color.BLUE ) );
398 app.setMaterial( material );
399 TransformGroup tg = new TransformGroup();
400 Transform3D trans = new Transform3D();
401 if ( translation != null ) {
402 trans.setTranslation( new Vector3d( translation ) );
403 tg.setTransform( trans );
404 }
405
406 BranchGroup b = new BranchGroup();
407 b.setCapability( BranchGroup.ALLOW_DETACH );
408 b.addChild( tg );
409
410 // tg.addChild( new Sphere( 0.2f, app ) );
411 tg.addChild( new ColorCube( 0.2f ) );
412 return b;
413 }
414
415 private void createButtons( JPanel buttonPanel ) {
416 JButton button = new JButton( "Open File" );
417 button.setMnemonic( KeyEvent.VK_O );
418 button.addActionListener( this );
419 buttonPanel.add( button, FlowLayout.LEFT );
420 }
421
422 private void readFile( String fileName ) {
423
424 if ( fileName == null || "".equals( fileName.trim() ) ) {
425 throw new InvalidParameterException( "the file name may not be null or empty" );
426 }
427 fileName = fileName.trim();
428
429 FeatureCollection fc = null;
430 if ( fileName.toUpperCase().endsWith( ".SHP" ) ) {
431 // File f = new File( fileName );
432 try {
433 ShapeFile file = new ShapeFileReader( fileName ).read();
434 fc = file.getFeatureCollection();
435 } catch ( IOException e ) {
436 LOG.logError( "Could not open shape file: " + fileName + " because: " + e.getMessage() );
437 return;
438 } catch ( DBaseException e ) {
439 LOG.logError( "Could not open shape file: " + fileName + " because: " + e.getMessage() );
440 return;
441 }
442 } else if ( fileName.toUpperCase().endsWith( ".XML" ) || fileName.toUpperCase().endsWith( ".GML" ) ) {
443 try {
444 XMLFragment doc = new XMLFragment( new File( fileName ) );
445 boolean isCityGML = ( doc.getRootElement()
446 .getOwnerDocument()
447 .lookupPrefix( CommonNamespaces.CITYGMLNS.toASCIIString() ) != null ) || CommonNamespaces.CITYGMLNS.toASCIIString()
448 .equals( doc.getRootElement()
449 .getOwnerDocument()
450 .lookupNamespaceURI( "" ) );
451
452 if ( !isCityGML ) {
453 isCityGML = isCityGMLDefined( doc.getRootElement() );
454 }
455 LOG.logInfo( "The xmlfile " + ( ( isCityGML ) ? "contains" : "does not contain" ) + " Citygml" );
456 if ( isCityGML ) {
457 // convert to gml
458 XSLTDocument transformer = new XSLTDocument( View3DFile.class.getResource( "toShape.xsl" ) );
459 doc = transformer.transform( doc );
460 System.out.println( "outgoingdoc: \n " + doc.getAsPrettyString() );
461 }
462 GMLFeatureCollectionDocument gmlDoc = new GMLFeatureCollectionDocument();
463 gmlDoc.setRootElement( doc.getRootElement() );
464 fc = gmlDoc.parse();
465 } catch ( SAXException e ) {
466 LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
467 return;
468 } catch ( TransformerException e ) {
469 LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
470 return;
471 } catch ( XMLParsingException e ) {
472 LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
473 return;
474 } catch ( MalformedURLException e ) {
475 LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
476 return;
477 } catch ( IOException e ) {
478 LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
479 return;
480 }
481 } else if ( fileName.toUpperCase().endsWith( ".WRL" ) || fileName.toUpperCase().endsWith( ".VRML" ) ) {
482 VrmlLoader loader = new VrmlLoader();
483 try {
484 Scene scene = loader.load( fileName );
485 if ( scene != null ) {
486 BranchGroup bg = scene.getSceneGroup();
487 BranchGroup result = new BranchGroup();
488 result.setCapability( BranchGroup.ALLOW_DETACH );
489 for( int i = 0; i< bg.numChildren(); ++i ){
490 removeTransformGroup( bg.getChild( i ), result );
491 }
492 LOG.logDebug( "Loaded branchgroup: " + bg.getName() );
493 addBranchGroupToScene( result );
494 } else {
495 JOptionPane.showMessageDialog( this, "Could not create scene from file: " + fileName );
496 }
497 // } catch ( FileNotFoundException e ) {
498 // LOG.logError( "Error while loading vrml from file: " + fileName, e );
499 // JOptionPane.showMessageDialog( this, "Could not create scene from file: " + fileName
500 // + " because: "
501 // + e.getMessage() );
502 } catch ( IncorrectFormatException e ) {
503 LOG.logError( "Error while loading vrml from file: " + fileName, e );
504 JOptionPane.showMessageDialog( this, "Could not create scene from file: " + fileName
505 + " because: "
506 + e.getMessage() );
507 } catch ( ParsingErrorException e ) {
508 LOG.logError( "Error while loading vrml from file: " + fileName, e );
509 JOptionPane.showMessageDialog( this, "Could not create scene from file: " + fileName
510 + " because: "
511 + e.getMessage() );
512 } catch ( Exception e ) {
513 LOG.logError( "Error while loading vrml from file: " + fileName, e );
514 JOptionPane.showMessageDialog( this, "Could not create scene from file: " + fileName
515 + " because: "
516 + e.getMessage() );
517 } catch ( Throwable e ) {
518 LOG.logError( "Error while loading vrml from file: " + fileName, e );
519 JOptionPane.showMessageDialog( this, "Could not create scene from file: " + fileName
520 + " because: "
521 + e.getMessage() );
522 }
523 }
524 if ( fc != null ) {
525 BranchGroup bg = new BranchGroup();
526 bg.setCapability( BranchGroup.ALLOW_DETACH );
527
528 Appearance app = new Appearance();
529 RenderingAttributes ra = new RenderingAttributes();
530 ra.setDepthBufferEnable( true );
531 app.setRenderingAttributes( ra );
532 Material material = new Material();
533 material.setAmbientColor( new Color3f( Color.WHITE ) );
534 material.setDiffuseColor( new Color3f( Color.RED ) );
535 material.setSpecularColor( new Color3f( Color.BLUE ) );
536 PolygonAttributes pa = new PolygonAttributes();
537 pa.setCullFace( PolygonAttributes.CULL_NONE);
538 pa.setBackFaceNormalFlip( true );
539 pa.setPolygonMode( PolygonAttributes.POLYGON_FILL );
540 app.setPolygonAttributes( pa );
541 app.setMaterial( material );
542 Envelope bbox = null;
543 for ( int i = 0; i < fc.size(); ++i ) {
544 Feature f = fc.getFeature( i );
545 Geometry geom = f.getDefaultGeometryPropertyValue();
546 if ( bbox == null ) {
547 bbox = geom.getEnvelope();
548 } else {
549 try {
550 bbox = bbox.merge( geom.getEnvelope() );
551 LOG.logDebug( "merging the bboxes resulted in: " + bbox );
552 } catch ( GeometryException e ) {
553 LOG.logError( "Couldn't merge the bboxes" );
554 e.printStackTrace();
555 }
556 }
557 }
558 Point3d centroid = new Point3d( 0, 0, 0 );
559 if ( bbox != null ) {
560 Point p = bbox.getCentroid();
561 double zValue = p.getZ();
562 if ( Double.isInfinite( zValue ) || Double.isNaN( zValue ) ) {
563 zValue = 0;
564 }
565 centroid.set( -p.getX(), -p.getY(), -zValue );
566 }
567 for ( int i = 0; i < fc.size(); ++i ) {
568 Feature f = fc.getFeature( i );
569 Geometry geom = f.getDefaultGeometryPropertyValue();
570 Shape3D shape = mapGeometryToShape3D( geom, centroid );
571 if ( shape != null ) {
572 shape.setAppearance( app );
573 bg.addChild( shape );
574 } else {
575 System.out.println( "ERRORORORORORORO" );
576 }
577 }
578 Enumeration en = bg.getAllChildren();
579 if ( en.hasMoreElements() ) {
580 addBranchGroupToScene( bg );
581 } else {
582 LOG.logError( "Could not read any 3D-Info from the location: " + fileName );
583 }
584 }
585 File f = new File( fileName );
586 setTitle( WIN_TITLE + f.getName() );
587 }
588
589 private void removeTransformGroup( javax.media.j3d.Node trans, BranchGroup result ){
590 if( trans instanceof Group ){
591 for( int i = 0; i< ((Group)trans).numChildren(); ++i ){
592 javax.media.j3d.Node n = ((Group)trans).getChild( i );
593 if( n instanceof TransformGroup ){
594 Transform3D t = new Transform3D( );
595 ((TransformGroup)n).getTransform( t );
596 LOG.logDebug( "Setting old transform: " + t );
597 Matrix3d id = new Matrix3d();
598 id.setIdentity();
599 t.setRotation( id );
600 ((TransformGroup)n).setTransform( t );
601 LOG.logDebug( "To new transform: " + t );
602 }
603 removeTransformGroup( n, result );
604 }
605 } else {
606 result.addChild( trans.cloneNode( true ) );
607 }
608 }
609
610
611 /**
612 * @param contextNode
613 * @return true if the namespace "http://www.citygml.org/citygml/1/0/0" was found in one of the nodes of the
614 * dom-tree.
615 */
616 private boolean isCityGMLDefined( Node contextNode ) {
617
618 boolean isCityGML = ( contextNode.lookupPrefix( CommonNamespaces.CITYGMLNS.toASCIIString() ) != null ) || CommonNamespaces.CITYGMLNS.toASCIIString()
619 .equals( contextNode.lookupNamespaceURI( null ) );
620 if ( !isCityGML ) {
621 NodeList nl = contextNode.getChildNodes();
622 for ( int i = 0; i < nl.getLength(); ++i ) {
623 isCityGML = isCityGMLDefined( nl.item( i ) );
624 if ( isCityGML ) {
625 return true;
626 }
627 }
628 }
629 return isCityGML;
630 }
631
632 private Shape3D mapGeometryToShape3D( Geometry geom, Point3d translation ) {
633 if ( geom instanceof Point ) {
634 return createShape3D( (Point) geom, translation );
635 } else if ( geom instanceof Curve ) {
636 return createShape3D( (Curve) geom, translation );
637 } else if ( geom instanceof Surface ) {
638 return createShape3D( (Surface) geom, translation );
639 } else if ( geom instanceof MultiSurface ) {
640 return createShape3D( (MultiSurface) geom, translation );
641 } else {
642 if ( geom == null ) {
643 LOG.logError( "Could not map the geometry which was not instantiated" );
644 } else {
645 LOG.logError( "Could not map the geometry: " + geom.getClass().getName() );
646 }
647 return null;
648 }
649
650 // if ( geom instanceof MultiPoint ) {
651 // return new ShapeMultiPoint( (MultiPoint) g );
652 // }
653 //
654 // if ( geom instanceof MultiCurve ) {
655 // List<Curve> cs = Arrays.asList( ( (MultiCurve) g ).getAllCurves() );
656 // return new ShapePolyline( cs );
657 // }
658 //
659
660 }
661
662 private Shape3D createShape3D( Point p, Point3d translation ) {
663 GeometryArray geomArray = new PointArray( 1, GeometryArray.COORDINATES );
664 double z = p.getZ();
665 if ( Double.isInfinite( z ) || Double.isNaN( z ) ) {
666 z = 0;
667 }
668 geomArray.setCoordinate( 0, new Point3d( p.getX() + translation.x, p.getY() + translation.y, z + translation.z ) );
669 Shape3D result = new Shape3D( geomArray );
670 result.setAppearanceOverrideEnable( true );
671 return result;
672 }
673
674 private Shape3D createShape3D( Curve c, Point3d translation ) {
675 int totalPoints = 0;
676 List<Integer> failSegments = new ArrayList<Integer>();
677 for ( int i = 0; i < c.getNumberOfCurveSegments(); ++i ) {
678 try {
679 totalPoints += c.getCurveSegmentAt( i ).getNumberOfPoints();
680 } catch ( GeometryException e ) {
681 LOG.logError( "Could not get CurveSegment at position: " + i );
682 failSegments.add( new Integer( i ) );
683 }
684 }
685
686 LineArray geomArray = new LineArray( totalPoints, GeometryArray.COORDINATES );
687 for ( int i = 0, pointCounter = 0; i < c.getNumberOfCurveSegments(); ++i ) {
688 if ( !failSegments.contains( new Integer( i ) ) ) {
689 CurveSegment segment = null;
690 try {
691 segment = c.getCurveSegmentAt( i );
692 } catch ( GeometryException e ) {
693 // cannot happen.
694 }
695 for ( int k = 0; k < segment.getNumberOfPoints(); ++k ) {
696 Position p = segment.getPositionAt( k );
697 double z = p.getZ();
698 if ( Double.isInfinite( z ) || Double.isNaN( z ) ) {
699 z = 0;
700 }
701 geomArray.setCoordinate( pointCounter++, new Point3d( p.getX() + translation.x,
702 p.getY() + translation.y,
703 z + translation.z ) );
704 }
705 }
706 }
707 Shape3D result = new Shape3D( geomArray );
708 result.setAppearanceOverrideEnable( true );
709 return result;
710 }
711
712 /**
713 *
714 * @param surface
715 * to be created
716 * @param translation
717 * to origin of the scene
718 * @return a Shape3D created from the surface.
719 */
720 private Shape3D createShape3D( Surface surface, Point3d translation ) {
721 GeometryInfo geometryInfo = new GeometryInfo( GeometryInfo.POLYGON_ARRAY );
722
723 Position[] pos = surface.getSurfaceBoundary().getExteriorRing().getPositions();
724 Ring[] innerRings = surface.getSurfaceBoundary().getInteriorRings();
725 int numberOfRings = 1;
726 int numberOfCoordinates = 3 * ( pos.length );
727 if ( innerRings != null ) {
728 for ( int i = 0; i < innerRings.length; i++ ) {
729 numberOfRings++;
730 numberOfCoordinates += ( 3 * innerRings[i].getPositions().length );
731 }
732 }
733
734 float[] coords = new float[numberOfCoordinates];
735 int contourCounts[] = { numberOfRings };
736 int[] stripCounts = new int[numberOfRings];
737 numberOfRings = 0;
738 stripCounts[numberOfRings++] = pos.length;
739
740 int z = 0;
741 for ( int i = 0; i < pos.length; i++ ) {
742 double zValue = pos[i].getZ();
743 if ( Double.isInfinite( zValue ) || Double.isNaN( zValue ) ) {
744 zValue = 0;
745 }
746 // LOG.logDebug( "Found a point in a surface: " + pos[i] );
747 coords[z++] = (float) ( pos[i].getX() + translation.x );
748 coords[z++] = (float) ( pos[i].getY() + translation.y );
749 coords[z++] = (float) ( zValue + translation.z );
750 }
751
752 if ( innerRings != null ) {
753 for ( int j = 0; j < innerRings.length; j++ ) {
754 pos = innerRings[j].getPositions();
755 stripCounts[numberOfRings++] = pos.length;
756 for ( int i = 0; i < pos.length; i++ ) {
757 double zValue = pos[i].getZ();
758 if ( Double.isInfinite( zValue ) || Double.isNaN( zValue ) ) {
759 zValue = 0;
760 }
761 coords[z++] = (float) ( pos[i].getX() + translation.x );
762 coords[z++] = (float) ( pos[i].getY() + translation.y );
763 coords[z++] = (float) ( zValue + translation.z );
764 }
765 }
766 }
767
768 geometryInfo.setCoordinates( coords );
769 geometryInfo.setStripCounts( stripCounts );
770 geometryInfo.setContourCounts( contourCounts );
771 geometryInfo.recomputeIndices();
772
773 NormalGenerator ng = new NormalGenerator();
774 ng.generateNormals( geometryInfo );
775 Shape3D result = new Shape3D( geometryInfo.getGeometryArray() );
776 result.setCapability( Shape3D.ALLOW_GEOMETRY_READ );
777 result.setCapability( Shape3D.ALLOW_GEOMETRY_WRITE );
778 result.setAppearanceOverrideEnable( true );
779 return result;
780 }
781
782 /**
783 * @param surface
784 * @return a Shape3D created from the multisurfaces.
785 */
786 private Shape3D createShape3D( MultiSurface multiSurface, Point3d translation ) {
787 Shape3D result = new Shape3D();
788 result.setCapability( Shape3D.ALLOW_GEOMETRY_READ );
789 result.setCapability( Shape3D.ALLOW_GEOMETRY_WRITE );
790 Surface[] allSurfaces = multiSurface.getAllSurfaces();
791 for ( int surfaceCount = 0; surfaceCount < allSurfaces.length; ++surfaceCount ) {
792 Surface surface = multiSurface.getSurfaceAt( surfaceCount );
793 Shape3D s3D = createShape3D( surface, translation );
794 result.addGeometry( s3D.getGeometry() );
795 }
796 result.setAppearanceOverrideEnable( true );
797 return result;
798 }
799
800 /*
801 * (non-Javadoc)
802 *
803 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
804 */
805 public void actionPerformed( ActionEvent e ) {
806 Object source = e.getSource();
807 if ( source instanceof JButton ) {
808 // JFileChooser filechooser = new JFileChooser();
809 // filechooser.setVisible( true );
810 int result = fileChooser.showOpenDialog( this );
811 if ( JFileChooser.APPROVE_OPTION == result ) {
812 File f = fileChooser.getSelectedFile();
813 if ( f != null ) {
814 String path = f.getAbsolutePath();
815 String dirpath = f.getParent();
816 System.out.println( "absolute Path: " + dirpath );
817 prefs.put( PREF_KEY, dirpath );
818 readFile( path );
819 }
820
821 }
822 }
823 }
824
825 /*
826 * (non-Javadoc)
827 *
828 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
829 */
830 public void keyPressed( KeyEvent arg0 ) {
831 // nottin
832 }
833
834 /*
835 * (non-Javadoc)
836 *
837 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
838 */
839 public void keyReleased( KeyEvent arg0 ) {
840 // nottin
841 }
842
843 /*
844 * (non-Javadoc)
845 *
846 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
847 */
848 public void keyTyped( KeyEvent e ) {
849 double x = 0;
850 double y = 0;
851 double z = 0;
852 if ( e.getKeyChar() == 'q' ) {
853 System.exit( 0 );
854 } else if ( e.getKeyChar() == 'x' ) {
855 x = 1;
856 } else if ( e.getKeyChar() == 'X' ) {
857 x = -1;
858 } else if ( e.getKeyChar() == 'y' ) {
859 y = 1;
860 } else if ( e.getKeyChar() == 'Y' ) {
861 y = -1;
862 } else if ( e.getKeyChar() == 'z' ) {
863 z = 1;
864 } else if ( e.getKeyChar() == 'Z' ) {
865 z = -1;
866 }
867
868 TransformGroup viewToWorld = simpleUniverse.getViewingPlatform().getViewPlatformTransform();
869 Transform3D trans = new Transform3D();
870 viewToWorld.getTransform( trans );
871 trans.invert();
872 Vector3d translation = new Vector3d();
873 trans.get( translation );
874
875 x += translation.x;
876 y += translation.y;
877 z += translation.z;
878 Point3d eye = new Point3d( x, y, z );
879 trans.lookAt( eye, centroid, new Vector3d( 0, 1, 0 ) );
880 LOG.logDebug( "Trans after:\n" + trans + "\ncentroid: " + centroid );
881 Vector3d dist = new Vector3d( centroid );
882 dist.sub( eye );
883 trackBall.setSchedulingBounds( new BoundingSphere( centroid, dist.length() ) );
884 viewToWorld.setTransform( trans );
885
886 }
887
888 /**
889 * @param args
890 */
891 public static void main( String[] args ) {
892
893 View3DFile viewer = new View3DFile( "/tmp/test.xml" );
894 viewer.toFront();
895 //View3DFile viewer = new View3DFile( true );
896 // viewer.toFront();
897
898 }
899
900 /**
901 *
902 * The <code>CustomFileFilter</code> class adds functionality to the filefilter mechanism of the JFileChooser.
903 *
904 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
905 *
906 * @author last edited by: $Author:$
907 *
908 * @version $Revision:$, $Date:$
909 *
910 */
911 private class CustomFileFilter extends FileFilter {
912
913 private List<String> acceptedExtensions;
914
915 private String desc;
916
917 /**
918 * @param acceptedExtensions
919 * list of extensions this filter accepts.
920 */
921 CustomFileFilter( List<String> acceptedExtensions, String description ) {
922 this.acceptedExtensions = new ArrayList<String>( acceptedExtensions.size() );
923 for ( String s : acceptedExtensions ) {
924 if ( s.startsWith( "." ) ) {
925 s = s.substring( 1 );
926 }
927 this.acceptedExtensions.add( s.trim().toUpperCase() );
928 }
929 desc = description;
930 }
931
932 @Override
933 public boolean accept( File pathname ) {
934 if ( pathname.isDirectory() ) {
935 return true;
936 }
937
938 String extension = getExtension( pathname );
939 if ( extension != null ) {
940 if ( acceptedExtensions.contains( extension.trim().toUpperCase() ) ) {
941 return true;
942 }
943 }
944 return false;
945 }
946
947 private String getExtension( File f ) {
948 String ext = null;
949 String s = f.getName();
950 int i = s.lastIndexOf( '.' );
951
952 if ( i > 0 && i < s.length() - 1 ) {
953 ext = s.substring( i + 1 ).toLowerCase();
954 }
955 return ext;
956 }
957
958 @Override
959 public String getDescription() {
960 return desc;
961 }
962 }
963 }