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    }