001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/graphics/FeatureLayer.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2007 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    package org.deegree.graphics;
045    
046    import java.util.ArrayList;
047    import java.util.List;
048    
049    import org.deegree.model.crs.CoordinateSystem;
050    import org.deegree.model.crs.GeoTransformer;
051    import org.deegree.model.crs.IGeoTransformer;
052    import org.deegree.model.feature.Feature;
053    import org.deegree.model.feature.FeatureCollection;
054    import org.deegree.model.feature.FeatureFactory;
055    import org.deegree.model.feature.FeatureProperty;
056    import org.deegree.model.spatialschema.Envelope;
057    import org.deegree.model.spatialschema.Geometry;
058    import org.deegree.model.spatialschema.GeometryFactory;
059    import org.deegree.model.spatialschema.Point;
060    import org.deegree.model.spatialschema.Position;
061    
062    /**
063     * A Layer is a collection of <tt>Feature</tt>s building a thematic 'unit' waterways or country
064     * borders for example. <tt>Feature</tt>s can be added or removed from the layer. A
065     * <tt>Feature</tt> can e changed by a modul of the application using the layer because only
066     * references to <tt>Feature</tt>s are stored within a layer.
067     *
068     * 
069     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
070     * @version $Revision: 7821 $ $Date: 2007-07-24 09:56:01 +0200 (Di, 24 Jul 2007) $
071     */
072    
073    public class FeatureLayer extends AbstractLayer {
074    
075        private FeatureCollection fc = null;
076    
077        /**
078         * creates a layer with EPSG:4326 as default coordinate system
079         */
080        FeatureLayer( String name ) throws Exception {
081            super( name );
082    
083            fc = FeatureFactory.createFeatureCollection( name, 50 );
084    
085            init( fc );
086        }
087    
088        /**
089         * Creates a new FeatureLayer object.
090         * 
091         * @param name
092         * @param crs
093         * 
094         * @throws Exception
095         */
096        FeatureLayer( String name, CoordinateSystem crs ) throws Exception {
097            super( name, crs );
098    
099            fc = FeatureFactory.createFeatureCollection( name, 50 );
100    
101            init( fc );
102        }
103    
104        /**
105         * Creates a new AbstractLayer object.
106         * 
107         * @param name
108         * @param crs
109         * @param fc
110         * 
111         * @throws Exception
112         */
113        FeatureLayer( String name, CoordinateSystem crs, FeatureCollection fc ) throws Exception {
114            super( name, crs );
115            init( fc );
116        }
117    
118        /**
119         * initializes serveral parameters of the layer and homogenizes the coordinate reference systems
120         * of the features
121         * @param feature
122         * @throws Exception
123         */
124        private void init( FeatureCollection feature ) throws Exception {
125    
126            this.fc = FeatureFactory.createFeatureCollection( feature.getId(), feature.size() );
127            // create object for coordinate transformation
128            IGeoTransformer gt = new GeoTransformer( cs );
129            double minx = 9E99;
130            double maxx = -9E99;
131            double miny = 9E99;
132            double maxy = -9E99;
133            String s1 = cs.getName();
134            for (int i = 0; i < feature.size(); i++) {                
135                Feature feat = feature.getFeature( i );
136                FeatureProperty[] prop = feat.getProperties();
137                FeatureProperty[] propN = new FeatureProperty[prop.length];
138                boolean changed = false;
139                for (int k = 0; k < prop.length; k++) {
140    
141                    Object value = prop[k].getValue();    
142                    propN[k] = prop[k]; 
143                    if ( value instanceof Geometry ) {
144                        
145                        CoordinateSystem _cs_ = ( (Geometry) value ).getCoordinateSystem();
146                        String s2 = null;
147                        if ( _cs_ != null ) {
148                            s2 = _cs_.getName();
149                        } else {
150                            // default reference system
151                            s2 = "EPSG:4326";
152                        }
153    
154                        if ( !s1.equalsIgnoreCase( s2 ) ) {
155                            Geometry transformedGeometry = gt.transform( (Geometry) value );                        
156                            propN[k] = FeatureFactory.createFeatureProperty( prop[k].getName(),
157                                                                             transformedGeometry );
158                            changed = true;                      
159                            value = transformedGeometry;
160                        }
161                        if ( value instanceof Point ) {
162                            Position pos = ( (Point) value ).getPosition();
163                            if ( pos.getX() > maxx ) {
164                                maxx = pos.getX();
165                            }
166                            if ( pos.getX() < minx ) {
167                                minx = pos.getX();
168                            }
169                            if ( pos.getY() > maxy ) {
170                                maxy = pos.getY();
171                            }
172                            if ( pos.getY() < miny ) {
173                                miny = pos.getY();
174                            }
175                        } else {
176                            Envelope en = ( (Geometry) value ).getEnvelope();
177                            if ( en.getMax().getX() > maxx ) {
178                                maxx = en.getMax().getX();
179                            }
180                            if ( en.getMin().getX() < minx ) {
181                                minx = en.getMin().getX();
182                            }
183                            if ( en.getMax().getY() > maxy ) {
184                                maxy = en.getMax().getY();
185                            }
186                            if ( en.getMin().getY() < miny ) {
187                                miny = en.getMin().getY();
188                            }
189                        }
190                    }
191                }
192                if ( changed ) {
193                    FeatureProperty[] fp = new FeatureProperty[propN.length];
194                    for (int j = 0; j < fp.length; j++) {                    
195                        fp[j] = FeatureFactory.createFeatureProperty( propN[j].getName(), 
196                                                                      propN[j].getValue() );
197                    }
198                    feat = FeatureFactory.createFeature( feat.getId(), feat.getFeatureType(), fp );
199                }
200                fc.add( feat );
201            }
202    
203            boundingbox = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, null );
204    
205        }
206    
207        /**
208         * 
209         *
210         */
211        private void recalculateBoundingbox() {
212    
213            double minx = 9E99;
214            double maxx = -9E99;
215            double miny = 9E99;
216            double maxy = -9E99;
217    
218            for (int i = 0; i < fc.size(); i++) {
219                Geometry[] prop = fc.getFeature( i ).getGeometryPropertyValues();
220                for (int k = 0; k < prop.length; k++) {
221                    if ( prop[k] instanceof Point ) {
222                        Position pos = ( (Point) prop[k] ).getPosition();
223                        if ( pos.getX() > maxx ) {
224                            maxx = pos.getX();
225                        }
226                        if ( pos.getX() < minx ) {
227                            minx = pos.getX();
228                        }
229                        if ( pos.getY() > maxy ) {
230                            maxy = pos.getY();
231                        }
232                        if ( pos.getY() < miny ) {
233                            miny = pos.getY();
234                        }
235                    } else {
236                        Envelope en = ( prop[k] ).getEnvelope();
237                        if ( en.getMax().getX() > maxx ) {
238                            maxx = en.getMax().getX();
239                        }
240                        if ( en.getMin().getX() < minx ) {
241                            minx = en.getMin().getX();
242                        }
243                        if ( en.getMax().getY() > maxy ) {
244                            maxy = en.getMax().getY();
245                        }
246                        if ( en.getMin().getY() < miny ) {
247                            miny = en.getMin().getY();
248                        }
249                    }
250                }
251            }
252    
253            boundingbox = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, null );
254    
255        }
256    
257        /**
258         * returns the feature that matches the submitted id
259         * @param id
260         * @return feature identified by its id
261         */
262        public Feature getFeatureById( String id ) {
263            return fc.getFeature( id );
264        }
265    
266        /**
267         * returns the feature that matches the submitted id
268         * @param ids
269         * @return features identified by their id
270         */
271        public Feature[] getFeaturesById( String[] ids ) {
272    
273            List<Feature> list = new ArrayList<Feature>();
274    
275            Feature feature = null;
276    
277            for (int i = 0; i < fc.size(); i++) {
278                feature = fc.getFeature( i );
279    
280                for (int k = 0; k < ids.length; k++) {
281                    if ( feature.getId().equals( ids[k] ) ) {
282                        list.add( feature );
283                        break;
284                    }
285                }
286            }
287    
288            return list.toArray( new Feature[list.size()] );
289        }
290    
291        /**
292         * returns the feature that matches the submitted index
293         * @param index
294         * @return a feature
295         */
296        public Feature getFeature( int index ) {
297            Feature feature = fc.getFeature( index );
298            return feature;
299        }
300    
301        /**
302         * returns all features
303         * @return all features as array
304         */
305        public Feature[] getAllFeatures() {
306            return fc.toArray();
307        }
308    
309        /**
310         * adds a feature to the layer
311         * @param feature
312         * @throws Exception
313         */
314        public void addFeature( Feature feature ) throws Exception {
315            fc.add( feature );
316            recalculateBoundingbox();
317        }
318    
319        /**
320         * adds a feature collection to the layer
321         * @param featureCollection
322         * @throws Exception
323         */
324        public void addFeatureCollection( FeatureCollection featureCollection ) throws Exception {
325            fc.add( featureCollection );
326            recalculateBoundingbox();
327        }
328    
329        /**
330         * removes a display Element from the layer
331         * @param feature
332         * @throws Exception
333         */
334        public void removeFeature( Feature feature ) throws Exception {
335            fc.remove( feature );
336            recalculateBoundingbox();
337        }
338    
339        /**
340         * removes the display Element from the layer that matches the submitted id
341         * @param id
342         * @throws Exception
343         */
344        public void removeFeature( int id ) throws Exception {
345            removeFeature( getFeature( id ) );
346        }
347    
348        /**
349         * returns the amount of features within the layer.
350         * @return number of contained features
351         */
352        public int getSize() {
353            return fc.size();
354        }
355    
356        /**
357         * sets the coordinate reference system of the MapView. If a new crs is set all geometries of
358         * GeometryFeatures will be transformed to the new coordinate reference system.
359         * @param crs
360         * @throws Exception
361         */
362        public void setCoordinatesSystem( CoordinateSystem crs ) throws Exception {
363            if ( !cs.equals( crs ) ) {
364                this.cs = crs;
365                init( fc );
366            }
367        }
368    }