[Schmitzm-commits] r511 - branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Thu Nov 5 18:41:34 CET 2009


Author: alfonx
Date: 2009-11-05 18:41:33 +0100 (Thu, 05 Nov 2009)
New Revision: 511

Added:
   branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/GeomFilterGenerator.java
   branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/SelectXMapPaneMouseListener.java
   branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/ZoomXMapPaneMouseListener.java
Modified:
   branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/XMapPane.java
Log:
compile error free ... XMapPane migration complete...

Added: branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/GeomFilterGenerator.java
===================================================================
--- branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/GeomFilterGenerator.java	2009-11-05 17:39:37 UTC (rev 510)
+++ branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/GeomFilterGenerator.java	2009-11-05 17:41:33 UTC (rev 511)
@@ -0,0 +1,249 @@
+package gtmig.org.geotools.swing;
+
+import java.awt.geom.Point2D;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.geotools.data.FeatureSource;
+import org.geotools.filter.AbstractFilter;
+import org.geotools.filter.GeometryFilterImpl;
+import org.geotools.filter.spatial.DWithinImpl;
+import org.geotools.referencing.CRS;
+import org.geotools.resources.CRSUtilities;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.feature.type.GeometryDescriptor;
+import org.opengis.filter.expression.Expression;
+import org.opengis.filter.spatial.BinarySpatialOperator;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.geotools.FilterUtil;
+import schmitzm.geotools.JTSUtil;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Geometry;
+
+/**
+ * The {@link GeomFilterGenerator} prepares a {@link BinarySpatialOperator}
+ * filter for multiple use. Only the "right" argument is prepared. The
+ * "left" argument (the geometry attribute of the {@link FeatureSource} to
+ * filter) is first set on calling {@link #adaptFilter(FeatureSource)} for a
+ * specific {@link FeatureSource}. This method also takes care to recreate
+ * the filter (or its "right" argument) if the given {@link FeatureSource}
+ * has another {@link CoordinateReferenceSystem} than the base constraint.<br>
+ * The type of filter (e.g. distance or bounding box) is specified by the
+ * subclass implemenation of
+ * {@link #prepareFilter(CoordinateReferenceSystem)} .
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+ public abstract class GeomFilterGenerator {
+	/**
+	 * Holds the {@link CoordinateReferenceSystem} the filter constraint
+	 * bases on.
+	 */
+	protected CoordinateReferenceSystem baseCRS = null;
+	/**
+	 * Caches the base filter constraint for several
+	 * {@link CoordinateReferenceSystem CoordinateReferenceSystems}.
+	 */
+	protected Map<CoordinateReferenceSystem, GeometryFilterImpl> filterCache = new HashMap<CoordinateReferenceSystem, GeometryFilterImpl>();
+
+	/**
+	 * Creates a new filter generator
+	 * 
+	 * @param crs
+	 *            {@link CoordinateReferenceSystem} the base constraint
+	 *            ("right" filter argument is relative to)
+	 */
+	public GeomFilterGenerator(CoordinateReferenceSystem crs) {
+		this.baseCRS = crs;
+	}
+
+	/**
+	 * Creates a filter containing the base constraint ("right" argument)
+	 * transformed to the given {@link CoordinateReferenceSystem}.
+	 * 
+	 * @param crs
+	 *            the {@link CoordinateReferenceSystem} the base constraint
+	 *            is transformed to
+	 */
+	protected abstract GeometryFilterImpl prepareFilter(
+			CoordinateReferenceSystem crs);
+
+	/**
+	 * Completes the filter with its "left" argument for a concrete
+	 * {@link FeatureSource}. If the {@link FeatureSource FeatureSource's}
+	 * CRS differs from the CRS the base constraint is specified in, first a
+	 * new filter is created by calling
+	 * {@link #prepareFilter(CoordinateReferenceSystem)}.
+	 * 
+	 * @param fs
+	 *            {@link FeatureSource} the filter is adaped to
+	 * @return
+	 */
+	public GeometryFilterImpl adaptFilter(
+			FeatureSource<SimpleFeatureType, SimpleFeature> fs) {
+		GeometryDescriptor geomDescr = fs.getSchema()
+				.getGeometryDescriptor();
+		CoordinateReferenceSystem fsCRS = geomDescr
+				.getCoordinateReferenceSystem();
+		GeometryFilterImpl filter = filterCache.get(fsCRS);
+		if (filter == null) {
+			filter = prepareFilter(fsCRS);
+			filterCache.put(fsCRS, filter);
+		}
+		Expression geometry = FilterUtil.FILTER_FAC2.property(geomDescr.getLocalName());
+		filter.setExpression1(geometry);
+		return filter;
+	}
+
+	/**
+	 * {@link GeomFilterGenerator} for a bounding box constraint.
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 */
+	public static class BoundingBoxFilterGenerator extends GeomFilterGenerator {
+		/**
+		 * Holds the base constraint (bounding box {@link Envelope}) relative to
+		 * the {@linkplain GeomFilterGenerator#baseCRS base CRS}.
+		 */
+		protected Envelope baseEnv = null;
+
+		/**
+		 * Creates a new filter generator.
+		 * 
+		 * @param baseEnv
+		 *            defines the bounding box
+		 * @param baseCrs
+		 *            defines the CRS of the bounding box
+		 */
+		public BoundingBoxFilterGenerator(Envelope baseEnv,
+				CoordinateReferenceSystem baseCrs) {
+			super(baseCrs);
+			this.baseEnv = baseEnv;
+		}
+
+		/**
+		 * Prepares a filter with the bounding box transformed to the given
+		 * {@link CoordinateReferenceSystem} as the "right" argument.
+		 * 
+		 * @param crs
+		 *            the {@link CoordinateReferenceSystem} the bounding box is
+		 *            transformed to
+		 */
+		protected GeometryFilterImpl prepareFilter(CoordinateReferenceSystem crs) {
+			Envelope bbEnv = baseEnv;
+			if (!CRS.equalsIgnoreMetadata(baseCRS,crs))
+				bbEnv = JTSUtil.transformEnvelope(baseEnv, baseCRS, crs);
+			// Filter fuer Envelope zusammenstellen
+			Expression bbox = FilterUtil.FILTER_FAC.createBBoxExpression(bbEnv);
+			GeometryFilterImpl bboxFilter = (GeometryFilterImpl) FilterUtil.FILTER_FAC
+					.createGeometryFilter(AbstractFilter.GEOMETRY_BBOX);
+			// GeometryFilterImpl bboxFilter =
+			// (GeometryFilterImpl)ff.createGeometryFilter(AbstractFilter.
+			// GEOMETRY_WITHIN);
+			bboxFilter.setExpression2(bbox);
+			return bboxFilter;
+		}
+	}
+
+	/**
+	 * {@link GeomFilterGenerator} for a "near distance" constraint.
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 */
+	public static class NearPointFilterGenerator extends GeomFilterGenerator {
+		/**
+		 * Holds the base constraint (coordinate) relative to the
+		 * {@linkplain GeomFilterGenerator#baseCRS base CRS}.
+		 */
+		protected Coordinate basePoint = null;
+		/**
+		 * Holds the distance "around" the base point relative to the
+		 * {@linkplain GeomFilterGenerator#baseCRS base CRS}.
+		 */
+		protected double baseDist = 0.0;
+		/**
+		 * Holds a point which is in distance {@link #baseDist} to the
+		 * {@link #basePoint}.
+		 */
+		protected Coordinate basePoint2 = null;
+
+		/**
+		 * Creates a new filter generator.
+		 * 
+		 * @param basePoint
+		 *            defNearPointFilterGeneratorines the point for the "near point" constraint
+		 * @param dist
+		 *            defines the distance around the base point
+		 * @param crs
+		 *            defines the CRS of base point
+		 */
+		public NearPointFilterGenerator(Coordinate basePoint, double dist,
+				CoordinateReferenceSystem crs) {
+			super(crs);
+			this.basePoint = basePoint;
+			this.baseDist = dist;
+			// Create a point which is in distance "dist" to the base point
+			this.basePoint2 = new Coordinate(basePoint.x + dist, basePoint.y);
+		}
+
+		/**
+		 * Creates a new filter generator.
+		 * 
+		 * @param basePoint
+		 *            defines the point for the "near point" constraint
+		 * @param dist
+		 *            defines the distance around the base point
+		 * @param crs
+		 *            defines the CRS of base point
+		 */
+		public NearPointFilterGenerator(Point2D basePoint, double dist,
+				CoordinateReferenceSystem crs) {
+			this(new Coordinate(basePoint.getX(), basePoint.getY()), dist, crs);
+		}
+
+		/**
+		 * Prepares a filter with the base point and distance transformed to the
+		 * given {@link CoordinateReferenceSystem} as the "right" argument.
+		 * 
+		 * @param crs
+		 *            the {@link CoordinateReferenceSystem} the point and
+		 *            distance is transformed to
+		 */
+		protected GeometryFilterImpl prepareFilter(CoordinateReferenceSystem crs) {
+			Coordinate nearPoint = basePoint;
+			double nearDist = baseDist;
+			if (!baseCRS.equals(crs)) {
+				nearPoint = JTSUtil
+						.transformCoordinate(basePoint, baseCRS, crs);
+				// Transform the distance (maybe "dirty")
+				// --> transform the point2 and calculate the
+				// distance to the tranformed base point
+				Coordinate nearPoint2 = JTSUtil.transformCoordinate(basePoint2,
+						baseCRS, crs);
+
+				if (nearPoint == null || nearPoint2 == null)
+					throw new RuntimeException("Unable to transform CRS from "
+							+ baseCRS + " to " + crs);
+
+				nearDist = Math.abs(nearPoint.x - nearPoint2.x);
+			}
+			// Filter fuer Point zusammenstellen
+			final Geometry geometry = FilterUtil.GEOMETRY_FAC
+					.createPoint(nearPoint);
+
+			final DWithinImpl dwithinFilter = new DWithinImpl(
+					FilterUtil.FILTER_FAC2, null, null);
+			dwithinFilter.setDistance(nearDist);
+			dwithinFilter.setExpression2(FilterUtil.FILTER_FAC2
+					.literal(geometry));
+
+			return dwithinFilter;
+		}
+
+	}
+
+}
\ No newline at end of file

