001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/graphics/sld/PointPlacement.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    package org.deegree.graphics.sld;
045    
046    import org.deegree.framework.log.ILogger;
047    import org.deegree.framework.log.LoggerFactory;
048    import org.deegree.framework.xml.Marshallable;
049    import org.deegree.model.feature.Feature;
050    import org.deegree.model.filterencoding.FilterEvaluationException;
051    
052    /**
053     * Incarnation of a sld:PointPlacement-element. For a PointPlacement, the anchor point of the label
054     * and a linear displacement from the point can be specified, to allow a graphic symbol to be
055     * plotted directly at the point. This might be useful to label a city, for example. For a
056     * LinePlacement, a perpendicular offset can be specified, to allow the line itself to be plotted
057     * also. This might be useful for labelling a road or a river, for example.
058     * <p>
059     * 
060     * 
061     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
062     * @author last edited by: $Author: apoth $
063     * 
064     * @version. $Revision: 9340 $, $Date: 2007-12-27 13:32:12 +0100 (Do, 27 Dez 2007) $
065     */
066    public class PointPlacement implements Marshallable {
067    
068        private static final ILogger LOG = LoggerFactory.getLogger( PointPlacement.class );
069    
070        private ParameterValueType rotation = null;
071    
072        private ParameterValueType[] anchorPoint = null;
073    
074        private ParameterValueType[] displacement = null;
075    
076        // should the placement be optimized?
077        private boolean auto = false;
078    
079        /**
080         * package protected default constructor
081         * 
082         */
083        PointPlacement() {
084    
085        }
086    
087        /**
088         * Creates a new PointPlacement object.
089         * 
090         * @param anchorPoint
091         * @param displacement
092         * @param rotation
093         */
094        public PointPlacement( ParameterValueType[] anchorPoint, ParameterValueType[] displacement,
095                               ParameterValueType rotation, boolean auto ) {
096            this.anchorPoint = anchorPoint;
097            this.displacement = displacement;
098            this.rotation = rotation;
099            this.auto = auto;
100        }
101    
102        /**
103         * returns the anchor points (x and y) as array of
104         * 
105         * @see ParameterValueType
106         * @return anchor point as
107         * @see ParameterValueType
108         */
109        public ParameterValueType[] getAnchorPoint() {
110            return anchorPoint;
111        }
112    
113        /**
114         * returns the displacements (x and y) as array of
115         * 
116         * @see ParameterValueType
117         * @return displacements (x and y) as array of
118         * @see ParameterValueType
119         */
120        public ParameterValueType[] getDisplacement() {
121            return displacement;
122        }
123    
124        /**
125         * returns the rotation of
126         * 
127         * @see ParameterValueType
128         * @return
129         */
130        public ParameterValueType getRotation() {
131            return rotation;
132        }
133    
134        /**
135         * The AnchorPoint element of a PointPlacement gives the location inside of a label to use for
136         * anchoring the label to the main-geometry point.
137         * <p>
138         * </p>
139         * The coordinates are given as two floating-point numbers in the AnchorPointX and AnchorPointY
140         * elements each with values between 0.0 and 1.0 inclusive. The bounding box of the label to be
141         * rendered is considered to be in a coorindate space from 0.0 (lower-left corner) to 1.0
142         * (upper-right corner), and the anchor position is specified as a point in this space. The
143         * default point is X=0, Y=0.5, which is at the middle height of the left-hand side of the
144         * label. A system may choose different anchor points to de-conflict labels.
145         * <p>
146         * 
147         * @param feature
148         *            specifies the <tt>Feature</tt> to be used for evaluation of the underlying
149         *            'sld:ParameterValueType'
150         * @return 2 double values: x ([0]) and y ([0])
151         * @throws FilterEvaluationException
152         *             if the evaluation fails
153         */
154        public double[] getAnchorPoint( Feature feature )
155                                throws FilterEvaluationException {
156            double[] anchorPointVal = { 0.0, 0.5 };
157    
158            if ( anchorPoint != null ) {
159                anchorPointVal[0] = Double.parseDouble( anchorPoint[0].evaluate( feature ) );
160                anchorPointVal[1] = Double.parseDouble( anchorPoint[1].evaluate( feature ) );
161            }
162    
163            return anchorPointVal;
164        }
165    
166        /**
167         * @see PointPlacement#getAnchorPoint(Feature)
168         *      <p>
169         * @param anchorPoint
170         *            anchorPoint for the PointPlacement
171         */
172        public void setAnchorPoint( double[] anchorPoint ) {
173            ParameterValueType pvt = null;
174            ParameterValueType[] pvtArray = new ParameterValueType[anchorPoint.length];
175            for ( int i = 0; i < anchorPoint.length; i++ ) {
176                pvt = StyleFactory.createParameterValueType( "" + anchorPoint[i] );
177                pvtArray[i] = pvt;
178            }
179            this.anchorPoint = pvtArray;
180        }
181    
182        /**
183         * The Displacement element of a PointPlacement gives the X and Y displacements from the
184         * main-geometry point to render a text label.
185         * <p>
186         * </p>
187         * This will often be used to avoid over-plotting a graphic symbol marking a city or some such
188         * feature. The displacements are in units of pixels above and to the right of the point. A
189         * system may reflect this displacement about the X and/or Y axes to de-conflict labels. The
190         * default displacement is X=0, Y=0.
191         * <p>
192         * 
193         * @param feature
194         *            specifies the <tt>Feature</tt> to be used for evaluation of the underlying
195         *            'sld:ParameterValueType'
196         * @return 2 double values: x ([0]) and y ([0])
197         * @throws FilterEvaluationException
198         *             if the evaluation fails*
199         */
200        public double[] getDisplacement( Feature feature )
201                                throws FilterEvaluationException {
202            double[] displacementVal = { 0.0, 0.0 };
203    
204            if ( displacement != null ) {
205                displacementVal[0] = Double.parseDouble( displacement[0].evaluate( feature ) );
206                displacementVal[1] = Double.parseDouble( displacement[1].evaluate( feature ) );
207            }
208    
209            return displacementVal;
210        }
211    
212        /**
213         * @see PointPlacement#getDisplacement(Feature)
214         *      <p>
215         * @param displacement
216         */
217        public void setDisplacement( double[] displacement ) {
218            ParameterValueType pvt = null;
219            ParameterValueType[] pvtArray = new ParameterValueType[displacement.length];
220            for ( int i = 0; i < displacement.length; i++ ) {
221                pvt = StyleFactory.createParameterValueType( "" + displacement[i] );
222                pvtArray[i] = pvt;
223            }
224            this.displacement = pvtArray;
225        }
226    
227        /**
228         * The Rotation of a PointPlacement gives the clockwise rotation of the label in degrees from
229         * the normal direction for a font (left-to-right for Latin- derived human languages at least).
230         * <p>
231         * 
232         * @param feature
233         *            specifies the <tt>Feature</tt> to be used for evaluation of the underlying
234         *            'sld:ParameterValueType'
235         * @return double value describing the rotation parameter
236         * @throws FilterEvaluationException
237         *             if the evaluation fails*
238         */
239        public double getRotation( Feature feature )
240                                throws FilterEvaluationException {
241            double rot = 0.0;
242    
243            if ( rotation != null ) {
244                String tmp = rotation.evaluate( feature );
245                if ( tmp != null ) {
246                    try {
247                        rot = Double.parseDouble( tmp );
248                    } catch ( NumberFormatException e ) {
249                        LOG.logInfo( "could not parse rotation value as float, use 0° as default: ", tmp );
250                    }
251                }
252            }
253    
254            return rot;
255        }
256    
257        /**
258         * @see PointPlacement#getRotation(Feature)
259         * @param rotation
260         *            the rotation to be set for the PointPlacement
261         */
262        public void setRotation( double rotation ) {
263            ParameterValueType pvt = null;
264            pvt = StyleFactory.createParameterValueType( "" + rotation );
265            this.rotation = pvt;
266        }
267    
268        /**
269         * Returns whether the placement should be optimized or not.
270         * <p>
271         * 
272         * @return true, if it should be optimized
273         * 
274         */
275        public boolean isAuto() {
276            return auto;
277        }
278    
279        /**
280         * <p>
281         * 
282         * @param auto
283         * 
284         */
285        public void setAuto( boolean auto ) {
286            this.auto = auto;
287        }
288    
289        /**
290         * exports the content of the PointPlacement as XML formated String
291         * 
292         * @return xml representation of the PointPlacement
293         */
294        public String exportAsXML() {
295    
296            StringBuffer sb = new StringBuffer( 1000 );
297            sb.append( "<PointPlacement" );
298            if ( auto ) {
299                sb.append( " auto='true'" );
300            }
301            sb.append( ">" );
302            if ( anchorPoint != null && anchorPoint.length > 1 ) {
303                sb.append( "<AnchorPoint>" ).append( "<AnchorPointX>" );
304                sb.append( ( (Marshallable) anchorPoint[0] ).exportAsXML() );
305                sb.append( "</AnchorPointX>" ).append( "<AnchorPointY>" );
306                sb.append( ( (Marshallable) anchorPoint[1] ).exportAsXML() );
307                sb.append( "</AnchorPointY>" ).append( "</AnchorPoint>" );
308            }
309            if ( displacement != null && displacement.length > 1 ) {
310                sb.append( "<Displacement>" ).append( "<DisplacementX>" );
311                sb.append( ( (Marshallable) displacement[0] ).exportAsXML() );
312                sb.append( "</DisplacementX>" ).append( "<DisplacementY>" );
313                sb.append( ( (Marshallable) displacement[1] ).exportAsXML() );
314                sb.append( "</DisplacementY>" ).append( "</Displacement>" );
315            }
316            if ( rotation != null ) {
317                sb.append( "<Rotation>" );
318                sb.append( ( (Marshallable) rotation ).exportAsXML() );
319                sb.append( "</Rotation>" );
320            }
321    
322            sb.append( "</PointPlacement>" );
323    
324            return sb.toString();
325        }
326    }