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-2007 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.BoundingSphere;
063    import javax.media.j3d.Bounds;
064    import javax.media.j3d.BranchGroup;
065    import javax.media.j3d.Canvas3D;
066    import javax.media.j3d.ColoringAttributes;
067    import javax.media.j3d.DirectionalLight;
068    import javax.media.j3d.GeometryArray;
069    import javax.media.j3d.GraphicsConfigTemplate3D;
070    import javax.media.j3d.Group;
071    import javax.media.j3d.Light;
072    import javax.media.j3d.LineArray;
073    import javax.media.j3d.Material;
074    import javax.media.j3d.PointArray;
075    import javax.media.j3d.PolygonAttributes;
076    import javax.media.j3d.RenderingAttributes;
077    import javax.media.j3d.Shape3D;
078    import javax.media.j3d.Transform3D;
079    import javax.media.j3d.TransformGroup;
080    import javax.media.j3d.View;
081    import javax.swing.JButton;
082    import javax.swing.JFileChooser;
083    import javax.swing.JFrame;
084    import javax.swing.JPanel;
085    import javax.swing.filechooser.FileFilter;
086    import javax.vecmath.Color3f;
087    import javax.vecmath.Point3d;
088    import javax.vecmath.Vector3d;
089    import javax.vecmath.Vector3f;
090    import javax.xml.transform.TransformerException;
091    
092    import org.deegree.framework.log.ILogger;
093    import org.deegree.framework.log.LoggerFactory;
094    import org.deegree.framework.xml.XMLFragment;
095    import org.deegree.framework.xml.XMLParsingException;
096    import org.deegree.framework.xml.XSLTDocument;
097    import org.deegree.io.dbaseapi.DBaseException;
098    import org.deegree.io.shpapi.shape_new.ShapeFile;
099    import org.deegree.io.shpapi.shape_new.ShapeFileReader;
100    import org.deegree.model.feature.Feature;
101    import org.deegree.model.feature.FeatureCollection;
102    import org.deegree.model.feature.GMLFeatureCollectionDocument;
103    import org.deegree.model.spatialschema.Curve;
104    import org.deegree.model.spatialschema.CurveSegment;
105    import org.deegree.model.spatialschema.Envelope;
106    import org.deegree.model.spatialschema.Geometry;
107    import org.deegree.model.spatialschema.GeometryException;
108    import org.deegree.model.spatialschema.MultiSurface;
109    import org.deegree.model.spatialschema.Point;
110    import org.deegree.model.spatialschema.Position;
111    import org.deegree.model.spatialschema.Ring;
112    import org.deegree.model.spatialschema.Surface;
113    import org.deegree.ogcbase.CommonNamespaces;
114    import org.w3c.dom.Node;
115    import org.w3c.dom.NodeList;
116    import org.xml.sax.SAXException;
117    
118    import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
119    import com.sun.j3d.utils.geometry.ColorCube;
120    import com.sun.j3d.utils.geometry.GeometryInfo;
121    import com.sun.j3d.utils.geometry.NormalGenerator;
122    import com.sun.j3d.utils.universe.SimpleUniverse;
123    
124    /**
125     * The <code>View3DFile</code> class can display shape and gml/citygml file in 3D.
126     * 
127     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
128     * 
129     * @author last edited by: $Author:$
130     * 
131     * @version $Revision:$, $Date:$
132     * 
133     */
134    
135    public class View3DFile extends JFrame implements ActionListener, KeyListener {
136        /**
137         * 
138         */
139        private static final long serialVersionUID = 7698388852544865855L;
140    
141        private static ILogger LOG = LoggerFactory.getLogger( View3DFile.class );
142    
143        private SimpleUniverse simpleUniverse;
144    
145        // private JCanvas3D canvas;
146        // private TrackBall trackBall;
147    
148        private Canvas3D canvas;
149    
150        private MouseRotate trackBall;
151    
152        private BranchGroup scene;
153    
154        private TransformGroup rotationGroup;
155    
156        private Light firstLight, secondLight, thirdLight;
157        
158        private Point3d centroid;
159        
160        private JFileChooser fileChooser;
161        
162        private Preferences prefs;
163        private final static  String PREF_KEY = "lastlocation";
164        private final static String WIN_TITLE = "Deegree 3D Object viewer: ";
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         * @throws DBaseException
172         * @throws IOException
173         */
174        public View3DFile( String fileName ){
175            this( false );
176            readFile( fileName );
177        }
178    
179        /**
180         * Creates a new frame with the menus and the canvas3d set.
181         * @param testSphere true if a sphere should be displayed.
182         */
183        public View3DFile( boolean testSphere ) {
184            super( WIN_TITLE );
185    
186            // add listener for closing the frame/application
187            addWindowListener( new WindowAdapter() {
188                @Override
189                public void windowClosing( WindowEvent evt ) {
190                    System.exit( 0 );
191                }
192            } );
193            setLayout( new BorderLayout() );
194            setMinimumSize( new Dimension( 400, 400 ) );
195            setPreferredSize( new Dimension( 400, 400 ) );
196            setVisible( true );
197    
198            //Setting up the fileChooser.
199            prefs = Preferences.userNodeForPackage( View3DFile.class );
200            String lastLoc = prefs.get( PREF_KEY, System.getProperty( "user.home" ) );
201            File lastFile = new File( lastLoc );
202            if( !lastFile.exists() ){
203                lastFile = new File( System.getProperty( "user.home" ) );
204            }
205            fileChooser = new JFileChooser( lastFile );
206            
207            ArrayList<String> extensions = new ArrayList<String>();
208            extensions.add( "gml" );
209            extensions.add( "xml" );
210            CustomFileFilter fileFilter = new CustomFileFilter( extensions, "(*.gml *.xml)GML or CityGML-Files" );
211            fileChooser.setFileFilter( fileFilter );
212            
213            extensions.clear();
214            extensions.add( "shp" );
215            fileFilter = new CustomFileFilter( extensions, "Esri ShapeFiles" );
216            fileChooser.setFileFilter( fileFilter );
217            fileChooser.setAcceptAllFileFilterUsed( false );
218            fileChooser.setMultiSelectionEnabled( false );
219            
220            //Adding the button panel
221            JPanel buttonPanel = new JPanel( new FlowLayout() );
222            createButtons( buttonPanel );
223            getContentPane().add( buttonPanel, BorderLayout.SOUTH );
224            
225            
226            
227            //setting up Java3D
228            GraphicsConfigTemplate3D configTemplate = new GraphicsConfigTemplate3D();
229            configTemplate.setSceneAntialiasing( GraphicsConfigTemplate.PREFERRED );
230            configTemplate.setDoubleBuffer( GraphicsConfigTemplate.REQUIRED );
231            canvas = new Canvas3D( SimpleUniverse.getPreferredConfiguration() );
232            simpleUniverse = new SimpleUniverse( canvas );
233            if ( canvas != null ) {
234                getContentPane().add( canvas, BorderLayout.CENTER );
235            }
236    
237            View view = simpleUniverse.getViewer().getView();
238    
239            // view parameters
240            view.setBackClipDistance( 10000 );
241            view.setFrontClipDistance( 0.1 );
242            view.setWindowEyepointPolicy( View.RELATIVE_TO_FIELD_OF_VIEW );
243            view.setSceneAntialiasingEnable( true );
244    
245            centroid = new Point3d();
246            scene = new BranchGroup();
247            firstLight = createDirectionalLight( new Vector3f( 0, 0, 1 ) );
248            secondLight = createDirectionalLight( new Vector3f( 0, -1, 0 ) );
249            thirdLight = createDirectionalLight( new Vector3f( -1, 0, 0 ) );
250    
251            scene.addChild( firstLight );
252            scene.addChild( secondLight );
253            scene.addChild( thirdLight );
254    
255            //is handled by the mouse rotater, all objects will be added to it.
256            rotationGroup = new TransformGroup();
257            rotationGroup.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE );
258            rotationGroup.setCapability( TransformGroup.ALLOW_TRANSFORM_READ );
259            rotationGroup.setCapability( BranchGroup.ALLOW_DETACH );
260            rotationGroup.setCapability( Group.ALLOW_CHILDREN_EXTEND );
261            rotationGroup.setCapability( Group.ALLOW_CHILDREN_READ );
262            rotationGroup.setCapability( Group.ALLOW_CHILDREN_WRITE );
263            scene.addChild( rotationGroup );
264    
265            trackBall = new MouseRotate();
266            trackBall.setTransformGroup( rotationGroup );
267            trackBall.setSchedulingBounds( new BoundingSphere() );
268            scene.addChild( trackBall );
269    
270            simpleUniverse.addBranchGraph( scene );
271    
272            //adding the key listeners
273            addKeyListener( this );
274            canvas.addKeyListener( this );
275                   
276            if ( testSphere ) {
277                BranchGroup sphere = createJ3DSphere( new Point3d( 0, 0, 0 ) );
278                addBranchGroupToScene( sphere );
279            }
280            
281            pack();
282        }
283    
284        /**
285         * Create a directional light, with color.WHITE.
286         */
287        private DirectionalLight createDirectionalLight( Vector3f lightDir ) {
288            // create the color for the light
289            Color3f color = new Color3f( Color.WHITE );
290            // create the directional light with the color and direction
291            DirectionalLight light = new DirectionalLight( color, lightDir );
292            light.setCapability( Light.ALLOW_INFLUENCING_BOUNDS_READ );
293            light.setCapability( Light.ALLOW_INFLUENCING_BOUNDS_WRITE );
294            return light;
295        }
296    
297        private void addBranchGroupToScene( BranchGroup b ) {
298            rotationGroup.removeAllChildren();
299            // translationGroup.removeAllChildren();
300            // System.out.println( b.getBounds() );
301            Bounds bounds = b.getBounds();
302            if ( bounds != null ) {
303                
304                BoundingSphere bs = new BoundingSphere( bounds );
305                bs.getCenter( centroid );
306                
307                double radius = bs.getRadius();
308                
309                View view = simpleUniverse.getViewer().getView();
310                // view parameters
311                view.setBackClipDistance( radius*4 );
312                //the near clippingplane is one hundereth of the far.
313                view.setFrontClipDistance( (radius*4)*0.001 );
314                
315    
316                TransformGroup viewToWorld = simpleUniverse.getViewingPlatform().getViewPlatformTransform();
317                Transform3D trans = new Transform3D();
318                trans.lookAt( new Point3d( 0, 0, -radius*2 ), centroid, new Vector3d( 0, 1, 0 ) );
319                LOG.logDebug( "Trans Matrix after lookat:\n" + trans );
320                viewToWorld.setTransform( trans );
321                
322                LOG.logDebug( "Center: " + centroid );
323                LOG.logDebug( "radius: " + bs.getRadius() );
324    
325                firstLight.setInfluencingBounds( new BoundingSphere( centroid, radius * 3 ) );
326                secondLight.setInfluencingBounds( new BoundingSphere( centroid, radius * 3 ) );
327                thirdLight.setInfluencingBounds( new BoundingSphere( centroid, radius * 3 ) );
328                trackBall.setSchedulingBounds( new BoundingSphere( centroid, radius*4 ) );
329            }
330            rotationGroup.addChild( b );
331        }
332    
333        /**
334         * @return a brand new sphere
335         */
336        private BranchGroup createJ3DSphere( Point3d translation ) {
337            Appearance app = new Appearance();
338            RenderingAttributes ra = new RenderingAttributes();
339            ra.setDepthBufferEnable( true );
340            ra.setDepthBufferWriteEnable( true );
341            app.setRenderingAttributes( ra );
342    
343            ColoringAttributes ca = new ColoringAttributes();
344            ca.setShadeModel( ColoringAttributes.SHADE_GOURAUD );
345            ca.setCapability( ColoringAttributes.NICEST );
346            app.setColoringAttributes( ca );
347    
348            Material material = new Material();
349            material.setAmbientColor( new Color3f( Color.WHITE ) );
350            material.setDiffuseColor( new Color3f( Color.RED ) );
351            material.setSpecularColor( new Color3f( Color.BLUE ) );
352            app.setMaterial( material );
353            TransformGroup tg = new TransformGroup();
354            Transform3D trans = new Transform3D();
355            if ( translation != null ) {
356                trans.setTranslation( new Vector3d( translation ) );
357                tg.setTransform( trans );
358            }
359    
360            BranchGroup b = new BranchGroup();
361            b.setCapability( BranchGroup.ALLOW_DETACH );
362            b.addChild( tg );
363    
364            // tg.addChild( new Sphere( 0.2f, app ) );
365            tg.addChild( new ColorCube( 0.2f ) );
366            return b;
367        }
368    
369        private void createButtons( JPanel buttonPanel ) {
370            JButton button = new JButton( "Open File" );
371            button.setMnemonic( KeyEvent.VK_O );
372            button.addActionListener( this );
373            buttonPanel.add( button, FlowLayout.LEFT );
374        }
375    
376        private void readFile( String fileName )                          {
377    
378            if ( fileName == null || "".equals( fileName.trim() ) ) {
379                throw new InvalidParameterException( "the file name may not be null or empty" );
380            }
381            FeatureCollection fc = null;
382            if ( fileName.endsWith( ".shp" ) ) {
383                // File f = new File( fileName );
384                try {
385                    ShapeFile file = new ShapeFileReader( fileName ).read();
386                    fc = file.getFeatureCollection();
387                } catch ( IOException e ) {
388                    LOG.logError( "Could not open shape file: " + fileName + " because: " + e.getMessage() );
389                    return;
390                } catch ( DBaseException e ) {
391                    LOG.logError( "Could not open shape file: " + fileName + " because: " + e.getMessage() );
392                    return;
393                }
394            } else if ( fileName.endsWith( ".xml" ) || fileName.endsWith( ".gml" ) ) {
395                try {
396                    XMLFragment doc = new XMLFragment( new File( fileName ) );
397                    boolean isCityGML = ( doc.getRootElement().getOwnerDocument().lookupPrefix(
398                                                                                                CommonNamespaces.CITYGMLNS.toASCIIString() ) != null )
399                                        || CommonNamespaces.CITYGMLNS.toASCIIString().equals(
400                                                                                              doc.getRootElement().getOwnerDocument().lookupNamespaceURI(
401                                                                                                                                                          "" ) );
402                    if ( !isCityGML ) {
403                        isCityGML = isCityGMLDefined( doc.getRootElement() );
404                    }
405                    System.out.println( "is Citygml: " + isCityGML );
406                    if ( isCityGML ) {
407                        // convert to gml
408                        File f = new File( "src/org/deegree/tools/app3d/toShape.xsl" );
409                        XSLTDocument transformer = new XSLTDocument( f.toURL() );
410                        doc = transformer.transform( doc );
411                        // System.out.println( "outgoingdoc: \n " + doc.getAsPrettyString() );
412                    }
413                    GMLFeatureCollectionDocument gmlDoc = new GMLFeatureCollectionDocument();
414                    gmlDoc.setRootElement( doc.getRootElement() );
415                    fc = gmlDoc.parse();
416                } catch ( SAXException e ) {
417                    LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
418                    return;
419                } catch ( TransformerException e ) {
420                    LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
421                    return;
422                } catch ( XMLParsingException e ) {
423                    LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
424                    return;
425                } catch ( MalformedURLException e ) {
426                    LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
427                    return;
428                } catch ( IOException e ) {
429                    LOG.logError( "Could not open gml file: " + fileName + " because: " + e.getMessage() );
430                    return;
431                }
432            }
433            BranchGroup bg = new BranchGroup();
434            bg.setCapability( BranchGroup.ALLOW_DETACH );
435    
436            Appearance app = new Appearance();
437            RenderingAttributes ra = new RenderingAttributes();
438            ra.setDepthBufferEnable( true );
439            ra.setDepthBufferEnable( true );
440            app.setRenderingAttributes( ra );
441            Material material = new Material();
442            material.setAmbientColor( new Color3f( Color.WHITE ) );
443            material.setDiffuseColor( new Color3f( Color.RED ) );
444            material.setSpecularColor( new Color3f( Color.BLUE ) );
445            PolygonAttributes pa = new PolygonAttributes();
446            pa.setCullFace( PolygonAttributes.CULL_NONE );
447            app.setPolygonAttributes( pa );
448            app.setMaterial( material );
449            Envelope bbox = null;
450            for ( int i = 0; i < fc.size(); ++i ) {
451                Feature f = fc.getFeature( i );
452                Geometry geom = f.getDefaultGeometryPropertyValue();
453                if ( bbox == null ) {
454                    bbox = geom.getEnvelope();
455                } else {
456                    try {
457                        bbox = bbox.merge( geom.getEnvelope() );
458                        LOG.logDebug( "merging the bboxes resulted in: " + bbox );
459                    } catch ( GeometryException e ) {
460                        LOG.logError( "Couldn't merge the bboxes" );
461                        e.printStackTrace();
462                    }
463                }
464            }
465            Point3d centroid = new Point3d( 0, 0, 0 );
466            if ( bbox != null ) {
467                Point p = bbox.getCentroid();
468                double zValue = p.getZ();
469                if ( Double.isInfinite( zValue ) || Double.isNaN( zValue ) ) {
470                    zValue = 0;
471                }
472                centroid.set( -p.getX(), -p.getY(), -zValue );
473            }
474            for ( int i = 0; i < fc.size(); ++i ) {
475                Feature f = fc.getFeature( i );
476                Geometry geom = f.getDefaultGeometryPropertyValue();
477                Shape3D shape = mapGeometryToShape3D( geom, centroid );
478                if ( shape != null ) {
479                    shape.setAppearance( app );
480                    bg.addChild( shape );
481                } else {
482                    System.out.println( "ERRORORORORORORO" );
483                }
484            }
485            Enumeration en = bg.getAllChildren();
486            if ( en.hasMoreElements() ) {
487                addBranchGroupToScene( bg );
488            } else {
489                LOG.logError( "Could read any 3D-Info from the location: " + fileName );
490            }
491            File f = new File( fileName );
492            setTitle( WIN_TITLE + f.getName() );
493        }
494    
495        /**
496         * @param contextNode
497         * @return true if the namespace "http://www.citygml.org/citygml/1/0/0" was found in one of the nodes of the
498         *         dom-tree.
499         */
500        private boolean isCityGMLDefined( Node contextNode ) {
501    
502            boolean isCityGML = ( contextNode.lookupPrefix( CommonNamespaces.CITYGMLNS.toASCIIString() ) != null )
503                                || CommonNamespaces.CITYGMLNS.toASCIIString().equals( contextNode.lookupNamespaceURI( null ) );
504            if ( !isCityGML ) {
505                NodeList nl = contextNode.getChildNodes();
506                for ( int i = 0; i < nl.getLength(); ++i ) {
507                    isCityGML = isCityGMLDefined( nl.item( i ) );
508                    if ( isCityGML ) {
509                        return true;
510                    }
511                }
512            }
513            return isCityGML;
514        }
515    
516        private Shape3D mapGeometryToShape3D( Geometry geom, Point3d translation ) {
517            if ( geom instanceof Point ) {
518                return createShape3D( (Point) geom, translation );
519            } else if ( geom instanceof Curve ) {
520                return createShape3D( (Curve) geom, translation );
521            } else if ( geom instanceof Surface ) {
522                return createShape3D( (Surface) geom, translation );
523            } else if ( geom instanceof MultiSurface ) {
524                return createShape3D( (MultiSurface) geom, translation );
525            } else {
526                if ( geom == null ) {
527                    LOG.logError( "Could not map the geometry which was not instantiated" );
528                } else {
529                    LOG.logError( "Could not map the geometry: " + geom.getClass().getName() );
530                }
531                return null;
532            }
533    
534            // if ( geom instanceof MultiPoint ) {
535            // return new ShapeMultiPoint( (MultiPoint) g );
536            // }
537            //
538            // if ( geom instanceof MultiCurve ) {
539            // List<Curve> cs = Arrays.asList( ( (MultiCurve) g ).getAllCurves() );
540            // return new ShapePolyline( cs );
541            // }
542            //
543    
544        }
545    
546        private Shape3D createShape3D( Point p, Point3d translation ) {
547            GeometryArray geomArray = new PointArray( 1, GeometryArray.COORDINATES );
548            double z = p.getZ();
549            if ( Double.isInfinite( z ) || Double.isNaN( z ) ) {
550                z = 0;
551            }
552            geomArray.setCoordinate( 0, new Point3d( p.getX() + translation.x, p.getY() + translation.y, z + translation.z ) );
553            Shape3D result = new Shape3D( geomArray );
554            result.setAppearanceOverrideEnable( true );
555            return result;
556        }
557    
558        private Shape3D createShape3D( Curve c, Point3d translation ) {
559            int totalPoints = 0;
560            List<Integer> failSegments = new ArrayList<Integer>();
561            for ( int i = 0; i < c.getNumberOfCurveSegments(); ++i ) {
562                try {
563                    totalPoints += c.getCurveSegmentAt( i ).getNumberOfPoints();
564                } catch ( GeometryException e ) {
565                    LOG.logError( "Could not get CurveSegment at position: " + i );
566                    failSegments.add( new Integer( i ) );
567                }
568            }
569    
570            LineArray geomArray = new LineArray( totalPoints, GeometryArray.COORDINATES );
571            for ( int i = 0, pointCounter = 0; i < c.getNumberOfCurveSegments(); ++i ) {
572                if ( !failSegments.contains( new Integer( i ) ) ) {
573                    CurveSegment segment = null;
574                    try {
575                        segment = c.getCurveSegmentAt( i );
576                    } catch ( GeometryException e ) {
577                        // cannot happen.
578                    }
579                    for ( int k = 0; k < segment.getNumberOfPoints(); ++k ) {
580                        Position p = segment.getPositionAt( k );
581                        double z = p.getZ();
582                        if ( Double.isInfinite( z ) || Double.isNaN( z ) ) {
583                            z = 0;
584                        }
585                        geomArray.setCoordinate( pointCounter++, new Point3d( p.getX() + translation.x, p.getY()
586                                                                                                        + translation.y,
587                                                                              z + translation.z ) );
588                    }
589                }
590            }
591            Shape3D result = new Shape3D( geomArray );
592            result.setAppearanceOverrideEnable( true );
593            return result;
594        }
595    
596        /**
597         * 
598         * @param surface to be created
599         * @param translation to origin of the scene
600         * @return a Shape3D created from the surface.
601         */
602        private Shape3D createShape3D( Surface surface, Point3d translation ) {
603            GeometryInfo geometryInfo = new GeometryInfo( GeometryInfo.POLYGON_ARRAY );
604    
605            Position[] pos = surface.getSurfaceBoundary().getExteriorRing().getPositions();
606            Ring[] innerRings = surface.getSurfaceBoundary().getInteriorRings();
607            int k = 1;
608            int l = 3 * ( pos.length         );
609            if ( innerRings != null ) {
610                for ( int i = 0; i < innerRings.length; i++ ) {
611                    k++;
612                    l += ( 3 * innerRings[i].getPositions().length );
613                }
614            }
615    
616            float[] coords = new float[l];
617            int contourCounts[] = { k };
618            int[] stripCounts = new int[k];
619            k = 0;
620            stripCounts[k++] = pos.length;
621    
622            int z = 0;
623            for ( int i = 0; i < pos.length; i++ ) {
624                double zValue = pos[i].getZ();
625                if ( Double.isInfinite( zValue ) || Double.isNaN( zValue ) ) {
626                    zValue = 0;
627                }
628                //LOG.logDebug( "Found a point in a surface: " + pos[i] );
629                coords[z++] = (float) ( pos[i].getX() + translation.x );
630                coords[z++] = (float) ( pos[i].getY() + translation.y );
631                coords[z++] = (float) ( zValue + translation.z );
632            }
633    
634            if ( innerRings != null ) {
635                for ( int j = 0; j < innerRings.length; j++ ) {
636                    pos = innerRings[j].getPositions();
637                    stripCounts[k++] = pos.length;
638                    for ( int i = 0; i < pos.length; i++ ) {
639                        double zValue = pos[i].getZ();
640                        if ( Double.isInfinite( zValue ) || Double.isNaN( zValue ) ) {
641                            zValue = 0;
642                        }
643                        coords[z++] = (float) ( pos[i].getX() + translation.x );
644                        coords[z++] = (float) ( pos[i].getY() + translation.y );
645                        coords[z++] = (float) ( zValue + translation.z );
646                    }
647                }
648            }
649    
650            geometryInfo.setCoordinates( coords );
651            geometryInfo.setStripCounts( stripCounts );
652            geometryInfo.setContourCounts( contourCounts );
653    
654            NormalGenerator ng = new NormalGenerator();
655            ng.generateNormals( geometryInfo );
656            Shape3D result = new Shape3D( geometryInfo.getGeometryArray() );
657            result.setCapability( Shape3D.ALLOW_GEOMETRY_READ );
658            result.setCapability( Shape3D.ALLOW_GEOMETRY_WRITE );
659            result.setAppearanceOverrideEnable( true );
660            return result;
661        }
662    
663        /**
664         * @param surface
665         * @return a Shape3D created from the multisurfaces.
666         */
667        private Shape3D createShape3D( MultiSurface multiSurface, Point3d translation ) {
668            Shape3D result = new Shape3D();
669            result.setCapability( Shape3D.ALLOW_GEOMETRY_READ );
670            result.setCapability( Shape3D.ALLOW_GEOMETRY_WRITE );
671            Surface[] allSurfaces = multiSurface.getAllSurfaces();
672            for ( int surfaceCount = 0; surfaceCount < allSurfaces.length; ++surfaceCount ) {
673                Surface surface = multiSurface.getSurfaceAt( surfaceCount );
674                Shape3D s3D = createShape3D( surface, translation );
675                result.addGeometry( s3D.getGeometry() );
676            }
677            result.setAppearanceOverrideEnable( true );
678            return result;
679        }
680    
681        /*
682         * (non-Javadoc)
683         * 
684         * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
685         */
686        public void actionPerformed( ActionEvent e ) {
687            Object source = e.getSource();
688            if ( source instanceof JButton ) {
689                // JFileChooser filechooser = new JFileChooser();
690                // filechooser.setVisible( true );
691                int result = fileChooser.showOpenDialog( this );
692                if( JFileChooser.APPROVE_OPTION == result ){
693                    File f = fileChooser.getSelectedFile();
694                    if( f != null ) {
695                        String path = f.getAbsolutePath();
696                        String dirpath = f.getParent();
697                        System.out.println( "absolute Path: " + dirpath );
698                        prefs.put( PREF_KEY, dirpath );
699                        readFile( path );
700                    }
701    
702                }
703            }
704        }
705    
706        /*
707         * (non-Javadoc)
708         * 
709         * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
710         */
711        public void keyPressed( KeyEvent arg0 ) {
712            // nottin
713        }
714    
715        /*
716         * (non-Javadoc)
717         * 
718         * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
719         */
720        public void keyReleased( KeyEvent arg0 ) {
721            // nottin
722        }
723    
724        /*
725         * (non-Javadoc)
726         * 
727         * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
728         */
729        public void keyTyped( KeyEvent e ) {
730            double x = 0;
731            double y = 0;
732            double z = 0;
733            if ( e.getKeyChar() == 'q' ) {
734                System.exit( 0 );
735            } else if ( e.getKeyChar() == 'x' ) {
736                x = 1;
737            } else if ( e.getKeyChar() == 'X' ) {
738                x = -1;
739            } else if ( e.getKeyChar() == 'y' ) {
740                y = 1;
741            } else if ( e.getKeyChar() == 'Y' ) {
742                y = -1;
743            } else if ( e.getKeyChar() == 'z' ) {
744                z = 1;
745            } else if ( e.getKeyChar() == 'Z' ) {
746                z = -1;
747            }
748            
749            TransformGroup viewToWorld = simpleUniverse.getViewingPlatform().getViewPlatformTransform();
750            Transform3D trans = new Transform3D();
751            viewToWorld.getTransform( trans );
752            trans.invert();
753            Vector3d translation = new Vector3d();
754            trans.get( translation );
755            
756            x += translation.x;
757            y += translation.y;
758            z += translation.z;
759            Point3d eye = new Point3d( x, y, z );
760            trans.lookAt( eye, centroid, new Vector3d( 0, 1, 0 ) );
761            LOG.logDebug( "Trans after:\n" + trans );
762            Vector3d dist = new Vector3d( centroid );
763            dist.sub( eye );
764            trackBall.setSchedulingBounds( new BoundingSphere( centroid, dist.length() ) );
765            viewToWorld.setTransform( trans );
766    
767        }
768        /**
769         * @param args
770         */
771        public static void main( String[] args ) {
772    
773            View3DFile viewer = new View3DFile( "/home/rutger/testViewer/3dtest2.shp" );
774            viewer.toFront();
775    //         View3DFile viewer = new View3DFile( true );
776    //         viewer.toFront();
777    
778        }
779        
780        private class CustomFileFilter extends FileFilter{
781    
782            private List<String> acceptedExtensions;
783            private String desc;
784            /**
785             * @param acceptedExtensions list of extensions this filter accepts.
786             */
787            CustomFileFilter( List<String> acceptedExtensions, String description) {
788                this.acceptedExtensions = new ArrayList<String>(acceptedExtensions.size() );
789                for( String s : acceptedExtensions ){
790                    if( s.startsWith( "." ) ){
791                        s = s.substring( 1 );
792                    }
793                    this.acceptedExtensions.add( s.trim().toUpperCase() );
794                }
795                desc = description;
796            }
797    
798            @Override
799            public boolean accept( File pathname ) {
800                if (pathname.isDirectory()) {
801                    return true;
802                }
803    
804                    String extension = getExtension(pathname);
805                    if (extension != null) {
806                        if ( acceptedExtensions.contains( extension.trim().toUpperCase() )) {
807                            return true;
808                        }
809                    }                        
810                    return false;
811            }
812            private String getExtension( File f ){
813                String ext = null;
814                String s = f.getName();
815                int i = s.lastIndexOf('.');
816    
817                if (i > 0 &&  i < s.length() - 1) {
818                    ext = s.substring(i+1).toLowerCase();
819                }
820                return ext;
821            }
822    
823            @Override
824            public String getDescription() {
825                return desc;
826            }
827        }
828    }
829