Added: branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/SelectXMapPaneMouseListener.java
===================================================================
--- branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/SelectXMapPaneMouseListener.java	2009-11-05 17:39:37 UTC (rev 510)
+++ branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/SelectXMapPaneMouseListener.java	2009-11-05 17:41:33 UTC (rev 511)
@@ -0,0 +1,268 @@
+package gtmig.org.geotools.swing;
+
+import gtmig.org.geotools.swing.GeomFilterGenerator.BoundingBoxFilterGenerator;
+
+import java.awt.Cursor;
+import java.awt.Point;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.geom.Point2D;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import org.apache.log4j.Logger;
+import org.geotools.data.memory.MemoryFeatureCollection;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.map.MapLayer;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+
+import schmitzm.geotools.gui.SelectableXMapPane;
+import schmitzm.geotools.map.event.FeatureSelectedEvent;
+import sun.misc.PerformanceLogger;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.GeometryFactory;
+
+public class SelectXMapPaneMouseListener extends MouseAdapter {
+
+	private final SelectableXMapPane xMapPane;
+	private boolean enabled;
+
+	public boolean isEnabled() {
+		if (!xMapPane.isWellDefined())
+			return false;
+		if ((xMapPane.getState() == XMapPane.ZOOM_IN
+				|| xMapPane.getState() == xMapPane.ZOOM_OUT || xMapPane
+				.getState() == xMapPane.PAN))
+			return false;
+		if (xMapPane.getState() == XMapPane.NONE)
+			;
+		return enabled;
+	}
+
+	/**
+	 * Reagiert auf Linksklick mit der ueber {@link #setState(int)}eingestellten
+	 * Aktion und auf Rechtsklick mit Zoom-Out (sofern {@link #ZOOM_IN}-State
+	 * fuer Linksklick eingestellt). Alle anderen Klicks werden ignoriert.
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 *         (University of Bonn/Germany)
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void mouseClicked(MouseEvent e) {
+		if (!isEnabled())
+			return;
+		
+		xMapPane.setCursor(XMapPane.WAIT_CURSOR);
+		//		
+		// int clickX = e.getX();
+		// int clickY = e.getY();
+		// selectionPerformed(clickX, clickY, clickX, clickY);}
+		//		
+		int state = xMapPane.getState();
+
+		/**
+		 * BEGIN StefanChange Dieser Block findet sichtbare Features im Umkreis
+		 * des Mausklicks und kümmert sich selbst um das verschicken der Events.
+		 * Dabei wird z.Zt. immer eine FeaterCollection mit nur einem
+		 * SimpleFeature verschickt. Und zwar jenes SimpleFeature, welches am
+		 * nächsten liegt.
+		 */
+
+		// Fenster-Koordinate in Geo-Koordinate umwandelt
+		Point2D geoCoord = xMapPane.getScreenToWorld().transform(e.getPoint(),
+				null);
+		
+		com.vividsolutions.jts.geom.Point mousePoint = new GeometryFactory()
+				.createPoint(new Coordinate(geoCoord.getX(), geoCoord.getY()));
+
+		// Rechnet 10 Pixel in die Einheit der Karte um.
+		final Point pAtDistance = new Point((int) e.getPoint().getX() + 10,
+				(int) e.getPoint().getY());
+		final Point2D geoCoordAtDistance = xMapPane.getScreenToWorld()
+				.transform(pAtDistance, null);
+		final Double dist = Math.abs(geoCoordAtDistance.getX()
+				- geoCoord.getX()) / 2;
+
+//		final Envelope envelope = new Envelope(geoCoord.getX(),
+//				geoCoord.getY(), geoCoord.getX(), geoCoord.getY());
+
+		//
+		// This is a tweak. The NearPointFilterGenerator doesn't work
+		// any more in GT2.6... So we use a small BBOX.
+		// Well, it's not the
+		// NearPointFilterGenerator, but GeoTools that fails. I already
+		// invested 3h in this... I guess the bug is in
+		// ExtractBoundsFilterVisitor.visit(ProperyName) retuning null.
+		// It should return the BBOX of value the named property.
+
+		// Hashtable<MapLayer, FeatureCollection<SimpleFeatureType,
+		// SimpleFeature>> result = findVisibleFeatures(
+		// new NearPointFilterGenerator(geoCoord, dist,
+		// getContext().getCoordinateReferenceSystem()),
+		// state, envelope);
+		
+//		envelope.expandBy(dist);
+//
+		Envelope envelope = new Envelope(geoCoord.getX() - dist, geoCoord
+				.getY()
+				- dist, geoCoord.getX() + dist, geoCoord.getY() + dist);
+
+		Hashtable<MapLayer, FeatureCollection<SimpleFeatureType, SimpleFeature>> result = xMapPane
+				.findVisibleFeatures(new BoundingBoxFilterGenerator(  envelope,
+						xMapPane.getContext().getCoordinateReferenceSystem()),
+						state, envelope);
+
+		// Ein Event auslösen für das jeweils nächste Feature pro Layer
+		for (Enumeration<MapLayer> element = result.keys(); element
+				.hasMoreElements();) {
+
+			MapLayer layer = element.nextElement();
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc = result
+					.get(layer);
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fcOne;
+
+			if (fc != null && !fc.isEmpty()) {
+
+				if (fc.size() > 1) {
+					// Hier werden alle Features weggeschmissen, bis auf
+					// das raeumlich naechste.
+
+					SimpleFeature nearestFeature = null;
+					Double nearestDist = 0.0;
+
+					Iterator<SimpleFeature> fcIt = fc.iterator();
+					try {
+
+						while (fcIt.hasNext()) {
+							SimpleFeature f = fcIt.next();
+							Object obj = f.getAttribute(0);
+
+							if (obj instanceof Geometry) {
+								// Bei Punkten ja noch ganz einfach:
+								Geometry featureGeometry = (Geometry) obj;
+								double distance = featureGeometry
+										.distance(mousePoint);
+
+								if ((nearestFeature == null)
+										|| (distance < nearestDist)) {
+									nearestFeature = f;
+									nearestDist = distance;
+								}
+							} else {
+								LOGGER
+										.info("!obj instanceof Geometry      obj = "
+												+ obj.getClass()
+														.getSimpleName());
+							}
+
+						}
+
+					} finally {
+						fc.close(fcIt);
+					}
+
+					fcOne = new MemoryFeatureCollection(fc.getSchema());
+					fc.clear();
+					fcOne.add(nearestFeature);
+				} else {
+					fcOne = fc;
+				}
+				xMapPane.fireMapPaneEvent(new FeatureSelectedEvent(xMapPane,
+						layer, envelope, fcOne));
+			}
+		}
+		
+		xMapPane.updateCursorAndRepaintTimer();
+
+	}
+
+	/**
+	 * Verarbeitet die Mausrad-Aktion, indem gezoomed wird.
+	 * 
+	 * @param wheelEvt
+	 *            Mausrad-Event
+	 */
+	@Override
+	public void mouseWheelMoved(MouseWheelEvent wheelEvt) {
+		if (!isEnabled())
+			return;
+
+		final int units = wheelEvt.getUnitsToScroll();
+		if (units > 0)
+			xMapPane.zoomTo(wheelEvt.getPoint(), 1. + .11 * units);
+		else
+			xMapPane.zoomTo(wheelEvt.getPoint(), 2. / -units);
+	}
+
+	@Override
+	public void mouseDragged(final MouseEvent event) {
+		if (!isEnabled())
+			return;
+
+		xMapPane.mouseDragged(startPos, lastPos, event);
+
+		lastPos = event.getPoint();
+	}
+
+	/**
+	 * Stores beginning of a drag event in window coordinates
+	 */
+	protected Point startPos;
+
+	/**
+	 * Stores last position of a drag event in window coordinates
+	 */
+	protected Point lastPos;
+
+	public void mouseReleased(final MouseEvent event) {
+		if (!isEnabled())
+			return;
+
+		if (xMapPane.getState() == XMapPane.PAN
+				|| event.getButton() == MouseEvent.BUTTON3) {
+			xMapPane.performPan();
+		} else if (xMapPane.getState() == XMapPane.SELECT_ALL
+				|| xMapPane.getState() == XMapPane.SELECT_TOP) {
+			xMapPane.drawRectangle(xMapPane.getGraphics(), startPos, event
+					.getPoint());
+
+			Point mp = event.getPoint();
+
+			// keine wirkliche Selektion, sondern nur ein Klick
+			if (startPos.x == mp.x || startPos.y == mp.y) {
+				mouseClicked(event);
+				return;
+			}
+
+			// SELECTION!
+			xMapPane.performSelectionEvent(startPos.x, startPos.y, mp.x, mp.y);
+		}
+
+	}
+
+	public void mousePressed(final MouseEvent e) {
+		if (!isEnabled())
+			return;
+		startPos = new Point(e.getPoint());
+		lastPos = new Point(e.getPoint());
+	}
+
+	public SelectXMapPaneMouseListener(SelectableXMapPane xMapPane) {
+		this.xMapPane = xMapPane;
+	}
+
+	public void setEnabled(boolean enabled) {
+		this.enabled = enabled;
+	}
+
+	private static Logger LOGGER = Logger
+			.getLogger(SelectXMapPaneMouseListener.class);
+
+}

