/* ********************************************************************** * * ROLANDS & ASSOCIATES Corporation * 500 Sloat Avenue * Monterey, CA 93940 * (831) 373-2025 * * Copyright (C) 2002, 2003 ROLANDS & ASSOCIATES Corporation. All rights reserved. * Openmap is a trademark of BBN Technologies, A Verizon Company * * * ********************************************************************** * * $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/ScaleDisplayLayer.java,v $ * $Revision: 1.9 $ * $Date: 2005/12/09 21:09:08 $ * $Author: dietrick $ * * ********************************************************************** */ package com.bbn.openmap.layer; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Properties; import java.util.Vector; import java.util.logging.Logger; import javax.swing.ButtonGroup; import javax.swing.JPanel; import javax.swing.JRadioButton; import com.bbn.openmap.omGraphics.DrawingAttributes; import com.bbn.openmap.omGraphics.OMColor; import com.bbn.openmap.omGraphics.OMGraphicList; import com.bbn.openmap.omGraphics.OMLine; import com.bbn.openmap.omGraphics.OMText; import com.bbn.openmap.proj.Length; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.proj.coords.LatLonPoint; import com.bbn.openmap.util.PropUtils; /** * Layer objects are components which can be added to the MapBean to make a map. * <p> * Layers implement the ProjectionListener interface to listen for * ProjectionEvents. When the projection changes, they may need to re-fetch, * regenerate their graphics, and then repaint themselves into the new view. * <p> * <pre> * * ### Layer used by the overview handler * scaleLayer.class=com.rolands.jtlsweb.map.layer.ScaleDisplayLayer * scaleLayer.prettyName=Scale * scaleLayer.lineColor=ff777777 * scaleLayer.textColor=ff000000 * scaleLayer.unitOfMeasure=nm * scaleLayer.locationXoffset=-10 * scaleLayer.locationYoffset=-20 * scaleLayer.width=150 * scaleLayer.height=10 * * # unitOfMeasure - any com.bbn.openmap.proj.Length instance returned by Length.get(string). * # locationXoffset - offset in pixels from left/right, positive from left edge, negative from right edge * # locationYoffset - offset in pixels from top/bottom, positive from top edge, negative from bottom edge * # width - width of scale indicator bar in pixels * # height - height of scale indicator bar in pixels * * </pre> */ public class ScaleDisplayLayer extends OMGraphicHandlerLayer { public ScaleDisplayLayer() { super(); setProjectionChangePolicy(new com.bbn.openmap.layer.policy.ListResetPCPolicy(this)); setUnitOfMeasure(Length.KM.toString()); } protected Logger logger = Logger.getLogger("com.bbn.openmap.layer.ScaleDisplayLayer"); // Color variables for different line types protected java.awt.Color lineColor = null; protected java.awt.Color textColor = null; // Default colors to use, if not specified in the properties. protected String defaultLineColorString = "FFFFFF"; protected String defaultTextColorString = "FFFFFF"; protected String defaultUnitOfMeasureString = "km"; protected int defaultLocationXoffset = -10; protected int defaultLocationYoffset = -10; protected int defaultWidth = 150; protected int defaultHeight = 10; // property text values public static final String UnitOfMeasureProperty = "unitOfMeasure"; public static final String LocationXOffsetProperty = "locationXoffset"; public static final String LocationYOffsetProperty = "locationYoffset"; public static final String WidthProperty = "width"; public static final String HeightProperty = "height"; protected String unitOfMeasure = null; protected Length uom = Length.get(defaultUnitOfMeasureString); protected String uomAbbr = uom.getAbbr(); protected int locationXoffset = defaultLocationXoffset; protected int locationYoffset = defaultLocationYoffset; protected int width = defaultWidth; protected int height = defaultHeight; protected DrawingAttributes dAttributes = DrawingAttributes.getDefaultClone(); /** * Sets the properties for the <code>Layer</code>. This allows * <code>Layer</code> s to get a richer set of parameters than the * <code>setArgs</code> method. * * @param prefix the token to prefix the property names * @param properties the <code>Properties</code> object */ public void setProperties(String prefix, Properties properties) { super.setProperties(prefix, properties); prefix = PropUtils.getScopedPropertyPrefix(prefix); dAttributes.setProperties(prefix, properties); String unitOfMeasureString = properties.getProperty(prefix + UnitOfMeasureProperty); if (unitOfMeasureString != null) { setUnitOfMeasure(unitOfMeasureString); } locationXoffset = PropUtils.intFromProperties(properties, prefix + LocationXOffsetProperty, defaultLocationXoffset); locationYoffset = PropUtils.intFromProperties(properties, prefix + LocationYOffsetProperty, defaultLocationYoffset); width = PropUtils.intFromProperties(properties, prefix + WidthProperty, defaultWidth); height = PropUtils.intFromProperties(properties, prefix + HeightProperty, defaultHeight); } public Properties getProperties(Properties props) { props = super.getProperties(props); String prefix = PropUtils.getScopedPropertyPrefix(this); dAttributes.setProperties(props); props.put(prefix + LocationXOffsetProperty, Integer.toString(locationXoffset)); props.put(prefix + LocationYOffsetProperty, Integer.toString(locationYoffset)); props.put(prefix + WidthProperty, Integer.toString(width)); props.put(prefix + HeightProperty, Integer.toString(height)); props.put(prefix + UnitOfMeasureProperty, unitOfMeasure); return props; } public synchronized OMGraphicList prepare() { int w, h, left_x = 0, right_x = 0, lower_y = 0, upper_y = 0; Projection projection = getProjection(); OMGraphicList graphics = new OMGraphicList(); w = projection.getWidth(); h = projection.getHeight(); if (locationXoffset < 0) { left_x = w + locationXoffset - width; right_x = w + locationXoffset; } else if (locationXoffset >= 0) { left_x = locationXoffset; right_x = locationXoffset + width; } if (locationYoffset < 0) { upper_y = h + locationYoffset - height; lower_y = h + locationYoffset; } else if (locationYoffset >= 0) { upper_y = locationYoffset; lower_y = locationYoffset + height; } graphics.clear(); OMLine line = new OMLine(left_x, lower_y, right_x, lower_y); dAttributes.setTo(line); graphics.add(line); line = new OMLine(left_x, lower_y, left_x, upper_y); dAttributes.setTo(line); graphics.add(line); line = new OMLine(right_x, lower_y, right_x, upper_y); dAttributes.setTo(line); graphics.add(line); /* * We need to use better coordinates to measure distance, like the same * pixel distance at the center of the map. There's a problem using the * lower right location, in that those distances decrease as you zoom out. */ int y = h / 2; int x = w / 2; int xSide = (right_x - left_x) / 2; LatLonPoint loc1 = projection.inverse(x - xSide, y, new LatLonPoint.Double()); LatLonPoint loc2 = projection.inverse(x + xSide, y, new LatLonPoint.Double()); double dist = uom.fromRadians(loc1.distance(loc2)); String outtext; if (dist < 1.0f) { outtext = String.format("%.3f %s", dist, uomAbbr); } else if (dist < 10.0f) { outtext = String.format("%.2f %s", dist, uomAbbr); } else if (dist < 100.0f) { outtext = String.format("%.1f %s", dist, uomAbbr); } else { outtext = String.format("%.0f %s", dist, uomAbbr); } OMText text = new OMText((left_x + right_x) / 2, lower_y - 3, "" + outtext, OMText.JUSTIFY_CENTER); Font font = text.getFont(); text.setFont(font.deriveFont(font.getStyle(), font.getSize() + 4)); dAttributes.setTo(text); text.setTextMatteColor((Color) dAttributes.getMattingPaint()); text.setTextMatteStroke(new BasicStroke(5)); text.setMattingPaint(OMColor.clear); graphics.add(text); graphics.generate(projection); return graphics; } /** * Getter for property unitOfMeasure. * * @return Value of property unitOfMeasure. */ public String getUnitOfMeasure() { return this.unitOfMeasure; } /** * Setter for property unitOfMeasure. * * @param unitOfMeasure New value of property unitOfMeasure. * * @throws PropertyVetoException */ public void setUnitOfMeasure(String unitOfMeasure) { if (unitOfMeasure == null) unitOfMeasure = Length.KM.toString(); this.unitOfMeasure = unitOfMeasure; // There is a bug in the Length.get() method that will not // return // the correct (or any value) for a requested uom. // This does not work: // uom = com.bbn.openmap.proj.Length.get(unitOfMeasure); // Therefore, The following code correctly obtains the proper // Length object. Length[] choices = Length.values(); uom = null; for (int i = 0; i < choices.length; i++) { if (unitOfMeasure.equalsIgnoreCase(choices[i].toString()) || unitOfMeasure.equalsIgnoreCase(choices[i].getAbbr())) { uom = choices[i]; break; } } // of no uom is found assign Kilometers as the default. if (uom == null) uom = Length.KM; uomAbbr = uom.getAbbr(); } JPanel palettePanel; ButtonGroup uomButtonGroup; Vector<JRadioButton> buttons = new Vector<JRadioButton>(); /** Creates the interface palette. */ public java.awt.Component getGUI() { if (palettePanel == null) { logger.fine("creating palette."); palettePanel = new JPanel(); uomButtonGroup = new ButtonGroup(); palettePanel.setLayout(new javax.swing.BoxLayout(palettePanel, javax.swing.BoxLayout.Y_AXIS)); palettePanel.setBorder(new javax.swing.border.TitledBorder("Unit Of Measure")); java.awt.event.ActionListener al = new ActionListener() { // We don't have to check for action commands or anything like that. // We know this listener is going to be added to JRadioButtons that // are labeled with abbreviations for length. public void actionPerformed(ActionEvent e) { JRadioButton jrb = (JRadioButton) e.getSource(); setUnitOfMeasure(jrb.getText()); } }; for (Length lengthType : Length.values()) { JRadioButton jrb = new JRadioButton(); jrb.setText(lengthType.getAbbr()); jrb.setToolTipText(lengthType.toString()); uomButtonGroup.add(jrb); palettePanel.add(jrb); jrb.addActionListener(al); jrb.setSelected(unitOfMeasure.equalsIgnoreCase(lengthType.getAbbr())); buttons.add(jrb); } } else { for (JRadioButton button : buttons) { button.setSelected(uom.getAbbr().equalsIgnoreCase(button.getText())); } } return palettePanel; } }