001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wpvs/utils/VisADWrapper.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2006 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     Aennchenstraße 19
030     53177 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    package org.deegree.ogcwebservices.wpvs.utils;
044    
045    import java.rmi.RemoteException;
046    import java.util.ArrayList;
047    import java.util.List;
048    
049    import org.deegree.framework.log.ILogger;
050    import org.deegree.framework.log.LoggerFactory;
051    import org.deegree.model.spatialschema.Point;
052    
053    import visad.Delaunay;
054    import visad.FlatField;
055    import visad.FunctionType;
056    import visad.Irregular2DSet;
057    import visad.RealTupleType;
058    import visad.RealType;
059    import visad.VisADException;
060    
061    /**
062     * A wrapper for VisAD objects. This class takes care of collecting points to build a TIN, of TIN
063     * creation itself and its output as a geometry collection.
064     * 
065     * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a>
066     * @author last edited by: $Author: rbezema $
067     * 
068     * $Revision: 7963 $, $Date: 2007-08-09 12:03:15 +0200 (Do, 09 Aug 2007) $
069     * 
070     * 
071     */
072    public class VisADWrapper {
073    
074        private static final ILogger LOG = LoggerFactory.getLogger( VisADWrapper.class );
075    
076        /**
077         * A list for hold points representing te DEM/TIN.
078         */
079        private List<Point> pointsList;
080        
081        private double scale;
082    
083        /**
084         * Initializes the object by creating a common domain field from the geometrical information
085         * (the envelope, the width and the height) supplied. The envelope cannot the null, nor can the
086         * dimensions by < 1.
087         * 
088         * @param ptsList
089         *            a list of Points
090         * @param scale to multiply to the z-value
091         */
092        public VisADWrapper( List<Point> ptsList, double scale  ) {
093            this.pointsList = ptsList;
094            this.scale = scale;
095        }
096    
097        /**
098         * Add <code>Point</code>s to the internal list. Lists without any elements (or null lists)
099         * are ignored.
100         * 
101         * @param points
102         *            to be added to the list
103         */
104        public final void addPoints( List<Point> points ) {
105    
106            if ( points == null || points.size() == 0 ) {
107                return;
108            }
109    
110            this.pointsList.addAll( points );
111        }
112    
113        /**
114         * Generates a list of tringles containing the triangles representing the TIN. Triangles are
115         * represented float[3][3]
116         * 
117         * @return a collection of <code>float[3][3]</code>, each of which representing a TIN
118         *         triangle
119         * 
120         */
121        public final List<float[][]> getTriangleCollectionAsList() {
122    
123            List<float[][]> list = null;
124            try {
125                FlatField tinField = triangulatePoints();
126                if ( tinField == null )
127                    return null;
128                list = toGeoCollectionList( tinField );
129            } catch ( NoClassDefFoundError ncdfe ) {
130                LOG.logError( "WPVS: It seems that the visad library could not be found: "
131                              + ncdfe.getLocalizedMessage(), ncdfe );
132            } catch ( VisADException ve ) {
133                LOG.logError( ve.getLocalizedMessage(), ve );
134            }
135            return list;
136        }
137    
138        /**
139         * Triangulate <code>GM_Point</code>s contained in <code>gmPointsList</code> using the
140         * Clarkson algorithm. This method returns a <code>FlatField</code> containing all points
141         * triangulated and with their elevation values.<br/>
142         * 
143         * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a>
144         * 
145         * @param gmPointsList
146         *            the list of <code>GM_Point</code>s. Cannot be null and must contain at least 3
147         *            <code>GM_Point</code>s.
148         * @return a <code>FlatField</code> containg a TIN (with an <code>Irregular2DSet</code> as
149         *         its domain set and the elevation values)
150         * 
151         */
152        private FlatField triangulatePoints()
153                                throws NoClassDefFoundError {
154    
155            if ( this.pointsList == null || this.pointsList.size() < 3 ) {
156                throw new IllegalArgumentException(
157                                                    "Points list cannot be null and must contain at least 3 GM_Points." );
158            }
159            
160            //removing double points
161            ArrayList<Point> remove = new ArrayList<Point>();
162            for ( int i = 0; i < pointsList.size(); ++i ) {
163                Point p = pointsList.get( i );
164    
165                if ( !remove.contains( p ) ) {
166                    for ( int j = i+1; j < pointsList.size(); ++j ) {
167                        Point tmpP = pointsList.get( j );
168                        if ( ( Math.abs( tmpP.getX() - p.getX() ) < 0.001 )
169                             && ( Math.abs( tmpP.getY() - p.getY() ) < 0.001 ) ) {
170                            remove.add( tmpP );
171                        }
172                    }
173                }
174            }
175            for( Point p : remove ){
176                pointsList.remove( p );
177            }
178            float[][] triPoints = new float[3][this.pointsList.size()];
179            int cnt = 0;
180    
181            for ( Point p : this.pointsList ) {
182                triPoints[0][cnt] = (float) p.getX();
183                triPoints[1][cnt] = (float) p.getY();
184                triPoints[2][cnt++] = (float) (p.getZ()*scale);
185            }
186    
187            try {
188                FunctionType functionType = new FunctionType( new RealTupleType( RealType.XAxis,
189                                                                                 RealType.YAxis ),
190                                                              RealType.ZAxis );
191                float[][] ptsXY = new float[][] { triPoints[0], triPoints[1] };
192    
193                // ptsXY = Delaunay.perturb(ptsXY,0.21f, false);
194                ptsXY = Delaunay.perturb( ptsXY, 5.5f, false );
195                Delaunay delan = Delaunay.factory( ptsXY, true );
196                //Delaunay delan = new DelaunayClarkson( ptsXY );
197                //Delaunay delan = new DelaunayWatson( ptsXY );
198                //delan.setNonConvex();
199                try {
200                    delan.improve( ptsXY, 3 );
201                } catch ( Exception e ) {
202                    // just do noting
203                }
204                
205    
206                // Delaunay delan = new DelaunayClarkson( ptsXY );
207                // Delaunay delan = new DelaunayFast( ptsXY );
208                Irregular2DSet pointsSet = new Irregular2DSet( functionType.getDomain(), ptsXY, null,
209                                                               null, null, delan );
210    
211                FlatField ff = new FlatField( functionType, pointsSet );
212    
213                ff.setSamples( new float[][] { triPoints[2] }, true );
214    
215                return ff;
216    
217            } catch ( VisADException e ) {
218                System.out.println( e.getMessage() );
219                e.printStackTrace();
220                return null;
221            } catch ( RemoteException re ) {
222                re.printStackTrace();
223                return null;
224            } catch ( IndexOutOfBoundsException ioobe ) {
225                ioobe.printStackTrace();
226                return null;
227            }
228        }
229    
230        /**
231         * Generated a list of triangles from the FlatField passed in as tinField
232         * 
233         * @param tinField
234         *            the FlatField containing triangles
235         * @return a collection of <code>float[3][3]</code>, each of which representing a TIN
236         *         triangle
237         * @throws VisADException
238         * @throws Exception
239         *             in the unlikely event that a VisAD expcetion is thrown
240         */
241        private final List<float[][]> toGeoCollectionList( FlatField tinField )
242                                throws NoClassDefFoundError, VisADException {
243            if ( tinField == null ) {
244                throw new RuntimeException( "FlatField cannot be null." );
245            }
246    
247            List<float[][]> geoCollec = new ArrayList<float[][]>( 5000 );
248    
249            Irregular2DSet domainSet = (Irregular2DSet) tinField.getDomainSet();
250    
251            float[][] xyPositions = domainSet.getSamples();
252            float[][] zValues = tinField.getFloats();
253            int[][] indices = domainSet.Delan.Tri;
254    
255            // loop over triangles...
256            for ( int i = 0; i < indices.length; i++ ) {
257    
258                // indices[i].length == coords.length == 3
259                // this is float[3][3] -> 3 points per triabngle, each point with 3 coords
260                float[][] myCoords = new float[3][3];
261    
262                // ...then over points
263                for ( int j = 0; j < indices[i].length; j++ ) {
264    
265                    int index = indices[i][j];
266                    myCoords[j] = new float[3];
267                    myCoords[j][0] = xyPositions[0][index];
268                    myCoords[j][1] = xyPositions[1][index];
269                    myCoords[j][2] = zValues[0][index];
270                }
271    
272                geoCollec.add( myCoords );
273            }
274    
275            tinField = null;
276    
277            return geoCollec;
278        }
279    
280        /**
281         * Clear all points and invalidate list.
282         * 
283         */
284        public void clear() {
285            this.pointsList.clear();
286            this.pointsList = null;
287    
288        }
289    
290    }
291    /***************************************************************************************************
292     * Changes to this class. What the people have been up to: $Log$
293     * Changes to this class. What the people have been up to: Revision 1.4  2007/01/23 15:19:11  bezema
294     * Changes to this class. What the people have been up to: added the scale "parameter" to the measurepoints
295     * Changes to this class. What the people have been up to:
296     * Changes to this class. What the people have been up to: Revision 1.3  2007/01/23 15:09:41  bezema
297     * Changes to this class. What the people have been up to: added some methods for wfs dgm to sow together the triangle terrains
298     * Changes to this class. What the people have been up to: Changes to
299     * this class. What the people have been up to: Revision 1.2 2007/01/15 17:03:25 bezema Changes to
300     * this class. What the people have been up to: if no library is found, this will be catched now
301     * Changes to this class. What the people have been up to: Changes to this class. What the people
302     * have been up to: Revision 1.1 2006/12/06 15:11:24 bezema Changes to this class. What the people
303     * have been up to: renamed the wpvs.util package into wpvs.utils, removed not used classes and
304     * moved SunPosition SUnLight in the util package Changes to this class. What the people have been
305     * up to: Changes to this class. What the people have been up to: Revision 1.10 2006/11/23 11:46:40
306     * bezema Changes to this class. What the people have been up to: The initial version of the new
307     * wpvs Changes to this class. What the people have been up to: Revision 1.9 2006/07/12 14:46:19
308     * poth comment footer added
309     * 
310     **************************************************************************************************/