Modified: branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/XMapPane.java
===================================================================
--- branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/XMapPane.java	2009-11-05 17:39:37 UTC (rev 510)
+++ branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/XMapPane.java	2009-11-05 17:41:33 UTC (rev 511)
@@ -22,7 +22,6 @@
 
 import java.awt.AlphaComposite;
 import java.awt.Color;
-import java.awt.Composite;
 import java.awt.Cursor;
 import java.awt.Font;
 import java.awt.Graphics;
@@ -69,6 +68,7 @@
 import org.geotools.renderer.label.LabelCacheImpl;
 import org.geotools.renderer.lite.LabelCache;
 import org.geotools.swing.JMapPane;
+import org.geotools.swing.RenderingExecutor;
 import org.geotools.swing.event.MapMouseEvent;
 import org.geotools.swing.event.MapPaneEvent;
 import org.geotools.swing.event.MapPaneListener;
@@ -85,7 +85,6 @@
 import schmitzm.geotools.map.event.JMapPaneListener;
 import schmitzm.geotools.map.event.MapLayerAdapter;
 import schmitzm.swing.SwingUtil;
-import skrueger.geotools.RenderingExecutor;
 
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.Envelope;
@@ -1089,7 +1088,7 @@
 
 	public static final int NONE = -123;
 
