001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/graphics/displayelements/HorizontalLabel.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.displayelements;
037
038 import java.awt.BasicStroke;
039 import java.awt.Color;
040 import java.awt.Font;
041 import java.awt.Graphics2D;
042 import java.awt.Rectangle;
043 import java.awt.Stroke;
044 import java.awt.TexturePaint;
045 import java.awt.font.LineMetrics;
046 import java.awt.font.TextLayout;
047 import java.awt.geom.AffineTransform;
048 import java.awt.image.BufferedImage;
049
050 import org.deegree.framework.log.ILogger;
051 import org.deegree.framework.log.LoggerFactory;
052 import org.deegree.graphics.sld.Fill;
053 import org.deegree.graphics.sld.GraphicFill;
054 import org.deegree.graphics.sld.Halo;
055 import org.deegree.model.feature.Feature;
056 import org.deegree.model.filterencoding.FilterEvaluationException;
057
058 /**
059 * This is a horizontal label with style information and screen coordinates, ready to be rendered to the view.
060 * <p>
061 *
062 * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider</a>
063 * @version $Revision: 18195 $ $Date: 2009-06-18 17:55:39 +0200 (Do, 18 Jun 2009) $
064 */
065
066 class HorizontalLabel implements Label {
067
068 private static final ILogger LOG = LoggerFactory.getLogger( HorizontalLabel.class );
069
070 private String caption;
071
072 private int[] xpoints = new int[4];
073
074 private int[] ypoints = new int[4];
075
076 // width and height of the caption
077 private int w;
078
079 // width and height of the caption
080 private int h;
081
082 private Color color;
083
084 private Font font;
085
086 private int descent;
087
088 private int ascent;
089
090 private Halo halo;
091
092 private Feature feature;
093
094 private double opacity;
095
096 /**
097 * @param caption
098 * @param font
099 * @param color
100 * @param metrics
101 * @param feature
102 * @param halo
103 * @param x
104 * @param y
105 * @param w
106 * @param h
107 * @param anchorPoint
108 * @param displacement
109 */
110 HorizontalLabel( String caption, Font font, Color color, LineMetrics metrics, Feature feature, Halo halo, int x,
111 int y, int w, int h, double anchorPoint[], double[] displacement, double opacity ) {
112
113 this.opacity = opacity;
114 this.caption = caption;
115 this.font = font;
116 this.color = color;
117 this.descent = (int) metrics.getDescent();
118 this.ascent = (int) metrics.getAscent();
119 this.feature = feature;
120 this.halo = halo;
121
122 this.w = w;
123 this.h = h;
124
125 int dx = (int) ( -anchorPoint[0] * w + displacement[0] + 0.5 );
126 int dy = (int) ( anchorPoint[1] * h - displacement[1] + 0.5 );
127
128 // vertices of label boundary
129 xpoints[0] = x + dx;
130 ypoints[0] = y + dy;
131 xpoints[1] = x + w + dx;
132 ypoints[1] = y + dy;
133 xpoints[2] = x + w + dx;
134 ypoints[2] = y - h + dy;
135 xpoints[3] = x + dx;
136 ypoints[3] = y - h + dy;
137 }
138
139 /**
140 * @return the text
141 *
142 */
143 public String getCaption() {
144 return caption;
145 }
146
147 public void paintBoundaries( Graphics2D g ) {
148 setColor( g, new Color( 0x888888 ), 0.5 );
149 g.fillPolygon( xpoints, ypoints, xpoints.length );
150 g.setColor( Color.BLACK );
151 }
152
153 /**
154 * Renders the label (including halo) to the submitted <tt>Graphics2D</tt> context.
155 * <p>
156 *
157 * @param g
158 * <tt>Graphics2D</tt> context to be used
159 */
160 public void paint( Graphics2D g ) {
161
162 // render the halo (only if specified)
163 if ( halo != null ) {
164 try {
165 paintHalo( g, halo, xpoints[0], ypoints[0] - descent );
166 } catch ( FilterEvaluationException e ) {
167 e.printStackTrace();
168 }
169 }
170
171 // render the text
172 setColor( g, color, opacity );
173 g.setFont( font );
174 g.drawString( caption, xpoints[0], ypoints[0] - descent );
175 }
176
177 /**
178 * Renders the label's halo to the submitted <tt>Graphics2D</tt> context.
179 * <p>
180 *
181 * @param g
182 * <tt>Graphics2D</tt> context to be used
183 *
184 * @throws FilterEvaluationException
185 * if the evaluation of a <tt>ParameterValueType</tt> fails
186 */
187 private void paintHalo( Graphics2D g, Halo halo, int x, int y )
188 throws FilterEvaluationException {
189
190 int radius = (int) halo.getRadius( feature );
191
192 // only draw filled rectangle or circle, if Fill-Element is given
193 Fill fill = halo.getFill();
194
195 if ( fill != null ) {
196 GraphicFill gFill = fill.getGraphicFill();
197
198 if ( gFill != null ) {
199 BufferedImage texture = gFill.getGraphic().getAsImage( feature );
200 Rectangle anchor = new Rectangle( 0, 0, texture.getWidth(), texture.getHeight() );
201 g.setPaint( new TexturePaint( texture, anchor ) );
202 } else {
203 double opacity = fill.getOpacity( feature );
204 Color color = fill.getFill( feature );
205 setColor( g, color, opacity );
206 }
207 if ( radius < 1 ) {
208 g.fillRect( x - 1, y - ascent - 1, w + 2, h + 2 );
209 }
210 } else {
211 g.setColor( Color.white );
212 }
213
214 if ( radius > 0 ) {
215 TextLayout layout = new TextLayout( caption, font, g.getFontRenderContext() );
216
217 BasicStroke stroke = new BasicStroke( radius, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND );
218 Stroke oldStroke = g.getStroke();
219 g.setFont( font );
220 g.setStroke( stroke );
221
222 AffineTransform transform = g.getTransform();
223 AffineTransform oldTransform = (AffineTransform) transform.clone();
224 transform.translate( xpoints[0], ypoints[0] - descent );
225 g.setTransform( transform );
226 g.draw( layout.getOutline( null ) );
227 g.setStroke( oldStroke );
228 g.setTransform( oldTransform );
229 }
230 }
231
232 public int getX() {
233 return xpoints[0];
234 }
235
236 public int getY() {
237 return ypoints[0];
238 }
239
240 public int getMaxX() {
241 return xpoints[1];
242 }
243
244 public int getMaxY() {
245 return ypoints[1];
246 }
247
248 public int getMinX() {
249 return xpoints[3];
250 }
251
252 public int getMinY() {
253 return ypoints[3];
254 }
255
256 /**
257 * Determines if the label intersects with another label.
258 * <p>
259 *
260 * @param that
261 * label to test
262 * @return true if the labels intersect
263 */
264 public boolean intersects( Label that ) {
265
266 if ( !( that instanceof HorizontalLabel ) ) {
267 LOG.logInfo( "Intersection test for rotated labels is not implemented yet!" );
268 return false;
269 }
270
271 // coordinates of this Envelope's BBOX
272 double west1 = getMinX();
273 double south1 = getMinY();
274 double east1 = getMaxX();
275 double north1 = getMaxY();
276
277 // coordinates of the other Envelope's BBOX
278 double west2 = ( (HorizontalLabel) that ).getMinX();
279 double south2 = ( (HorizontalLabel) that ).getMinY();
280 double east2 = ( (HorizontalLabel) that ).getMaxX();
281 double north2 = ( (HorizontalLabel) that ).getMaxY();
282
283 // special cases: one box lays completly inside the other one
284 if ( ( west1 <= west2 ) && ( south1 <= south2 ) && ( east1 >= east2 ) && ( north1 >= north2 ) ) {
285 return true;
286 }
287 if ( ( west1 >= west2 ) && ( south1 >= south2 ) && ( east1 <= east2 ) && ( north1 <= north2 ) ) {
288 return true;
289 }
290 // in any other case of intersection, at least one line of the BBOX has
291 // to cross a line of the other BBOX
292 // check western boundary of box 1
293 // "touching" boxes must not intersect
294 if ( ( west1 >= west2 ) && ( west1 < east2 ) ) {
295 if ( ( south1 <= south2 ) && ( north1 > south2 ) ) {
296 return true;
297 }
298
299 if ( ( south1 < north2 ) && ( north1 >= north2 ) ) {
300 return true;
301 }
302 }
303 // check eastern boundary of box 1
304 // "touching" boxes must not intersect
305 if ( ( east1 > west2 ) && ( east1 <= east2 ) ) {
306 if ( ( south1 <= south2 ) && ( north1 > south2 ) ) {
307 return true;
308 }
309
310 if ( ( south1 < north2 ) && ( north1 >= north2 ) ) {
311 return true;
312 }
313 }
314 // check southern boundary of box 1
315 // "touching" boxes must not intersect
316 if ( ( south1 >= south2 ) && ( south1 < north2 ) ) {
317 if ( ( west1 <= west2 ) && ( east1 > west2 ) ) {
318 return true;
319 }
320
321 if ( ( west1 < east2 ) && ( east1 >= east2 ) ) {
322 return true;
323 }
324 }
325 // check northern boundary of box 1
326 // "touching" boxes must not intersect
327 if ( ( north1 > south2 ) && ( north1 <= north2 ) ) {
328 if ( ( west1 <= west2 ) && ( east1 > west2 ) ) {
329 return true;
330 }
331
332 if ( ( west1 < east2 ) && ( east1 >= east2 ) ) {
333 return true;
334 }
335 }
336 return false;
337 }
338
339 private Graphics2D setColor( Graphics2D g2, Color color, double opacity ) {
340 if ( opacity < 0.999 ) {
341 final int alpha = (int) Math.round( opacity * 255 );
342 final int red = color.getRed();
343 final int green = color.getGreen();
344 final int blue = color.getBlue();
345 color = new Color( red, green, blue, alpha );
346 }
347
348 g2.setColor( color );
349 return g2;
350 }
351
352 @Override
353 public String toString() {
354 return caption;
355 }
356 }