📄 scalefilterlayer.java
字号:
// **********************************************************************// // <copyright>// // BBN Technologies// 10 Moulton Street// Cambridge, MA 02138// (617) 873-8000// // Copyright (C) BBNT Solutions LLC. All rights reserved.// // </copyright>// **********************************************************************// // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/ScaleFilterLayer.java,v $// $RCSfile: ScaleFilterLayer.java,v $// $Revision: 1.7.2.5 $// $Date: 2006/10/13 16:02:16 $// $Author: dietrick $// // **********************************************************************package com.bbn.openmap.layer;import java.awt.Component;import java.awt.Graphics;import java.awt.GridBagConstraints;import java.awt.GridBagLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.MouseEvent;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;import java.beans.PropertyVetoException;import java.beans.beancontext.BeanContext;import java.util.HashSet;import java.util.Iterator;import java.util.Properties;import java.util.StringTokenizer;import java.util.Vector;import javax.swing.JButton;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JTabbedPane;import com.bbn.openmap.Layer;import com.bbn.openmap.MouseDelegator;import com.bbn.openmap.event.InfoDisplayEvent;import com.bbn.openmap.event.InfoDisplayListener;import com.bbn.openmap.event.LayerStatusEvent;import com.bbn.openmap.event.LayerStatusListener;import com.bbn.openmap.event.MapMouseListener;import com.bbn.openmap.event.MapMouseMode;import com.bbn.openmap.event.NavMouseMode;import com.bbn.openmap.event.NullMouseMode;import com.bbn.openmap.event.ProjectionEvent;import com.bbn.openmap.event.SelectMouseMode;import com.bbn.openmap.proj.Projection;import com.bbn.openmap.util.Debug;import com.bbn.openmap.util.PropUtils;/** * An OpenMap Layer that encapsulates other layers and acts as a scale filter. * It will delegate responsibility to one of several layers depending on the * scale. * <p> * To use this layer, list it as a layer in the openmap.properties file in the * openmap.layers properties, as you would add any other layer. Then, add these * properties to the openmap.properties file. The layers added to the * ScaleFilterLayer do not get added to the openmap.layers property, but instead * get added to the scaledFilterLayer.layers property listed here. Then, the * properties for these layers are added to the openmap.properties file like any * other layer. <BR> * The properties for this layer look like this: <BR> * <BR> * <code><pre> * * ####################################### * # Properties for ScaleFilterLayer * ####################################### * scaledFilterLayer.class=com.bbn.openmap.layer.ScaleFilterLayer * scaledFilterLayer.prettyName=&ltPretty name used on menu&ge * # List 2 or more layers, larger scale layers first * scaledFilterLayer.layers=layer_1 layer_2 layer_3 ... * # List the transition scales to switch between layers * scaledFilterLayer.transitionScales= (transition scale from layer 1 to 2) (transition scale from layer 2 to 3) (...) * ####################################### * * </pre></code> */public class ScaleFilterLayer extends Layer implements InfoDisplayListener, LayerStatusListener, PropertyChangeListener, MapMouseListener { /** * The layers property. */ public final static transient String layersProperty = "layers"; /** * The transition scales property. */ public final static transient String transitionScalesProperty = "transitionScales"; /** * The layers. */ protected Vector layers; /** * The transition scales. */ protected float[] transitionScales; /** * The default transition scale. */ protected float defaultTransitionScale = 40000000f; /** * The index of the currently selected layer. */ protected int targetIndex = -1; /** * Initializes an empty layer. */ public ScaleFilterLayer() { // Setting the overlay layout seemed like a good idea at the time, but // it introduces a strange bug where the bounds of the layer get set // between the center of the map and the lower left corner. This only // happens for the BufferedLayerMapBean, when there are buffered layers // active. Very strange, but not setting an overlay seems to work OK, // too. // setLayout(new OverlayLayout(this)); // To get MouseDelegator, to make decisions on receiving mouse // modes for child layers. setAddToBeanContext(true); } /** * Get the Vector holding the Layers. If it hasn't been asked for yet, a * new, empty Vector will be returned, one that will be used internally. */ public Vector getLayers() { if (layers == null) { layers = new Vector(); } return layers; } /** * Get the transition scales used to set the active layer. */ public float[] getTransitionScales() { return transitionScales; } /** * Programmatic way to set layers and scales. There should be one more layer * on the list than there is scale in the float array. Layers that should be * displayed for larger scale numbers (smaller scale) should be at the front * of the Vector list, and larger numbers should be at the front of the * scale array. For scale numbers larger than the first number in the array, * the first layer will be displayed. As the scale number decreases, other * layers will be displayed. * * @param list Vector of layers * @param scales Array of transition scales. */ public void setLayersAndScales(Vector list, float[] scales) { layers = list; transitionScales = scales; } /** * Initializes this layer from the given properties. * * @param props the <code>Properties</code> holding settings for this * layer */ public void setProperties(String prefix, Properties props) { // Clear out layer and scale state setLayersAndScales(null, null); super.setProperties(prefix, props); prefix = PropUtils.getScopedPropertyPrefix(prefix); parseLayers(prefix, props); parseScales(prefix, props); // Update our target layer. If there is a current projection and this // layer is active, we need to pass it along. if (getProjection() != null) { Layer currentLayer = configureAppropriateLayer(getProjection().getScale()); fireStatusUpdate(LayerStatusEvent.START_WORKING); currentLayer.projectionChanged(new ProjectionEvent((Object) null, getProjection())); } } public Properties getProperties(Properties props) { props = super.getProperties(props); String prefix = PropUtils.getScopedPropertyPrefix(this); float[] ts = getTransitionScales(); StringBuffer tsBuffer = new StringBuffer(); if (ts != null) { for (int i = 0; i < ts.length; i++) { tsBuffer.append(Float.toString(ts[i]) + " "); } } props.put(prefix + transitionScalesProperty, tsBuffer.toString()); StringBuffer layerBuffer = new StringBuffer(); for (Iterator it = getLayers().iterator(); it.hasNext();) { Layer layer = (Layer) it.next(); layerBuffer.append(layer.getPropertyPrefix() + " "); layer.getProperties(props); } props.put(prefix + layersProperty, layerBuffer.toString()); return props; } /** * Get the layer that's appropriate at the current scale. The targetedIndex * needs to be set before this is called. The targetedIndex is the index to * the layers array representing the current layer. * * @return Layer */ public Layer getAppropriateLayer() { Vector target = getLayers(); if (target == null) { return SinkLayer.getSharedInstance(); } if ((targetIndex < 0) || (targetIndex > target.size())) { return SinkLayer.getSharedInstance(); } Layer l = (Layer) target.elementAt(targetIndex); return l; } /** * Create the Layers from a property value string. * * @param prefix String * @param props Properties */ protected void parseLayers(String prefix, Properties props) { String layersString = props.getProperty(prefix + layersProperty); Vector layers = getLayers(); if (layersString == null || layersString.equals("")) { Debug.error("ScaleFilterLayer(): null layersString!"); return; } StringTokenizer tok = new StringTokenizer(layersString); while (tok.hasMoreTokens()) { Object obj; String layerName = tok.nextToken(); String classProperty = layerName + ".class"; String className = props.getProperty(classProperty); if (className == null) { Debug.error("ScaleFilterLayer.parseLayers(): Failed to locate property \"" + classProperty + "\""); Debug.error("ScaleFilterLayer.parseLayers(): Skipping layer \"" + layerName + "\""); className = SinkLayer.class.getName(); } try { if (className.equals(SinkLayer.class.getName())) { obj = SinkLayer.getSharedInstance(); } else { obj = Class.forName(className).newInstance(); } if (Debug.debugging("scalefilterlayer")) { Debug.output("ScaleFilterLayer.parseLayers(): Instantiated " + className); } } catch (Exception e) { Debug.error("ScaleFilterLayer.parseLayers(): Failed to instantiate \"" + className + "\": " + e); obj = SinkLayer.getSharedInstance(); } // create the layer and set its properties if (obj instanceof Layer) { Layer l = (Layer) obj; l.setProperties(layerName, props); l.addLayerStatusListener(this); l.addInfoDisplayListener(this); layers.addElement(l); } } } /** * Create the transition scales from a property value string. If there are N * layers, there should be N-1 transition scales. * * @param prefix String * @param props Properties */ protected void parseScales(String prefix, Properties props) { StringTokenizer tok = null; Vector layers = getLayers(); int size = layers.size(); if (size > 0) { --size; } transitionScales = new float[size]; String scales = props.getProperty(prefix + transitionScalesProperty); if (scales == null) { Debug.error("ScaleFilterLayer.parseScales(): Failed to locate property \"" + transitionScalesProperty + "\""); if (transitionScales.length > 0) { transitionScales[0] = defaultTransitionScale; } for (int i = 1; i < transitionScales.length; i++) { transitionScales[i] = transitionScales[i - 1] / 3; } return; } try { tok = new StringTokenizer(scales); transitionScales[0] = (tok.hasMoreTokens()) ? new Float(tok.nextToken()).floatValue() : defaultTransitionScale; } catch (NumberFormatException e) { Debug.error("ScaleFilterLayer.parseScales()1: " + e); transitionScales[0] = defaultTransitionScale; } for (int i = 1; i < transitionScales.length; i++) { try { transitionScales[i] = (tok.hasMoreTokens()) ? new Float(tok.nextToken()).floatValue() : transitionScales[i - 1] / 3; } catch (NumberFormatException e) { Debug.error("ScaleFilterLayer.parseScales()2: " + e); transitionScales[i] = transitionScales[i - 1] / 3; } } } /** * Implementing the ProjectionPainter interface. */ public synchronized void renderDataForProjection(Projection proj, java.awt.Graphics g) { if (proj == null) { Debug.error("ScaleFilterLayer.renderDataForProjection: null projection!"); return; } else { setTargetIndex(proj.getScale()); Layer layer = getAppropriateLayer(); layer.renderDataForProjection(proj, g); } } /** * Calculate the index of the target layer. If there are N layers, there are * N-1 transitionScales. The ith layer is chosen if the scale is greater * than the ith transitionScale. * * @param scale the current map scale * @return true if the targetIndex has changed as a result of the new scale. */ public boolean setTargetIndex(float scale) { boolean changed = false; float[] target = transitionScales; int i = 0; if (target != null) { for (i = 0; i < target.length; i++) { if (scale > target[i]) { break; } } } if (targetIndex != i) { changed = true; } targetIndex = i; if (Debug.debugging("scalefilterlayer")) { Debug.output("ScaleFilterLayer(" + getName() + ") targetIndex: " + targetIndex + ", changed: " + changed); } return changed; } /** * Handles projection change notification events. Throws out old graphics, * and requests new graphics from the spatial index based on the bounding * rectangle of the new <code>Projection</code>. * * @param ev the new projection event */ public void projectionChanged(ProjectionEvent ev) { // Lets the ScaleFilterLayer remember the projection, just in case. setProjection(ev); Projection proj = ev.getProjection(); // get the appropriate layer and invoke projectionChanged Layer layer = configureAppropriateLayer(proj.getScale()); fireStatusUpdate(LayerStatusEvent.START_WORKING); layer.projectionChanged(ev); } protected Layer configureAppropriateLayer(float scale) { Layer currentLayer = getAppropriateLayer(); boolean changed = setTargetIndex(scale); // get the appropriate layer and invoke projectionChanged Layer layer = getAppropriateLayer(); if (changed) { currentLayer.removeNotify(); setPaletteTab(targetIndex); remove(currentLayer); // This will handle the repaint() requests from the // layer... add(layer); layer.addNotify(); checkMouseMode(); } return layer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -