0001: /*
0002: * GeoTools - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation;
0009: * version 2.1 of the License.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: */
0016: package org.geotools.gui.swing;
0017:
0018: /**
0019: * A simple map container that is a JPanel with a map in. provides simple
0020: * pan,zoom, highlight and selection The mappane stores an image of the map
0021: * (drawn from the context) and an image of the slected feature(s) to speed up
0022: * rendering of the highlights. Thus the whole map is only redrawn when the bbox
0023: * changes, selection is only redrawn when the selected feature changes.
0024: *
0025: *
0026: * @author Ian Turton
0027: *
0028: */
0029:
0030: import java.awt.Color;
0031: import java.awt.Cursor;
0032: import java.awt.Graphics;
0033: import java.awt.Graphics2D;
0034: import java.awt.LayoutManager;
0035: import java.awt.Rectangle;
0036: import java.awt.event.MouseEvent;
0037: import java.awt.event.MouseListener;
0038: import java.awt.event.MouseMotionListener;
0039: import java.awt.image.BufferedImage;
0040: import java.beans.PropertyChangeEvent;
0041: import java.beans.PropertyChangeListener;
0042: import java.io.IOException;
0043: import java.util.Date;
0044: import java.util.HashMap;
0045: import java.util.Map;
0046:
0047: import javax.swing.JPanel;
0048:
0049: import org.geotools.feature.FeatureCollection;
0050: import org.geotools.filter.IllegalFilterException;
0051: import org.geotools.gui.swing.event.HighlightChangeListener;
0052: import org.geotools.gui.swing.event.HighlightChangedEvent;
0053: import org.geotools.gui.swing.event.SelectionChangeListener;
0054: import org.geotools.gui.swing.event.SelectionChangedEvent;
0055: import org.geotools.map.DefaultMapContext;
0056: import org.geotools.map.MapContext;
0057: import org.geotools.map.MapLayer;
0058: import org.geotools.map.event.MapLayerListEvent;
0059: import org.geotools.map.event.MapLayerListListener;
0060: import org.geotools.referencing.crs.DefaultGeographicCRS;
0061: import org.geotools.renderer.GTRenderer;
0062: import org.geotools.renderer.lite.LabelCache;
0063: import org.geotools.renderer.lite.LabelCacheDefault;
0064: import org.geotools.renderer.lite.StreamingRenderer;
0065: import org.geotools.styling.Graphic;
0066: import org.geotools.styling.LineSymbolizer;
0067: import org.geotools.styling.Mark;
0068: import org.geotools.styling.PointSymbolizer;
0069: import org.geotools.styling.PolygonSymbolizer;
0070: import org.geotools.styling.Style;
0071: import org.geotools.styling.StyleBuilder;
0072: import org.geotools.styling.StyleFactory;
0073: import org.opengis.filter.Filter;
0074: import org.opengis.filter.FilterFactory2;
0075: import org.opengis.referencing.crs.CoordinateReferenceSystem;
0076:
0077: import com.vividsolutions.jts.geom.Coordinate;
0078: import com.vividsolutions.jts.geom.Envelope;
0079: import com.vividsolutions.jts.geom.Geometry;
0080: import com.vividsolutions.jts.geom.GeometryFactory;
0081:
0082: public class JMapPane extends JPanel implements MouseListener,
0083: MouseMotionListener, HighlightChangeListener,
0084: SelectionChangeListener, PropertyChangeListener,
0085: MapLayerListListener {
0086: /**
0087: *
0088: */
0089: private static final long serialVersionUID = -8647971481359690499L;
0090:
0091: public static final int Reset = 0;
0092:
0093: public static final int ZoomIn = 1;
0094:
0095: public static final int ZoomOut = 2;
0096:
0097: public static final int Pan = 3;
0098:
0099: public static final int Select = 4;
0100:
0101: private static final int POLYGON = 0;
0102:
0103: private static final int LINE = 1;
0104:
0105: private static final int POINT = 2;
0106:
0107: /**
0108: * what renders the map
0109: */
0110: GTRenderer renderer;
0111:
0112: private GTRenderer highlightRenderer, selectionRenderer;
0113:
0114: /**
0115: * the map context to render
0116: */
0117: MapContext context;
0118:
0119: private MapContext selectionContext;
0120:
0121: /**
0122: * the area of the map to draw
0123: */
0124: Envelope mapArea;
0125:
0126: /**
0127: * the size of the pane last time we drew
0128: */
0129: private Rectangle oldRect = null;
0130:
0131: /**
0132: * the last map area drawn.
0133: */
0134: private Envelope oldMapArea = null;
0135:
0136: /**
0137: * the base image of the map
0138: */
0139: private BufferedImage baseImage;
0140:
0141: /**
0142: * image of selection
0143: */
0144: private BufferedImage selectImage;
0145:
0146: /**
0147: * style for selected items
0148: */
0149: private Style selectionStyle;
0150:
0151: /**
0152: * layer that selection works on
0153: */
0154: private MapLayer selectionLayer;
0155:
0156: /**
0157: * layer that highlight works on
0158: */
0159: private MapLayer highlightLayer;
0160:
0161: /**
0162: * the object which manages highlighting
0163: */
0164: private HighlightManager highlightManager;
0165:
0166: /**
0167: * is highlighting on or off
0168: */
0169: private boolean highlight = true;
0170:
0171: /**
0172: * a factory for filters
0173: */
0174: FilterFactory2 ff;
0175:
0176: /**
0177: * a factory for geometries
0178: */
0179: GeometryFactory gf = new GeometryFactory(); // FactoryFinder.getGeometryFactory(null);
0180:
0181: /**
0182: * the collections of features to be selected or highlighted
0183: */
0184: FeatureCollection selection;
0185:
0186: /**
0187: * the collections of features to be selected or highlighted
0188: */
0189: FeatureCollection highlightFeature;
0190:
0191: private int state = ZoomIn;
0192:
0193: /**
0194: * how far to zoom in or out
0195: */
0196: private double zoomFactor = 2.0;
0197:
0198: Style lineHighlightStyle;
0199:
0200: Style pointHighlightStyle;
0201:
0202: Style polygonHighlightStyle;
0203:
0204: Style polygonSelectionStyle;
0205:
0206: Style pointSelectionStyle;
0207:
0208: Style lineSelectionStyle;
0209:
0210: boolean changed = true;
0211:
0212: LabelCache labelCache = new LabelCacheDefault();
0213:
0214: private boolean reset = false;
0215:
0216: int startX;
0217:
0218: int startY;
0219:
0220: private boolean clickable;
0221:
0222: int lastX;
0223:
0224: int lastY;
0225:
0226: private SelectionManager selectionManager;
0227:
0228: public JMapPane() {
0229: this (null, true, null, null);
0230: }
0231:
0232: /**
0233: * create a basic JMapPane
0234: *
0235: * @param render -
0236: * how to draw the map
0237: * @param context -
0238: * the map context to display
0239: */
0240: public JMapPane(GTRenderer render, MapContext context) {
0241: this (null, true, render, context);
0242: }
0243:
0244: /**
0245: * full constructor extending JPanel
0246: *
0247: * @param layout -
0248: * layout (probably shouldn't be set)
0249: * @param isDoubleBuffered -
0250: * a Swing thing I don't really understand
0251: * @param render -
0252: * what to draw the map with
0253: * @param context -
0254: * what to draw
0255: */
0256: public JMapPane(LayoutManager layout, boolean isDoubleBuffered,
0257: GTRenderer render, MapContext context) {
0258: super (layout, isDoubleBuffered);
0259:
0260: ff = (FilterFactory2) org.geotools.factory.CommonFactoryFinder
0261: .getFilterFactory(null);
0262: setRenderer(render);
0263:
0264: setContext(context);
0265:
0266: this .addMouseListener(this );
0267: this .addMouseMotionListener(this );
0268: setHighlightManager(new HighlightManager(highlightLayer));
0269: setSelectionManager(new SelectionManager(selectionLayer));
0270: lineHighlightStyle = setupStyle(LINE, Color.red);
0271:
0272: pointHighlightStyle = setupStyle(POINT, Color.red);
0273:
0274: polygonHighlightStyle = setupStyle(POLYGON, Color.red);
0275:
0276: polygonSelectionStyle = setupStyle(POLYGON, Color.cyan);
0277:
0278: pointSelectionStyle = setupStyle(POINT, Color.cyan);
0279:
0280: lineSelectionStyle = setupStyle(LINE, Color.cyan);
0281: setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
0282: }
0283:
0284: /**
0285: * get the renderer
0286: */
0287: public GTRenderer getRenderer() {
0288: return renderer;
0289: }
0290:
0291: public void setRenderer(GTRenderer renderer) {
0292: Map hints = new HashMap();
0293: if (renderer instanceof StreamingRenderer) {
0294: hints = renderer.getRendererHints();
0295: if (hints == null) {
0296: hints = new HashMap();
0297: }
0298: if (hints.containsKey(StreamingRenderer.LABEL_CACHE_KEY)) {
0299: labelCache = (LabelCache) hints
0300: .get(StreamingRenderer.LABEL_CACHE_KEY);
0301: } else {
0302: hints
0303: .put(StreamingRenderer.LABEL_CACHE_KEY,
0304: labelCache);
0305: }
0306: renderer.setRendererHints(hints);
0307: }
0308:
0309: this .renderer = renderer;
0310: this .highlightRenderer = new StreamingRenderer();
0311: this .selectionRenderer = new StreamingRenderer();
0312:
0313: hints.put("memoryPreloadingEnabled", Boolean.FALSE);
0314: highlightRenderer.setRendererHints(hints);
0315: selectionRenderer.setRendererHints(hints);
0316:
0317: if (this .context != null) {
0318: this .renderer.setContext(this .context);
0319: }
0320: }
0321:
0322: public MapContext getContext() {
0323: return context;
0324: }
0325:
0326: public void setContext(MapContext context) {
0327: if (this .context != null) {
0328: this .context.removeMapLayerListListener(this );
0329: }
0330:
0331: this .context = context;
0332:
0333: if (context != null) {
0334: this .context.addMapLayerListListener(this );
0335: }
0336:
0337: if (renderer != null) {
0338: renderer.setContext(this .context);
0339: }
0340: }
0341:
0342: public Envelope getMapArea() {
0343: return mapArea;
0344: }
0345:
0346: public void setMapArea(Envelope mapArea) {
0347: this .mapArea = mapArea;
0348: }
0349:
0350: public int getState() {
0351: return state;
0352: }
0353:
0354: public void setState(int state) {
0355: this .state = state;
0356:
0357: // System.out.println("State: " + state);
0358: }
0359:
0360: public double getZoomFactor() {
0361: return zoomFactor;
0362: }
0363:
0364: public void setZoomFactor(double zoomFactor) {
0365: this .zoomFactor = zoomFactor;
0366: }
0367:
0368: public MapLayer getSelectionLayer() {
0369: return selectionLayer;
0370: }
0371:
0372: public void setSelectionLayer(MapLayer selectionLayer) {
0373: this .selectionLayer = selectionLayer;
0374: if (selectionManager != null) {
0375: selectionManager.setSelectionLayer(selectionLayer);
0376: }
0377: }
0378:
0379: public boolean isHighlight() {
0380: return highlight;
0381: }
0382:
0383: public void setHighlight(boolean highlight) {
0384: this .highlight = highlight;
0385: }
0386:
0387: public MapLayer getHighlightLayer() {
0388: return highlightLayer;
0389: }
0390:
0391: public void setHighlightLayer(MapLayer highlightLayer) {
0392: this .highlightLayer = highlightLayer;
0393:
0394: if (highlightManager != null) {
0395: highlightManager.setHighlightLayer(highlightLayer);
0396: }
0397: }
0398:
0399: public HighlightManager getHighlightManager() {
0400: return highlightManager;
0401: }
0402:
0403: public void setHighlightManager(HighlightManager highlightManager) {
0404: this .highlightManager = highlightManager;
0405: this .highlightManager.addHighlightChangeListener(this );
0406: this .addMouseMotionListener(this .highlightManager);
0407: }
0408:
0409: public Style getLineHighlightStyle() {
0410: return lineHighlightStyle;
0411: }
0412:
0413: public void setLineHighlightStyle(Style lineHighlightStyle) {
0414: this .lineHighlightStyle = lineHighlightStyle;
0415: }
0416:
0417: public Style getLineSelectionStyle() {
0418: return lineSelectionStyle;
0419: }
0420:
0421: public void setLineSelectionStyle(Style lineSelectionStyle) {
0422: this .lineSelectionStyle = lineSelectionStyle;
0423: }
0424:
0425: public Style getPointHighlightStyle() {
0426: return pointHighlightStyle;
0427: }
0428:
0429: public void setPointHighlightStyle(Style pointHighlightStyle) {
0430: this .pointHighlightStyle = pointHighlightStyle;
0431: }
0432:
0433: public Style getPointSelectionStyle() {
0434: return pointSelectionStyle;
0435: }
0436:
0437: public void setPointSelectionStyle(Style pointSelectionStyle) {
0438: this .pointSelectionStyle = pointSelectionStyle;
0439: }
0440:
0441: public Style getPolygonHighlightStyle() {
0442: return polygonHighlightStyle;
0443: }
0444:
0445: public void setPolygonHighlightStyle(Style polygonHighlightStyle) {
0446: this .polygonHighlightStyle = polygonHighlightStyle;
0447: }
0448:
0449: public Style getPolygonSelectionStyle() {
0450: return polygonSelectionStyle;
0451: }
0452:
0453: public void setPolygonSelectionStyle(Style polygonSelectionStyle) {
0454: this .polygonSelectionStyle = polygonSelectionStyle;
0455: }
0456:
0457: protected void paintComponent(Graphics g) {
0458: super .paintComponent(g);
0459:
0460: if ((renderer == null) || (mapArea == null)) {
0461: return;
0462: }
0463:
0464: Rectangle r = getBounds();
0465: Rectangle dr = new Rectangle(r.width, r.height);
0466:
0467: if (!r.equals(oldRect) || reset) {
0468: if (!r.equals(oldRect)) {
0469: try {
0470: mapArea = context.getLayerBounds();
0471: } catch (IOException e) {
0472: // TODO Auto-generated catch block
0473: e.printStackTrace();
0474: }
0475: }
0476: /* either the viewer size has changed or we've done a reset */
0477: changed = true; /* note we need to redraw */
0478: reset = false; /* forget about the reset */
0479: oldRect = r; /* store what the current size is */
0480: mapArea = fixAspectRatio(r, mapArea);
0481: }
0482:
0483: if (!mapArea.equals(oldMapArea)) { /* did the map extent change? */
0484: changed = true;
0485: oldMapArea = mapArea;
0486: // when we tell the context that the bounds have changed WMSLayers
0487: // can refresh them selves
0488: context.setAreaOfInterest(mapArea, context
0489: .getCoordinateReferenceSystem());
0490: }
0491:
0492: if (changed) { /* if the map changed then redraw */
0493: changed = false;
0494: baseImage = new BufferedImage(dr.width, dr.height,
0495: BufferedImage.TYPE_INT_ARGB);
0496:
0497: Graphics2D ig = baseImage.createGraphics();
0498: /* System.out.println("rendering"); */
0499: renderer.setContext(context);
0500: labelCache.clear(); // work around anoying labelcache bug
0501:
0502: // draw the map
0503: renderer.paint((Graphics2D) ig, dr, mapArea);
0504: }
0505:
0506: ((Graphics2D) g).drawImage(baseImage, 0, 0, this );
0507:
0508: if ((selection != null) && (selection.size() > 0)) {
0509: // paint selection
0510:
0511: String type = selectionLayer.getFeatureSource().getSchema()
0512: .getDefaultGeometry().getType().getName();
0513: /*String type = selection.getDefaultGeometry().getGeometryType();*/
0514: /*System.out.println(type);*/
0515: if (type == null)
0516: type = "polygon";
0517:
0518: /* String type = "point"; */
0519:
0520: if (type.toLowerCase().endsWith("polygon")) {
0521: selectionStyle = polygonSelectionStyle;
0522: } else if (type.toLowerCase().endsWith("point")) {
0523: selectionStyle = pointSelectionStyle;
0524: } else if (type.toLowerCase().endsWith("line")) {
0525: selectionStyle = lineSelectionStyle;
0526: }
0527:
0528: selectionContext = new DefaultMapContext(
0529: DefaultGeographicCRS.WGS84);
0530:
0531: selectionContext.addLayer(selection, selectionStyle);
0532: selectionRenderer.setContext(selectionContext);
0533:
0534: selectImage = new BufferedImage(dr.width, dr.height,
0535: BufferedImage.TYPE_INT_ARGB);
0536:
0537: Graphics2D ig = selectImage.createGraphics();
0538: /* System.out.println("rendering selection"); */
0539: selectionRenderer.paint((Graphics2D) ig, dr, mapArea);
0540:
0541: ((Graphics2D) g).drawImage(selectImage, 0, 0, this );
0542: }
0543:
0544: if (highlight && (highlightFeature != null)
0545: && (highlightFeature.size() > 0)) {
0546: /*
0547: * String type = selection.getDefaultGeometry().getGeometryType();
0548: * System.out.println(type); if(type==null) type="polygon";
0549: */
0550: String type = highlightLayer.getFeatureSource().getSchema()
0551: .getDefaultGeometry().getType().getName();
0552: /*String type = selection.getDefaultGeometry().getGeometryType();*/
0553: //System.out.println(type);
0554: if (type == null)
0555: type = "polygon";
0556:
0557: /* String type = "point"; */
0558: Style highlightStyle = null;
0559: if (type.toLowerCase().endsWith("polygon")) {
0560: highlightStyle = polygonHighlightStyle;
0561: } else if (type.toLowerCase().endsWith("point")) {
0562: highlightStyle = pointHighlightStyle;
0563: } else if (type.toLowerCase().endsWith("line")) {
0564: highlightStyle = lineHighlightStyle;
0565: }
0566:
0567: MapContext highlightContext = new DefaultMapContext(
0568: DefaultGeographicCRS.WGS84);
0569:
0570: highlightContext.addLayer(highlightFeature, highlightStyle);
0571: highlightRenderer.setContext(highlightContext);
0572:
0573: /* System.out.println("rendering highlight"); */
0574: highlightRenderer.paint((Graphics2D) g, dr, mapArea);
0575: }
0576: }
0577:
0578: private Envelope fixAspectRatio(Rectangle r, Envelope mapArea) {
0579: double mapWidth = mapArea.getWidth(); /* get the extent of the map */
0580: double mapHeight = mapArea.getHeight();
0581: double scaleX = r.getWidth() / mapArea.getWidth(); /*
0582: * calculate the new
0583: * scale
0584: */
0585:
0586: double scaleY = r.getHeight() / mapArea.getHeight();
0587: double scale = 1.0; // stupid compiler!
0588:
0589: if (scaleX < scaleY) { /* pick the smaller scale */
0590: scale = scaleX;
0591: } else {
0592: scale = scaleY;
0593: }
0594:
0595: /* calculate the difference in width and height of the new extent */
0596: double deltaX = /* Math.abs */((r.getWidth() / scale) - mapWidth);
0597: double deltaY = /* Math.abs */((r.getHeight() / scale) - mapHeight);
0598:
0599: /*
0600: * System.out.println("delta x " + deltaX); System.out.println("delta y " +
0601: * deltaY);
0602: */
0603:
0604: /* create the new extent */
0605: Coordinate ll = new Coordinate(mapArea.getMinX()
0606: - (deltaX / 2.0), mapArea.getMinY() - (deltaY / 2.0));
0607: Coordinate ur = new Coordinate(mapArea.getMaxX()
0608: + (deltaX / 2.0), mapArea.getMaxY() + (deltaY / 2.0));
0609:
0610: return new Envelope(ll, ur);
0611: }
0612:
0613: public void doSelection(double x, double y, MapLayer layer) {
0614:
0615: Geometry geometry = gf.createPoint(new Coordinate(x, y));
0616:
0617: // org.opengis.geometry.Geometry geometry = new Point();
0618:
0619: findFeature(geometry, layer);
0620:
0621: }
0622:
0623: /**
0624: * @param geometry -
0625: * a geometry to construct the filter with
0626: * @param i -
0627: * the index of the layer to search
0628: * @throws IndexOutOfBoundsException
0629: */
0630: private void findFeature(Geometry geometry, MapLayer layer)
0631: throws IndexOutOfBoundsException {
0632: org.opengis.filter.spatial.BinarySpatialOperator f = null;
0633:
0634: if ((context == null) || (layer == null)) {
0635: return;
0636: }
0637:
0638: try {
0639: String name = layer.getFeatureSource().getSchema()
0640: .getDefaultGeometry().getName();
0641:
0642: if (name == "") {
0643: name = "the_geom";
0644: }
0645:
0646: try {
0647: f = ff
0648: .contains(ff.property(name), ff
0649: .literal(geometry));
0650: if (selectionManager != null) {
0651: System.out.println("selection changed");
0652: selectionManager.selectionChanged(this , f);
0653:
0654: }
0655: } catch (IllegalFilterException e) {
0656: // TODO Auto-generated catch block
0657: e.printStackTrace();
0658: }
0659:
0660: /*// f.addLeftGeometry(ff.property(name));
0661: // System.out.println("looking with " + f);
0662: FeatureCollection fc = layer.getFeatureSource().getFeatures(f);
0663:
0664:
0665:
0666: if (fcol == null) {
0667: fcol = fc;
0668:
0669: // here we should set the defaultgeom type
0670: } else {
0671: fcol.addAll(fc);
0672: }*/
0673:
0674: /*
0675: * GeometryAttributeType gat =
0676: * layer.getFeatureSource().getSchema().getDefaultGeometry();
0677: * fcol.setDefaultGeometry((Geometry)gat.createDefaultValue());
0678: */
0679:
0680: /*
0681: * Iterator fi = fc.iterator(); while (fi.hasNext()) { Feature feat =
0682: * (Feature) fi.next(); System.out.println("selected " +
0683: * feat.getAttribute("STATE_NAME")); }
0684: */
0685: } catch (IllegalFilterException e) {
0686: // TODO Auto-generated catch block
0687: e.printStackTrace();
0688: }
0689: return;
0690: }
0691:
0692: public void mouseClicked(MouseEvent e) {
0693: // TODO Auto-generated method stub
0694: // System.out.println("before area "+mapArea+"\nw:"+mapArea.getWidth()+"
0695: // h:"+mapArea.getHeight());
0696: Rectangle bounds = this .getBounds();
0697: double x = (double) (e.getX());
0698: double y = (double) (e.getY());
0699: double width = mapArea.getWidth();
0700: double height = mapArea.getHeight();
0701: double width2 = mapArea.getWidth() / 2.0;
0702: double height2 = mapArea.getHeight() / 2.0;
0703:
0704: double mapX = ((x * width) / (double) bounds.width)
0705: + mapArea.getMinX();
0706: double mapY = (((bounds.getHeight() - y) * height) / (double) bounds.height)
0707: + mapArea.getMinY();
0708:
0709: /*
0710: * System.out.println(""+x+"->"+mapX);
0711: * System.out.println(""+y+"->"+mapY);
0712: */
0713:
0714: /*
0715: * Coordinate ll = new Coordinate(mapArea.getMinX(), mapArea.getMinY());
0716: * Coordinate ur = new Coordinate(mapArea.getMaxX(), mapArea.getMaxY());
0717: */
0718: double zlevel = 1.0;
0719:
0720: switch (state) {
0721: case Pan:
0722: zlevel = 1.0;
0723:
0724: break;
0725:
0726: case ZoomIn:
0727: zlevel = zoomFactor;
0728:
0729: break;
0730:
0731: case ZoomOut:
0732: zlevel = 1.0 / zoomFactor;
0733:
0734: break;
0735:
0736: case Select:
0737: doSelection(mapX, mapY, selectionLayer);
0738:
0739: return;
0740:
0741: default:
0742: return;
0743: }
0744:
0745: Coordinate ll = new Coordinate(mapX - (width2 / zlevel), mapY
0746: - (height2 / zlevel));
0747: Coordinate ur = new Coordinate(mapX + (width2 / zlevel), mapY
0748: + (height2 / zlevel));
0749:
0750: mapArea = new Envelope(ll, ur);
0751: // System.out.println("after area "+mapArea+"\nw:"+mapArea.getWidth()+"
0752: // h:"+mapArea.getHeight());
0753: repaint();
0754: }
0755:
0756: public void mouseEntered(MouseEvent e) {
0757: // TODO Auto-generated method stub
0758: }
0759:
0760: public void mouseExited(MouseEvent e) {
0761: // TODO Auto-generated method stub
0762: }
0763:
0764: public void mousePressed(MouseEvent e) {
0765: startX = e.getX();
0766: startY = e.getY();
0767: lastX = 0;
0768: lastY = 0;
0769: }
0770:
0771: public void mouseReleased(MouseEvent e) {
0772: int endX = e.getX();
0773: int endY = e.getY();
0774:
0775: if ((state == JMapPane.ZoomIn) || (state == JMapPane.ZoomOut)) {
0776: drawRectangle(this .getGraphics());
0777: }
0778:
0779: processDrag(startX, startY, endX, endY);
0780: lastX = 0;
0781: lastY = 0;
0782: }
0783:
0784: public void mouseDragged(MouseEvent e) {
0785: Graphics graphics = this .getGraphics();
0786: int x = e.getX();
0787: int y = e.getY();
0788:
0789: if (state == JMapPane.Pan) {
0790: // move the image with the mouse
0791: if ((lastX > 0) && (lastY > 0)) {
0792: int dx = lastX - startX;
0793: int dy = lastY - startY;
0794: // System.out.println("translate "+dx+","+dy);
0795: graphics.clearRect(0, 0, this .getWidth(), this
0796: .getHeight());
0797: ((Graphics2D) graphics).drawImage(baseImage, dx, dy,
0798: this );
0799: }
0800:
0801: lastX = x;
0802: lastY = y;
0803: } else if ((state == JMapPane.ZoomIn)
0804: || (state == JMapPane.ZoomOut)) {
0805: graphics.setXORMode(Color.RED);
0806:
0807: if ((lastX > 0) && (lastY > 0)) {
0808: drawRectangle(graphics);
0809: }
0810:
0811: // draw new box
0812: lastX = x;
0813: lastY = y;
0814: drawRectangle(graphics);
0815: } else if (state == JMapPane.Select && selectionLayer != null) {
0816:
0817: // construct a new bbox filter
0818: Rectangle bounds = this .getBounds();
0819:
0820: double mapWidth = mapArea.getWidth();
0821: double mapHeight = mapArea.getHeight();
0822:
0823: double x1 = ((this .startX * mapWidth) / (double) bounds.width)
0824: + mapArea.getMinX();
0825: double y1 = (((bounds.getHeight() - this .startY) * mapHeight) / (double) bounds.height)
0826: + mapArea.getMinY();
0827: double x2 = ((x * mapWidth) / (double) bounds.width)
0828: + mapArea.getMinX();
0829: double y2 = (((bounds.getHeight() - y) * mapHeight) / (double) bounds.height)
0830: + mapArea.getMinY();
0831: double left = Math.min(x1, x2);
0832: double right = Math.max(x1, x2);
0833: double bottom = Math.min(y1, y2);
0834: double top = Math.max(y1, y2);
0835:
0836: String name = selectionLayer.getFeatureSource().getSchema()
0837: .getDefaultGeometry().getName();
0838:
0839: if (name == "") {
0840: name = "the_geom";
0841: }
0842: Filter bb = ff.bbox(ff.property(name), left, bottom, right,
0843: top, getContext().getCoordinateReferenceSystem()
0844: .toString());
0845: if (selectionManager != null) {
0846: selectionManager.selectionChanged(this , bb);
0847: }
0848:
0849: graphics.setXORMode(Color.green);
0850:
0851: /*
0852: * if ((lastX > 0) && (lastY > 0)) { drawRectangle(graphics); }
0853: */
0854:
0855: // draw new box
0856: lastX = x;
0857: lastY = y;
0858: drawRectangle(graphics);
0859: }
0860: }
0861:
0862: private void processDrag(int x1, int y1, int x2, int y2) {
0863: // System.out.println("processing drag from " + x1 + "," + y1 + " -> "
0864: // + x2 + "," + y2);
0865: if ((x1 == x2) && (y1 == y2)) {
0866: if (isClickable()) {
0867: mouseClicked(new MouseEvent(this , 0, new Date()
0868: .getTime(), 0, x1, y1, y2, false));
0869: }
0870:
0871: return;
0872: }
0873:
0874: Rectangle bounds = this .getBounds();
0875:
0876: double mapWidth = mapArea.getWidth();
0877: double mapHeight = mapArea.getHeight();
0878:
0879: double startX = ((x1 * mapWidth) / (double) bounds.width)
0880: + mapArea.getMinX();
0881: double startY = (((bounds.getHeight() - y1) * mapHeight) / (double) bounds.height)
0882: + mapArea.getMinY();
0883: double endX = ((x2 * mapWidth) / (double) bounds.width)
0884: + mapArea.getMinX();
0885: double endY = (((bounds.getHeight() - y2) * mapHeight) / (double) bounds.height)
0886: + mapArea.getMinY();
0887:
0888: if (state == JMapPane.Pan) {
0889: // move the image with the mouse
0890: // calculate X offsets from start point to the end Point
0891: double deltaX1 = endX - startX;
0892:
0893: // System.out.println("deltaX " + deltaX1);
0894: // new edges
0895: double left = mapArea.getMinX() - deltaX1;
0896: double right = mapArea.getMaxX() - deltaX1;
0897:
0898: // now for Y
0899: double deltaY1 = endY - startY;
0900:
0901: // System.out.println("deltaY " + deltaY1);
0902: double bottom = mapArea.getMinY() - deltaY1;
0903: double top = mapArea.getMaxY() - deltaY1;
0904: Coordinate ll = new Coordinate(left, bottom);
0905: Coordinate ur = new Coordinate(right, top);
0906:
0907: mapArea = fixAspectRatio(this .getBounds(), new Envelope(ll,
0908: ur));
0909: } else if (state == JMapPane.ZoomIn) {
0910: // make the dragged rectangle (in map coords) the new BBOX
0911: double left = Math.min(startX, endX);
0912: double right = Math.max(startX, endX);
0913: double bottom = Math.min(startY, endY);
0914: double top = Math.max(startY, endY);
0915: Coordinate ll = new Coordinate(left, bottom);
0916: Coordinate ur = new Coordinate(right, top);
0917:
0918: mapArea = fixAspectRatio(this .getBounds(), new Envelope(ll,
0919: ur));
0920: } else if (state == JMapPane.ZoomOut) {
0921: // make the dragged rectangle in screen coords the new map size?
0922: double left = Math.min(startX, endX);
0923: double right = Math.max(startX, endX);
0924: double bottom = Math.min(startY, endY);
0925: double top = Math.max(startY, endY);
0926: double nWidth = (mapWidth * mapWidth) / (right - left);
0927: double nHeight = (mapHeight * mapHeight) / (top - bottom);
0928: double deltaX1 = left - mapArea.getMinX();
0929: double nDeltaX1 = (deltaX1 * nWidth) / mapWidth;
0930: double deltaY1 = bottom - mapArea.getMinY();
0931: double nDeltaY1 = (deltaY1 * nHeight) / mapHeight;
0932: Coordinate ll = new Coordinate(
0933: mapArea.getMinX() - nDeltaX1, mapArea.getMinY()
0934: - nDeltaY1);
0935: double deltaX2 = mapArea.getMaxX() - right;
0936: double nDeltaX2 = (deltaX2 * nWidth) / mapWidth;
0937: double deltaY2 = mapArea.getMaxY() - top;
0938: double nDeltaY2 = (deltaY2 * nHeight) / mapHeight;
0939: Coordinate ur = new Coordinate(
0940: mapArea.getMaxX() + nDeltaX2, mapArea.getMaxY()
0941: + nDeltaY2);
0942: mapArea = fixAspectRatio(this .getBounds(), new Envelope(ll,
0943: ur));
0944: } else if (state == JMapPane.Select && selectionLayer != null) {
0945: double left = Math.min(startX, endX);
0946: double right = Math.max(startX, endX);
0947: double bottom = Math.min(startY, endY);
0948: double top = Math.max(startY, endY);
0949:
0950: String name = selectionLayer.getFeatureSource().getSchema()
0951: .getDefaultGeometry().getName();
0952:
0953: if (name == "") {
0954: name = "the_geom";
0955: }
0956: Filter bb = ff.bbox(ff.property(name), left, bottom, right,
0957: top, getContext().getCoordinateReferenceSystem()
0958: .toString());
0959: //System.out.println(bb.toString());
0960: if (selectionManager != null) {
0961: selectionManager.selectionChanged(this , bb);
0962: }
0963: /*FeatureCollection fc;
0964: selection = null;
0965: try {
0966: fc = selectionLayer.getFeatureSource().getFeatures(bb);
0967: selection = fc;
0968: } catch (IOException e) {
0969: e.printStackTrace();
0970: }
0971: */
0972: }
0973:
0974: repaint();
0975: }
0976:
0977: private boolean isClickable() {
0978: // TODO Auto-generated method stub
0979: return clickable;
0980: }
0981:
0982: private org.geotools.styling.Style setupStyle(int type, Color color) {
0983: StyleFactory sf = org.geotools.factory.CommonFactoryFinder
0984: .getStyleFactory(null);
0985: StyleBuilder sb = new StyleBuilder();
0986:
0987: org.geotools.styling.Style s = sf.createStyle();
0988: s.setTitle("selection");
0989:
0990: // TODO parameterise the color
0991: PolygonSymbolizer ps = sb.createPolygonSymbolizer(color);
0992: ps.setStroke(sb.createStroke(color));
0993:
0994: LineSymbolizer ls = sb.createLineSymbolizer(color);
0995: Graphic h = sb.createGraphic();
0996: h.setMarks(new Mark[] { sb.createMark("square", color) });
0997:
0998: PointSymbolizer pts = sb.createPointSymbolizer(h);
0999:
1000: // Rule r = sb.createRule(new Symbolizer[]{ps,ls,pts});
1001: switch (type) {
1002: case POLYGON:
1003: s = sb.createStyle(ps);
1004:
1005: break;
1006:
1007: case POINT:
1008: s = sb.createStyle(pts);
1009:
1010: break;
1011:
1012: case LINE:
1013: s = sb.createStyle(ls);
1014: }
1015:
1016: return s;
1017: }
1018:
1019: public void highlightChanged(HighlightChangedEvent e) {
1020: // TODO Auto-generated method stub
1021: org.opengis.filter.Filter f = e.getFilter();
1022:
1023: try {
1024: highlightFeature = highlightLayer.getFeatureSource()
1025: .getFeatures(f);
1026: } catch (IOException e1) {
1027: // TODO Auto-generated catch block
1028: e1.printStackTrace();
1029: }
1030:
1031: repaint();
1032: }
1033:
1034: public void propertyChange(PropertyChangeEvent evt) {
1035: // TODO Auto-generated method stub
1036: String prop = evt.getPropertyName();
1037:
1038: if (prop.equalsIgnoreCase("crs")) {
1039: context.setAreaOfInterest(context.getAreaOfInterest(),
1040: (CoordinateReferenceSystem) evt.getNewValue());
1041: }
1042: }
1043:
1044: public boolean isReset() {
1045: return reset;
1046: }
1047:
1048: public void setReset(boolean reset) {
1049: this .reset = reset;
1050: }
1051:
1052: public void layerAdded(MapLayerListEvent event) {
1053: changed = true;
1054:
1055: if (context.getLayers().length == 1) { // the first one
1056:
1057: try {
1058: mapArea = context.getLayerBounds();
1059: } catch (IOException e) {
1060: // TODO Auto-generated catch block
1061: e.printStackTrace();
1062: }
1063:
1064: reset = true;
1065: }
1066:
1067: repaint();
1068: }
1069:
1070: public void layerRemoved(MapLayerListEvent event) {
1071: changed = true;
1072: repaint();
1073: }
1074:
1075: public void layerChanged(MapLayerListEvent event) {
1076: changed = true;
1077: // System.out.println("layer changed - repaint");
1078: repaint();
1079: }
1080:
1081: public void layerMoved(MapLayerListEvent event) {
1082: changed = true;
1083: repaint();
1084: }
1085:
1086: private void drawRectangle(Graphics graphics) {
1087: // undraw last box/draw new box
1088: int left = Math.min(startX, lastX);
1089: int right = Math.max(startX, lastX);
1090: int top = Math.max(startY, lastY);
1091: int bottom = Math.min(startY, lastY);
1092: int width = right - left;
1093: int height = top - bottom;
1094: // System.out.println("drawing rect("+left+","+bottom+","+ width+","+
1095: // height+")");
1096: graphics.drawRect(left, bottom, width, height);
1097: }
1098:
1099: /**
1100: * if clickable is set to true then a single click on the map pane will zoom
1101: * or pan the map.
1102: *
1103: * @param clickable
1104: */
1105: public void setClickable(boolean clickable) {
1106: this .clickable = clickable;
1107: }
1108:
1109: public void mouseMoved(MouseEvent e) {
1110: // TODO Auto-generated method stub
1111: }
1112:
1113: public FeatureCollection getSelection() {
1114: return selection;
1115: }
1116:
1117: public void setSelection(FeatureCollection selection) {
1118: this .selection = selection;
1119: repaint();
1120: }
1121:
1122: /* (non-Javadoc)
1123: * @see org.geotools.gui.swing.event.SelectionChangeListener#selectionChanged(org.geotools.gui.swing.event.SelectionChangedEvent)
1124: */
1125: public void selectionChanged(SelectionChangedEvent e) {
1126:
1127: try {
1128: selection = selectionLayer.getFeatureSource().getFeatures(
1129: e.getFilter());
1130: repaint();
1131: } catch (IOException e1) {
1132: e1.printStackTrace();
1133: }
1134: }
1135:
1136: public SelectionManager getSelectionManager() {
1137: return selectionManager;
1138: }
1139:
1140: public void setSelectionManager(SelectionManager selectionManager) {
1141: this.selectionManager = selectionManager;
1142: this.selectionManager.addSelectionChangeListener(this);
1143:
1144: }
1145: }
|