001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wpvs/utils/VisADWrapper.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.utils;
037    
038    import java.rmi.RemoteException;
039    import java.util.ArrayList;
040    import java.util.List;
041    
042    import javax.vecmath.Point3d;
043    
044    import org.deegree.framework.log.ILogger;
045    import org.deegree.framework.log.LoggerFactory;
046    
047    import visad.Delaunay;
048    import visad.FlatField;
049    import visad.FunctionType;
050    import visad.Irregular2DSet;
051    import visad.RealTupleType;
052    import visad.RealType;
053    import visad.VisADException;
054    
055    /**
056     * A wrapper for VisAD objects. This class takes care of collecting points to build a TIN, of TIN creation itself and
057     * its output as a geometry collection.
058     *
059     * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a>
060     * @author last edited by: $Author: mschneider $
061     *
062     * $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
063     *
064     *
065     */
066    public class VisADWrapper {
067    
068        private static final ILogger LOG = LoggerFactory.getLogger( VisADWrapper.class );
069    
070        /**
071         * A list for hold points representing te DEM/TIN.
072         */
073        private List<Point3d> pointsList;
074    
075        private double scale;
076    
077        /**
078         * Initializes the object by creating a common domain field from the geometrical information (the envelope, the
079         * width and the height) supplied. The envelope cannot the null, nor can the dimensions by < 1.
080         *
081         * @param ptsList
082         *            a list of Points
083         * @param scale
084         *            to multiply to the z-value
085         */
086        public VisADWrapper( List<Point3d> ptsList, double scale ) {
087            this.pointsList = ptsList;
088            this.scale = scale;
089        }
090    
091        /**
092         * Add <code>Point</code>s to the internal list. Lists without any elements (or null lists) are ignored.
093         *
094         * @param points
095         *            to be added to the list
096         */
097        public final void addPoints( List<Point3d> points ) {
098    
099            if ( points == null || points.size() == 0 ) {
100                return;
101            }
102    
103            this.pointsList.addAll( points );
104        }
105    
106        /**
107         * Generates a list of tringles containing the triangles representing the TIN. Triangles are represented float[3][3]
108         *
109         * @return a collection of <code>float[3][3]</code>, each of which representing a TIN triangle
110         *
111         */
112        public final List<float[][]> getTriangleCollectionAsList() {
113    
114            List<float[][]> list = null;
115            try {
116                FlatField tinField = triangulatePoints();
117                if ( tinField == null )
118                    return null;
119                list = toGeoCollectionList( tinField );
120            } catch ( NoClassDefFoundError ncdfe ) {
121                LOG.logError( "WPVS: It seems that the visad library could not be found: " + ncdfe.getLocalizedMessage(),
122                              ncdfe );
123            } catch ( VisADException ve ) {
124                LOG.logError( ve.getLocalizedMessage(), ve );
125            }
126            return list;
127        }
128    
129        /**
130         * Triangulate <code>GM_Point</code>s contained in <code>gmPointsList</code> using the Clarkson algorithm. This
131         * method returns a <code>FlatField</code> containing all points triangulated and with their elevation values.<br/>
132         *
133         * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a>
134         *
135         * @return a <code>FlatField</code> containing a TIN (with an <code>Irregular2DSet</code> as its domain set and
136         *         the elevation values)
137         *
138         */
139        private FlatField triangulatePoints()
140                                             throws NoClassDefFoundError {
141    
142            if ( this.pointsList == null || this.pointsList.size() < 3 ) {
143                throw new IllegalArgumentException( "Points list cannot be null and must contain at least 3 GM_Points." );
144            }
145    
146            // removing double points
147            ArrayList<Point3d> remove = new ArrayList<Point3d>();
148            for ( int i = 0; i < pointsList.size(); ++i ) {
149                Point3d p = pointsList.get( i );
150    
151                if ( !remove.contains( p ) ) {
152                    for ( int j = i + 1; j < pointsList.size(); ++j ) {
153                        Point3d tmpP = pointsList.get( j );
154                        if ( ( Math.abs( tmpP.x - p.x ) < 0.001 ) && ( Math.abs( tmpP.y - p.y ) < 0.001 ) ) {
155                            remove.add( tmpP );
156                        }
157                    }
158                }
159            }
160            for ( Point3d p : remove ) {
161                pointsList.remove( p );
162            }
163            float[][] triPoints = new float[3][this.pointsList.size()];
164            int cnt = 0;
165    
166            for ( Point3d p : this.pointsList ) {
167                triPoints[0][cnt] = (float) p.x;
168                triPoints[1][cnt] = (float) p.y;
169                triPoints[2][cnt++] = (float) ( p.z * scale );
170            }
171    
172            try {
173                FunctionType functionType = new FunctionType( new RealTupleType( RealType.XAxis, RealType.YAxis ),
174                                                              RealType.ZAxis );
175                float[][] ptsXY = new float[][] { triPoints[0], triPoints[1] };
176    
177                // ptsXY = Delaunay.perturb(ptsXY,0.1f, false);
178                // ptsXY = Delaunay.perturb( ptsXY, 5.5f, false );
179                Delaunay delan = Delaunay.factory( ptsXY, false );
180                // Delaunay delan = new DelaunayClarkson( ptsXY );
181                // Delaunay delan = new DelaunayWatson( ptsXY );
182                // DelaunayFast delan = new DelaunayFast( ptsXY );
183                // delan.setNonConvex();
184                try {
185                    // delan.improve( ptsXY, 5 );
186                } catch ( Exception e ) {
187                    // just do noting
188                }
189    
190                // Delaunay delan = new DelaunayClarkson( ptsXY );
191                // Delaunay delan = new DelaunayFast( ptsXY );
192                Irregular2DSet pointsSet = new Irregular2DSet( functionType.getDomain(), ptsXY, null, null, null, delan );
193    
194                FlatField ff = new FlatField( functionType, pointsSet );
195    
196                ff.setSamples( new float[][] { triPoints[2] }, true );
197    
198                return ff;
199    
200            } catch ( VisADException e ) {
201                LOG.logError(e.getMessage(), e );
202                return null;
203            } catch ( RemoteException re ) {
204                LOG.logError(re.getMessage(), re );
205                return null;
206            } catch ( IndexOutOfBoundsException ioobe ) {
207                LOG.logError(ioobe.getMessage(), ioobe );
208                return null;
209            }
210        }
211    
212        /**
213         * Generated a list of triangles from the FlatField passed in as tinField
214         *
215         * @param tinField
216         *            the FlatField containing triangles
217         * @return a collection of <code>float[3][3]</code>, each of which representing a TIN triangle
218         * @throws VisADException
219         *             in the unlikely event that a VisAD exception is thrown
220         * @throws NoClassDefFoundError
221         *             in the unlikely event that the VisAD library could not be found.
222         */
223        private final List<float[][]> toGeoCollectionList( FlatField tinField )
224                                                                               throws NoClassDefFoundError, VisADException {
225            if ( tinField == null ) {
226                throw new RuntimeException( "FlatField cannot be null." );
227            }
228    
229            List<float[][]> geoCollec = new ArrayList<float[][]>( 5000 );
230    
231            Irregular2DSet domainSet = (Irregular2DSet) tinField.getDomainSet();
232            float[][] xyPositions = domainSet.getSamples();
233            float[][] zValues = tinField.getFloats();
234            int[][] indices = domainSet.Delan.Tri;
235    
236            // loop over triangles...
237            for ( int i = 0; i < indices.length; i++ ) {
238    
239                // indices[i].length == coords.length == 3
240                // this is float[3][3] -> 3 points per triabngle, each point with 3 coords
241                float[][] myCoords = new float[3][3];
242    
243                // ...then over points
244                for ( int j = 0; j < indices[i].length; j++ ) {
245    
246                    int index = indices[i][j];
247                    myCoords[j] = new float[3];
248                    myCoords[j][0] = xyPositions[0][index];
249                    myCoords[j][1] = xyPositions[1][index];
250                    myCoords[j][2] = zValues[0][index];
251                }
252    
253                geoCollec.add( myCoords );
254            }
255    
256            tinField = null;
257    
258            return geoCollec;
259        }
260    
261        /**
262         * Clear all points and invalidate list.
263         *
264         */
265        public void clear() {
266            this.pointsList.clear();
267            this.pointsList = null;
268    
269        }
270    
271    }