001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/graphics/displayelements/ScaledFeature.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    package org.deegree.graphics.displayelements;
044    
045    import java.util.HashMap;
046    import java.util.Map;
047    
048    import org.deegree.datatypes.QualifiedName;
049    import org.deegree.datatypes.Types;
050    import org.deegree.io.datastore.PropertyPathResolvingException;
051    import org.deegree.model.feature.Feature;
052    import org.deegree.model.feature.FeatureFactory;
053    import org.deegree.model.feature.FeatureProperty;
054    import org.deegree.model.feature.schema.FeatureType;
055    import org.deegree.model.feature.schema.PropertyType;
056    import org.deegree.model.spatialschema.Envelope;
057    import org.deegree.model.spatialschema.Geometry;
058    import org.deegree.model.spatialschema.GeometryException;
059    import org.deegree.ogcbase.PropertyPath;
060    
061    /**
062     * This class is a wrapper for a Feature and a Feature itself.
063     * <p>
064     * It adds a special behavior/property to a feature that is required by deegree DisplayElements.
065     * This special behavior is an additional property named "$SCALE". In opposite to conventional
066     * properties this one can change its value during lifetime of a feature without changing the
067     * underlying feature itself. <br>
068     * The class is use to offer users the opportunity to use the scale of a map within expressions
069     * embedded in SLD rules/symbolizers, i.e. this enables a user to define that a symbol shall appear
070     * in 10m size independ of a map's scale.
071     * 
072     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
073     * @author last edited by: $Author: apoth $
074     * 
075     * @version $Revision: 9340 $, $Date: 2007-12-27 13:32:12 +0100 (Do, 27 Dez 2007) $
076     */
077    public class ScaledFeature implements Feature {
078    
079        private Feature feature;
080    
081        private FeatureType ft;
082    
083        private FeatureProperty[] props;
084    
085        private Map<String, String> attributeMap = new HashMap<String, String>();
086    
087        /**
088         * 
089         * @param feature
090         *            feature wrap
091         * @param scale
092         *            maps scale (should be -1 if not known)
093         */
094        public ScaledFeature( Feature feature, double scale ) {
095            this.feature = feature;
096            PropertyType[] ftp = feature.getFeatureType().getProperties();
097            PropertyType[] ftp2 = new PropertyType[ftp.length + 1];
098            for ( int i = 0; i < ftp.length; i++ ) {
099                ftp2[i] = ftp[i];
100            }
101            QualifiedName qn = new QualifiedName( feature.getName().getPrefix(), "$SCALE", feature.getName().getNamespace() );
102            ftp2[ftp2.length - 1] = FeatureFactory.createSimplePropertyType( qn, Types.DOUBLE, false );
103            FeatureProperty[] o = feature.getProperties();
104            props = new FeatureProperty[o.length + 1];
105            for ( int i = 0; i < o.length; i++ ) {
106                props[i] = o[i];
107            }
108            props[props.length - 1] = FeatureFactory.createFeatureProperty( qn, new Double( scale ) );
109            ft = FeatureFactory.createFeatureType( feature.getFeatureType().getName(), false, ftp2 );
110        }
111    
112        /**
113         * @return features owner
114         */
115        public FeatureProperty getOwner() {
116            return feature.getOwner();
117        }
118    
119        /**
120         * @return feature description
121         */
122        public String getDescription() {
123            return feature.getDescription();
124        }
125    
126        /**
127         * @return features name
128         */
129        public QualifiedName getName() {
130            return feature.getName();
131        }
132    
133        /**
134         * @see Feature#getDefaultGeometryPropertyValue()
135         */
136        public Geometry getDefaultGeometryPropertyValue() {
137            return feature.getDefaultGeometryPropertyValue();
138        }
139    
140        /**
141         * @return features envelope
142         */
143        public Envelope getBoundedBy()
144                                throws GeometryException {
145            return feature.getBoundedBy();
146        }
147    
148        /**
149         * @see Feature#getFeatureType() the returned feature type contains all properties of the
150         *      wrapped feature plus a property named '$SCALE'
151         */
152        public FeatureType getFeatureType() {
153            return ft;
154        }
155    
156        /**
157         * @see Feature#getGeometryPropertyValues()
158         */
159        public Geometry[] getGeometryPropertyValues() {
160            return feature.getGeometryPropertyValues();
161        }
162    
163        /**
164         * @see Feature#getId()
165         */
166        public String getId() {
167            return feature.getId();
168        }
169    
170        /**
171         * @see Feature#getProperties() the returned array contains all properties of the wrapped
172         *      feature plus a property named '$SCALE'
173         */
174        public FeatureProperty[] getProperties() {
175            return props;
176        }
177    
178        /**
179         * @see Feature#getProperties(int) The property '$SCALE' has the highest valid index
180         */
181        public FeatureProperty[] getProperties( int index ) {
182            return new FeatureProperty[] { props[index] };
183        }
184    
185        /**
186         * @see Feature#getDefaultProperty(String) use '$SCALE' to access the scale property value
187         */
188        public FeatureProperty getDefaultProperty( QualifiedName name ) {
189            QualifiedName qn = new QualifiedName( "$SCALE" );
190            if ( name.equals( qn ) ) {
191                return props[props.length - 1];
192            }
193            return feature.getDefaultProperty( name );
194        }
195    
196        /**
197         * @param name
198         * @return property array
199         */
200        public FeatureProperty[] getProperties( QualifiedName name ) {
201            if ( name.getLocalName().equalsIgnoreCase( "$SCALE" ) ) {
202                return new FeatureProperty[] { props[props.length - 1] };
203            }
204            return feature.getProperties( name );
205        }
206    
207        /**
208         * @param path
209         * @return property
210         */
211        public FeatureProperty getDefaultProperty( PropertyPath path )
212                                throws PropertyPathResolvingException {
213            if ( path.getStep( 0 ).getPropertyName().getLocalName().equalsIgnoreCase( "$SCALE" ) ) {
214                return props[props.length - 1];
215            }
216            return feature.getDefaultProperty( path );
217        }
218    
219        /**
220         * @see Feature#setProperty(FeatureProperty)
221         */
222        public void setProperty( FeatureProperty property, int index ) {
223            feature.setProperty( property, index );
224        }
225    
226        /**
227         * sets the features scale. Expected is the scale denominator as defined by OGC SLD
228         * specification
229         * 
230         * @param scale
231         */
232        public void setScale( double scale ) {
233            // must be multiplied with pixel size to get scale as length
234            // of a pixels diagonal measured in meter
235            props[props.length - 1].setValue( scale * 0.00028 );
236        }
237    
238        /**
239         * returns the features scale
240         * 
241         * @return the features scale
242         */
243        public double getScale() {
244            return ( (Double) props[props.length - 1].getValue() ).doubleValue();
245        }
246    
247        /**
248         * @param property
249         */
250        public void addProperty( FeatureProperty property ) {
251            this.feature.addProperty( property );
252        }
253    
254        /**
255         * @param propertyName
256         */
257        public void removeProperty( QualifiedName propertyName ) {
258            this.feature.removeProperty( propertyName );
259        }
260    
261        /**
262         * @param oldProperty
263         * @param newProperty
264         */
265        public void replaceProperty( FeatureProperty oldProperty, FeatureProperty newProperty ) {
266            this.feature.replaceProperty( oldProperty, newProperty );
267        }
268    
269        /**
270         * @param fid
271         */
272        public void setId( String fid ) {
273            feature.setId( fid );
274        }
275    
276        /**
277         * Returns the attribute value of the attribute with the specified name.
278         * 
279         * @param name
280         *            name of the attribute
281         * @return the attribute value
282         */
283        public String getAttribute( String name ) {
284            return this.attributeMap.get( name );
285        }
286    
287        /**
288         * Returns all attributes of the feature.
289         * 
290         * @return all attributes, keys are names, values are attribute values
291         */
292        public Map<String, String> getAttributes() {
293            return this.attributeMap;
294        }
295    
296        /**
297         * Sets the value of the attribute with the given name.
298         * 
299         * @param name
300         *            name of the attribute
301         * @param value
302         *            value to set
303         */
304        public void setAttribute( String name, String value ) {
305            this.attributeMap.put( name, value );
306        }
307    
308        /**
309         * Sets the feature type of this feature.
310         * 
311         * @param ft
312         *            feature type to set
313         */
314        public void setFeatureType( FeatureType ft ) {
315            feature.setFeatureType( ft );
316        }
317    
318        /*
319         * (non-Javadoc)
320         * 
321         * @see org.deegree.model.feature.Feature#setEnvelopesUpdated()
322         */
323        public void setEnvelopesUpdated() {
324            feature.setEnvelopesUpdated();
325        }
326    }