001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wpvs/j3d/TriangleTerrain.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     
043     ---------------------------------------------------------------------------*/
044    
045    package org.deegree.ogcwebservices.wpvs.j3d;
046    
047    import java.awt.image.BufferedImage;
048    import java.util.ArrayList;
049    import java.util.List;
050    
051    import javax.vecmath.Point3d;
052    import javax.vecmath.Point3f;
053    import javax.vecmath.TexCoord2f;
054    
055    import org.deegree.framework.log.ILogger;
056    import org.deegree.framework.log.LoggerFactory;
057    import org.deegree.model.spatialschema.Envelope;
058    import org.deegree.model.spatialschema.Position;
059    import org.deegree.ogcwebservices.wpvs.utils.VisADWrapper;
060    
061    import com.sun.j3d.utils.geometry.GeometryInfo;
062    import com.sun.j3d.utils.geometry.NormalGenerator;
063    
064    /**
065     * The <code>TriangleTerrain</code> class respresents the Java3D shape of a set of measurepoints. Before this Terrrain
066     * can be drawn the createTerrain method must be invoked, it will create triangles of the given measurepoints and will
067     * add the optional texture to the apearance of the Shap3D.
068     * 
069     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
070     * 
071     * @author last edited by: $Author: apoth $
072     * 
073     * @version $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
074     * 
075     */
076    
077    public class TriangleTerrain extends TerrainModel {
078    
079        private static ILogger LOG = LoggerFactory.getLogger( TriangleTerrain.class );
080    
081        private Envelope boundingBox;
082    
083        private double terrainWidth;
084    
085        private double terrainHeight;
086    
087        private List<Point3d> measurePoints = null;
088    
089        private double minimalHeightlevel;
090    
091    
092        private double scale;
093    
094        /**
095         * @param measurePoints
096         *            indicating height values inside this terrain. They will be triangulated in the createTerrain method.
097         * @param env the bbox of this triangle terrain.
098         * @param minimalHeightlevel
099         *            which will be used if the measurepoints have no height set.
100         * @param scale
101         *            to multiply onto the z-value of the measurepoints
102         */
103        public TriangleTerrain( List<Point3d> measurePoints, Envelope env, double minimalHeightlevel, double scale ) {
104            super();
105            this.measurePoints = measurePoints;
106            this.minimalHeightlevel = minimalHeightlevel;
107            this.scale = scale;
108    
109            boundingBox = env;
110    
111            this.terrainWidth = boundingBox.getWidth();
112            this.terrainHeight = boundingBox.getHeight();
113        }
114    
115        /**
116         * @return the boundingBox of this TriangleTerrain
117         */
118        public Envelope getBoundingBox() {
119            return boundingBox;
120        }
121    
122        @Override
123        public void createTerrain() {
124             List<float[][]> triangles = new ArrayList<float[][]>();
125            if ( measurePoints == null || measurePoints.size() == 0 ) { // just a square, asssuming a simple plane,
126                triangles = createFlatTerrain(  );
127            } else {
128                LOG.logDebug( "Trying to create triangles with the visad library" );
129                long time = System.currentTimeMillis();
130                VisADWrapper vw = new VisADWrapper( measurePoints, scale );
131                triangles = vw.getTriangleCollectionAsList();
132                if( triangles != null ){
133                    LOG.logDebug( new StringBuilder("Creation of ").append( triangles.size()).append( " triangles with the visad library was successfull. (took: ").append( (System.currentTimeMillis() - time) / 1000d).append(" seconds).").toString() );
134                } else{
135                    LOG.logDebug( new StringBuilder("Creation of triangles with the visad library was NOT successfull. Creating a flat terrain.").toString() );
136                    triangles = createFlatTerrain( );
137                }
138    
139            }
140    
141            double widthInv = 1d / terrainWidth;
142            double heightInv = 1d / terrainHeight;
143            Position originalLowerLeft = boundingBox.getMin();
144    
145            GeometryInfo geometryInfo = new GeometryInfo( GeometryInfo.TRIANGLE_ARRAY );
146    
147            BufferedImage texture = getTexture();
148            if ( texture != null ){
149                geometryInfo.setTextureCoordinateParams( 1, 2 );
150            }
151    
152            Point3f[] coordinates = new Point3f[triangles.size() * 3];
153            TexCoord2f[] texCoords = new TexCoord2f[triangles.size() * 3];
154    
155            int coordNr = 0;
156            for ( float[][] triangleCoords : triangles ) {
157                for ( int k = 0; k < 3; k++ ) {
158                    // System.out.println( Thread.currentThread() + "-> coordNR: " + coordNr );
159                    Point3f modelCoordinate = new Point3f( triangleCoords[k][0], triangleCoords[k][1], triangleCoords[k][2] );
160                    coordinates[coordNr] = modelCoordinate;
161    
162                    if ( texture != null ) {
163                        double texCoordX = ( modelCoordinate.x - originalLowerLeft.getX() ) * widthInv;
164                        double texCoordY = ( modelCoordinate.y - originalLowerLeft.getY() ) * heightInv;
165                        texCoordX = ( texCoordX > 1 ) ? 1 : ( ( texCoordX < 0 ) ? 0 : texCoordX );
166                        texCoordY = ( texCoordY > 1 ) ? 1 : ( ( texCoordY < 0 ) ? 0 : texCoordY );
167                        texCoords[coordNr] = new TexCoord2f( (float)texCoordX ,(float) texCoordY );
168                    }
169                    coordNr++;
170                }
171    
172            }
173            geometryInfo.setCoordinates( coordinates );
174            if ( texture != null ) {
175                geometryInfo.setTextureCoordinates( 0, texCoords );
176            }
177            geometryInfo.recomputeIndices();
178            NormalGenerator ng = new NormalGenerator();
179            ng.generateNormals( geometryInfo );
180    
181            setGeometry( geometryInfo.getGeometryArray() );
182        }
183        
184        private List<float[][]> createFlatTerrain( ){
185            LOG.logDebug( "Creating a flat square at minimalTerrain height, which will represent the terrain." );
186            List<float[][]> triangles = new ArrayList<float[][]>();
187            Position min = boundingBox.getMin();
188            Position max = boundingBox.getMax();
189            float[][] triangle = new float[3][3];
190            triangle[0][0] = (float) min.getX();
191            triangle[0][1] = (float) min.getY();
192            triangle[0][2] = (float) minimalHeightlevel;
193    
194            triangle[1][0] = (float) max.getX();
195            triangle[1][1] = (float) min.getY();
196            triangle[1][2] = (float) minimalHeightlevel;
197    
198            triangle[2][0] = (float) min.getX();
199            triangle[2][1] = (float) max.getY();
200            triangle[2][2] = (float) minimalHeightlevel;
201    
202            triangles.add( triangle );
203    
204            triangle = new float[3][3];
205            triangle[0][0] = (float) max.getX();
206            triangle[0][1] = (float) min.getY();
207            triangle[0][2] = (float) minimalHeightlevel;
208    
209            triangle[1][0] = (float) max.getX();
210            triangle[1][1] = (float) max.getY();
211            triangle[1][2] = (float) minimalHeightlevel;
212    
213            triangle[2][0] = (float) min.getX();
214            triangle[2][1] = (float) max.getY();
215            triangle[2][2] = (float) minimalHeightlevel;
216            triangles.add( triangle );
217            return triangles;
218        }
219    
220    }