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 }