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