-	private RenderingExecutor localExecuter;
+	private skrueger.geotools.RenderingExecutor localExecuter;
 
 	private BufferedImage finalImage;
 
@@ -1464,7 +1463,7 @@
 		 */
 
 		if (getBgContext() != null) {
-			bgExecuter = new RenderingExecutor(this);
+			bgExecuter = new skrueger.geotools.RenderingExecutor(this);
 			LOGGER.debug("starting bg renderer:");
 			// /* System.out.println("rendering"); */
 			final GTRenderer createGTRenderer = GTUtil.createGTRenderer(
@@ -1475,7 +1474,7 @@
 		}
 
 		if (getContext() != null) {
-			localExecuter = new RenderingExecutor(this);
+			localExecuter = new skrueger.geotools.RenderingExecutor(this);
 			LOGGER.debug("starting local renderer:");
 			final GTRenderer createGTRenderer = GTUtil.createGTRenderer(
 					localContext, getRendererHints());

Added: branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/ZoomXMapPaneMouseListener.java
===================================================================
--- branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/ZoomXMapPaneMouseListener.java	2009-11-05 17:39:37 UTC (rev 510)
+++ branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/ZoomXMapPaneMouseListener.java	2009-11-05 17:41:33 UTC (rev 511)
@@ -0,0 +1,240 @@
+package gtmig.org.geotools.swing;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+
+import org.apache.log4j.Logger;
+
+import schmitzm.swing.SwingUtil;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+
+public class ZoomXMapPaneMouseListener extends MouseAdapter {
+
+	private static Logger LOGGER = Logger
+			.getLogger(ZoomXMapPaneMouseListener.class);
+
+
+	protected final XMapPane xMapPane;
+
+	protected boolean enabled = true;
+
+	public ZoomXMapPaneMouseListener(XMapPane xMapPane) {
+		if (xMapPane == null) throw new IllegalArgumentException("xMapPane may not be null");
+		this.xMapPane = xMapPane;
+	}
+
+	/**
+	 * Stores beginning of a drag event in window coordinates
+	 */
+	protected Point startPos;
+	
+	/**
+	 * Stores last position of a drag event in window coordinates
+	 */
+	protected  Point lastPos;
+
+	/**
+	 * Draws a rectangle in XOR mode from the origin at {@link #startPos} to the
+	 * given point. All in screen coordinates.
+	 */
+	protected void drawRectangle(final Graphics graphics, Point e) {
+		// undraw last box/draw new box
+		final int left = Math.min(startPos.x, e.x);
+		final int right = Math.max(startPos.x, e.x);
+		final int top = Math.max(startPos.y, e.y);
+		final int bottom = Math.min(startPos.y, e.y);
+		final int width = right - left;
+		final int height = top - bottom;
+
+		if (width == 0 && height == 0)
+			return;
+
+		graphics.setXORMode(Color.WHITE);
+		graphics.drawRect(left, bottom, width, height);
+	}
+
+	public void mousePressed(final MouseEvent e) {
+		if (!isEnabled())
+			return;
+		startPos = new Point(e.getPoint());
+		lastPos = new Point(e.getPoint());
+	}
+
+	public void mouseReleased(final MouseEvent e) {
+		if (!isEnabled())
+			return;
+
+		final Rectangle bounds = xMapPane.getBounds();
+
+		Envelope mapArea = xMapPane.getMapArea();
+
+		// Replace with transform and translate
+		final double mapWidth = mapArea.getWidth();
+		final double mapHeight = mapArea.getHeight();
+
+		final double startX = ((startPos.x * mapWidth) / (double) bounds.width)
+				+ mapArea.getMinX();
+		final double startY = (((bounds.getHeight() - startPos.y) * mapHeight) / (double) bounds.height)
+				+ mapArea.getMinY();
+		final double endX = ((e.getPoint().x * mapWidth) / (double) bounds.width)
+				+ mapArea.getMinX();
+		final double endY = (((bounds.getHeight() - e.getPoint().y) * mapHeight) / (double) bounds.height)
+				+ mapArea.getMinY();
+
+		if ((xMapPane.getState() == XMapPane.PAN)
+				|| (e.getButton() == MouseEvent.BUTTON3)) {
+			xMapPane.performPan();
+
+		} else if (xMapPane.getState() == XMapPane.ZOOM_IN) {
+
+			drawRectangle(xMapPane.getGraphics(), e.getPoint());
+
+			// Don't zoom too small areas
+			if ((Math.abs(startPos.x - e.getPoint().x) * Math.abs(e.getPoint().y - startPos.y)) < 160)
+				return;
+
+			final double left = Math.min(startX, endX);
+			final double right = Math.max(startX, endX);
+			final double bottom = Math.min(startY, endY);
+			final double top = Math.max(startY, endY);
+			final Coordinate ll = new Coordinate(left, bottom);
+			final Coordinate ur = new Coordinate(right, top);
+
+			xMapPane.setMapArea(new Envelope(ll, ur));
+
+		} else if (xMapPane.getState() == XMapPane.ZOOM_OUT) {
+
+			// Remove the rectangle
+			drawRectangle(xMapPane.getGraphics(), e.getPoint());
+
+			// make the dragged rectangle in screen coords the new map size?
+			final double left = Math.min(startX, endX);
+			final double right = Math.max(startX, endX);
+			final double bottom = Math.min(startY, endY);
+			final double top = Math.max(startY, endY);
+			final double nWidth = (mapWidth * mapWidth) / (right - left);
+			final double nHeight = (mapHeight * mapHeight) / (top - bottom);
+			final double deltaX1 = left - mapArea.getMinX();
+			final double nDeltaX1 = (deltaX1 * nWidth) / mapWidth;
+			final double deltaY1 = bottom - mapArea.getMinY();
+			final double nDeltaY1 = (deltaY1 * nHeight) / mapHeight;
+			final Coordinate ll = new Coordinate(mapArea.getMinX() - nDeltaX1,
+					mapArea.getMinY() - nDeltaY1);
+			final double deltaX2 = mapArea.getMaxX() - right;
+			final double nDeltaX2 = (deltaX2 * nWidth) / mapWidth;
+			final double deltaY2 = mapArea.getMaxY() - top;
+			final double nDeltaY2 = (deltaY2 * nHeight) / mapHeight;
+			final Coordinate ur = new Coordinate(mapArea.getMaxX() + nDeltaX2,
+					mapArea.getMaxY() + nDeltaY2);
+
+			xMapPane.setMapArea(new Envelope(ll, ur));
+		}
+
+
+	}
+
+
+	public void setEnabled(boolean enabled) {
+		this.enabled = enabled;
+	}
+
+	/**
+	 * Returns <code>true</code> if the xMapPane is well defined and the
+	 * listener is enabled.
+	 */
+	public boolean isEnabled() {
+		return enabled && xMapPane.isWellDefined();
+	}
+	
+	/**
+	 * Verarbeitet die Mausrad-Aktion, indem gezoomed wird.
+	 * 
+	 * @param wheelEvt
+	 *            Mausrad-Event
+	 */
+	public void mouseWheelMoved(MouseWheelEvent wheelEvt) {
+		if (!isEnabled()) return;
+
+		final int units = wheelEvt.getUnitsToScroll();
+		if (units > 0)
+			xMapPane.zoomTo(wheelEvt.getPoint(), 1. + .11 * units);
+		else
+			xMapPane.zoomTo(wheelEvt.getPoint(), 2. / -units);
+	}
+
+	@Override
+	public void mouseClicked(final MouseEvent e) {
+
+		if (!isEnabled())
+			return;
+
+		int state = xMapPane.getState();
+
+		// Nothing to do for panning
+		if (state == XMapPane.PAN)
+			return;
+
+		// double zoomFactor = 1.;
+		//		
+		// final Envelope mapArea = xMapPane.getMapArea();
+		// if (mapArea == null)
+		// return;
+		//
+		// final Rectangle bounds = xMapPane.getVisibleRect();
+		//
+		// final double x = (double) (e.getX());
+		// final double y = (double) (e.getY());
+		// final double width = mapArea.getWidth();
+		// final double height = mapArea.getHeight();
+		// final double width2 = width / 2.0;
+		// final double height2 = height / 2.0;
+		// final double mapX = ((x * width) / (double) bounds.width)
+		// + mapArea.getMinX();
+		// final double mapY = (((bounds.getHeight() - y) * height) / (double)
+		// bounds.height)
+		// + mapArea.getMinY();
+		// double zlevel = 1.0;
+		//		
+		if (state == XMapPane.ZOOM_IN && e.getButton() == MouseEvent.BUTTON1) {
+			xMapPane.zoomTo(e.getPoint(), 1 / 2.);
+		} else if (state == XMapPane.ZOOM_IN
+				&& e.getButton() == MouseEvent.BUTTON3
+				|| state == XMapPane.ZOOM_OUT) {
+			xMapPane.zoomTo(e.getPoint(), 2.);
+		}
+		//
+		// final Coordinate ll = new Coordinate(mapX - (width2 / zlevel), mapY
+		// - (height2 / zlevel));
+		// final Coordinate ur = new Coordinate(mapX + (width2 / zlevel), mapY
+		// + (height2 / zlevel));
+		// final Envelope newMapArea = new Envelope(ll, ur);
+		//
+		// xMapPane.setMapArea(newMapArea);
+
+		// xMapPane.repaint();
+
+	}
+
+	/**
+	 * Constantly fired while the mouse is dragging
+	 */
+	public void mouseDragged(final MouseEvent event) {
+		if (!isEnabled())
+			return;
+		
+		xMapPane.mouseDragged(startPos, lastPos, event);
+
+
+		lastPos = event.getPoint();
+	}
+
+
+}



More information about the Schmitzm-commits mailing list