001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wpvs/j3d/DefaultSurface.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    package org.deegree.ogcwebservices.wpvs.j3d;
037    
038    import java.util.ArrayList;
039    import java.util.List;
040    
041    import javax.media.j3d.Shape3D;
042    import javax.vecmath.Point3d;
043    
044    import org.deegree.model.spatialschema.Geometry;
045    import org.deegree.model.spatialschema.MultiSurface;
046    import org.deegree.model.spatialschema.Position;
047    import org.deegree.model.spatialschema.Ring;
048    import org.deegree.model.spatialschema.Surface;
049    import org.deegree.model.spatialschema.SurfaceBoundary;
050    
051    import com.sun.j3d.utils.geometry.GeometryInfo;
052    import com.sun.j3d.utils.geometry.NormalGenerator;
053    
054    /**
055     *
056     *
057     *
058     * @version $Revision: 18195 $
059     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
060     * @author last edited by: $Author: mschneider $
061     *
062     * @version 1.0. $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
063     *
064     * @since 2.0
065     */
066    public class DefaultSurface extends Shape3D {
067    
068        /**
069         * The geometry to create the Shape3D from.
070         */
071        protected Geometry geometry;
072    
073        private String parentID;
074    
075        private String objectID;
076    
077        /**
078         *
079         * @param objectID
080         * @param parentID
081         * @param geometry
082         */
083        public DefaultSurface( String objectID, String parentID, Geometry geometry ) {
084            super();
085            if ( !( geometry instanceof MultiSurface || geometry instanceof Surface ) ) {
086                throw new UnsupportedOperationException( "Currently only surface and multisurfaces are supported" );
087            }
088            this.geometry = geometry;
089            this.parentID = parentID;
090            this.objectID = objectID;
091    
092            /*
093             * System.out.println( "new Appearance" ); Color3f specular = new Color3f( 0.7f, 0.7f, 0.7f ); Color3f white =
094             * new Color3f( 0.4f, 1, 0.4f );
095             *
096             * Material targetMaterial = new Material(); targetMaterial.setAmbientColor( white );
097             * targetMaterial.setDiffuseColor( white ); targetMaterial.setSpecularColor( specular );
098             * targetMaterial.setShininess( 75.0f ); targetMaterial.setLightingEnable( true ); targetMaterial.setCapability(
099             * Material.ALLOW_COMPONENT_WRITE ); // ColoringAttributes ca = new ColoringAttributes(); ca.setShadeModel(
100             * ColoringAttributes.SHADE_GOURAUD ); // Appearance defaultAppearance = new Appearance();
101             * defaultAppearance.setMaterial( targetMaterial ); defaultAppearance.setColoringAttributes( ca ); //
102             * PolygonAttributes targetPolyAttr = new PolygonAttributes(); targetPolyAttr.setCapability(
103             * PolygonAttributes.ALLOW_MODE_WRITE ); targetPolyAttr.setCapability( PolygonAttributes.ALLOW_NORMAL_FLIP_WRITE );
104             * targetPolyAttr.setPolygonMode( PolygonAttributes.POLYGON_FILL ); targetPolyAttr.setCullFace(
105             * PolygonAttributes.CULL_NONE ); // pa.setPolygonMode( PolygonAttributes.POLYGON_LINE );
106             * defaultAppearance.setPolygonAttributes( targetPolyAttr ); setAppearance( defaultAppearance );
107             */
108        }
109    
110        /**
111         * @return the ID of the Object this Surface is a part of (e.g. the building id if this is a wall)
112         */
113        public String getParentID() {
114            return parentID;
115        }
116    
117        /**
118         * @return the objectID value.
119         */
120        public String getObjectID() {
121            return objectID;
122        }
123    
124        /**
125         * @return a String composited of the parentID and "_" and the objectID
126         */
127        public String getDefaultSurfaceID() {
128            return parentID + '_' + objectID;
129        }
130    
131        /**
132         *
133         * @return the surface geometry encapsulated
134         */
135        public Geometry getSurfaceGeometry() {
136            return geometry;
137        }
138    
139        /**
140         * this method must be called before adding the surface to a Group
141         */
142        public void compile() {
143            setAppearanceOverrideEnable( true );
144            addGeometries( geometry );
145            setCapability( Shape3D.ALLOW_GEOMETRY_READ );
146            setCapability( Shape3D.ALLOW_GEOMETRY_WRITE );
147        }
148    
149        /**
150         * Adds the given surface.
151         *
152         * @param surface
153         *            to be added( only surface and multisurface are currently supported).
154         */
155        public void addGeometries( org.deegree.model.spatialschema.Geometry surface ) {
156            /**
157             * First create the coordinates and the contours
158             */
159            if ( surface != null ) {
160                if ( surface instanceof MultiSurface ) {
161                    for ( Surface multiSurface : ( (MultiSurface) surface ).getAllSurfaces() ) {
162                        GeometryInfo geomInfo = getGeometryInfo( multiSurface );
163                        addGeometry( geomInfo.getGeometryArray() );
164                    }
165                } else if ( surface instanceof Surface ) {
166                    // ((extractSurface( (Surface) surface, coordinates, contourCount );
167                    GeometryInfo geomInfo = getGeometryInfo( (Surface) surface );
168                    addGeometry( geomInfo.getGeometryArray() );
169                } else {
170                    throw new IllegalArgumentException( "Don't know how to create a textured surface from given geometry" );
171                }
172            }
173        }
174    
175        /**
176         * Creates a geometry info of the given surface.
177         *
178         * @param surface
179         * @return the geometry info
180         */
181        public GeometryInfo getGeometryInfo( Surface surface ) {
182    
183            GeometryInfo geometryInfo = new GeometryInfo( GeometryInfo.POLYGON_ARRAY );
184            List<Point3d> coordinates = new ArrayList<Point3d>();
185            List<Integer> contourCount = new ArrayList<Integer>( 200 );
186    
187            extractSurface( surface, coordinates, contourCount );
188    
189            /**
190             * Now create the geometry info as a polygon array
191             */
192            geometryInfo.setCoordinates( coordinates.toArray( new Point3d[0] ) );
193            int[] sc = new int[contourCount.size()];
194            int stripCountNumber = 0;
195            for ( int i = 0; i < contourCount.size(); ++i ) {
196                sc[i] = contourCount.get( i ).intValue();
197                stripCountNumber += sc[i];
198            }
199            geometryInfo.setStripCounts( sc );
200            // we don't actually need the contours, just an array which has the right length.
201            geometryInfo.setContourCounts( new int[] { sc.length } );
202    
203            // recalculate the normals
204            geometryInfo.recomputeIndices();
205            NormalGenerator ng = new NormalGenerator();
206            ng.generateNormals( geometryInfo );
207    
208            // convert the polygon into indexed triangles for faster access.
209            geometryInfo.convertToIndexedTriangles();
210            return geometryInfo;
211        }
212    
213        /**
214         * Extract the actual coordinates of a surface and puts them with in the given list.
215         *
216         * @param surface
217         *            to export
218         * @param coordinates
219         *            to fill
220         * @param contourCount
221         *            will the number of coordinates in a contour (rings).
222         */
223        protected void extractSurface( Surface surface, List<Point3d> coordinates, List<Integer> contourCount ) {
224            if ( surface != null ) {
225                SurfaceBoundary sb = surface.getSurfaceBoundary();
226                if ( sb != null ) {
227                    Ring outerRing = sb.getExteriorRing();
228                    if ( outerRing != null ) {
229                        Position[] pos = outerRing.getPositions();
230                        if ( pos != null ) {
231                            // the surface start and end point are the same, ignoring the last node.
232                            for ( int i = 0; i < pos.length - 1; ++i ) {
233                                coordinates.add( pos[i].getAsPoint3d() );
234                            }
235                            contourCount.add( new Integer( pos.length - 1 ) );
236                        }
237    
238                        Ring[] innerRings = sb.getInteriorRings();
239                        if ( innerRings != null ) {
240                            for ( Ring innerRing : innerRings ) {
241                                pos = innerRing.getPositions();
242                                if ( pos != null ) {
243                                    // the surface start and end point are the same, ignoring the last node.
244                                    for ( int i = 0; i < pos.length - 1; ++i ) {
245                                        coordinates.add( pos[i].getAsPoint3d() );
246                                    }
247                                    contourCount.add( new Integer( pos.length - 1 ) );
248                                }
249                            }
250                        }
251                    }
252                }
253            }
254    
255        }
256    
257        /**
258         * @return a String representation of all the geometries inside this surface
259         */
260        public String getGeometryAsString() {
261            StringBuffer sb = new StringBuffer( numGeometries() );
262            for ( int i = 0; i < numGeometries(); ++i ) {
263                javax.media.j3d.Geometry ga = getGeometry( i );
264                sb.append( ga.toString() );
265            }
266            return sb.toString();
267        }
268    }