From 002f3c6efa017209f60565d0beb6b0feb65d2c20 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sun, 9 May 2010 18:39:14 +0000 Subject: [PATCH 1/1] GisFieldViewer before leaving to field trip git-svn-id: https://svn.argeo.org/slc/trunk@3579 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../slc/geotools/swing/GisFieldViewer.java | 223 ++++++++++++++---- .../slc/geotools/swing/VersatileZoomTool.java | 34 ++- .../{Position.java => FieldPosition.java} | 8 +- .../org/argeo/slc/gpsbabel/GpsBabelCall.java | 1 + .../gpsbabel/GpsBabelPositionProvider.java | 29 ++- .../org/argeo/slc/jts/PositionProvider.java | 5 +- 6 files changed, 242 insertions(+), 58 deletions(-) rename runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/{Position.java => FieldPosition.java} (81%) diff --git a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/GisFieldViewer.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/GisFieldViewer.java index a79cfb5f9..b9eb10c53 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/GisFieldViewer.java +++ b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/GisFieldViewer.java @@ -1,6 +1,12 @@ package org.argeo.slc.geotools.swing; import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -14,28 +20,29 @@ import org.apache.commons.logging.LogFactory; import org.argeo.slc.core.deploy.DefaultResourceSet; import org.argeo.slc.core.deploy.ResourceSet; import org.argeo.slc.geotools.BeanFeatureTypeBuilder; -import org.argeo.slc.gis.model.Position; +import org.argeo.slc.gis.model.FieldPosition; import org.argeo.slc.jts.PositionProvider; import org.geotools.data.FileDataStoreFinder; import org.geotools.data.WorldFileReader; -import org.geotools.feature.DefaultFeatureCollection; -import org.geotools.feature.FeatureCollection; import org.geotools.gce.image.WorldImageFormat; +import org.geotools.geometry.DirectPosition2D; +import org.geotools.geometry.Envelope2D; import org.geotools.map.DefaultMapContext; -import org.geotools.map.DefaultMapLayer; import org.geotools.map.MapContext; import org.geotools.map.MapLayer; import org.geotools.styling.RasterSymbolizer; -import org.geotools.styling.SLD; import org.geotools.styling.Style; import org.geotools.styling.StyleBuilder; import org.geotools.swing.JMapFrame; import org.geotools.swing.JMapPane; -import org.opengis.feature.simple.SimpleFeature; -import org.opengis.feature.simple.SimpleFeatureType; +import org.geotools.swing.event.MapPaneAdapter; +import org.geotools.swing.event.MapPaneEvent; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; +import com.vividsolutions.jts.geom.Coordinate; + /** * GeoTools Quickstart demo application. Prompts the user for a shapefile and * displays its contents on the screen in a map frame @@ -44,11 +51,11 @@ import org.springframework.core.io.Resource; * http://svn.osgeo.org/geotools/trunk/demo/example/src/main/java/org * /geotools/demo/Quickstart.java $ */ -public class GisFieldViewer implements InitializingBean { +public class GisFieldViewer implements InitializingBean, DisposableBean { private final static Log log = LogFactory.getLog(GisFieldViewer.class); - protected final static BeanFeatureTypeBuilder POSITION = new BeanFeatureTypeBuilder( - Position.class); + protected final static BeanFeatureTypeBuilder POSITION = new BeanFeatureTypeBuilder( + FieldPosition.class); private DateFormat fieldPositionDateFormat = new SimpleDateFormat( "yyyyMMdd-HHmmss"); @@ -61,15 +68,21 @@ public class GisFieldViewer implements InitializingBean { private ResourceSet rasters = new DefaultResourceSet(); private JMapPane mapPane; + private JMapFrame mapFrame; /** in s */ - private Integer positionRefreshPeriod = 10; + private Integer positionRefreshPeriod = 1; + + private FieldPosition currentPosition = null; + private Boolean positionProviderDisconnected = false; + private VersatileZoomTool versatileZoomTool; public static void main(String[] args) throws Exception { new GisFieldViewer().afterPropertiesSet(); } public void afterPropertiesSet() { + new Thread(new PositionUpdater()).start(); // Create map context MapContext mapContext = new DefaultMapContext(); @@ -77,24 +90,41 @@ public class GisFieldViewer implements InitializingBean { // Now display the map // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - final JMapFrame frame = new JMapFrame(mapContext); - frame.enableStatusBar(true); - frame.enableToolBar(false); - frame.enableLayerTable(true); - frame.initComponents(); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + mapFrame = new JMapFrame(mapContext); + mapFrame.enableStatusBar(true); + mapFrame.enableToolBar(false); + mapFrame.enableLayerTable(true); + mapFrame.initComponents(); + mapFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame.setSize(800, 600); + mapFrame.setSize(800, 600); - mapPane = frame.getMapPane(); - mapPane.setCursorTool(new VersatileZoomTool()); + mapPane = mapFrame.getMapPane(); + versatileZoomTool = new VersatileZoomTool(); + mapPane.setCursorTool(versatileZoomTool); + + mapPane.addMapPaneListener(new CustomMapPaneListener()); SwingUtilities.invokeLater(new Runnable() { public void run() { - frame.setVisible(true); + // Fullscreen + // GraphicsEnvironment ge = GraphicsEnvironment + // .getLocalGraphicsEnvironment(); + // GraphicsDevice[] devices = ge.getScreenDevices(); + // if (devices.length < 1) + // throw new RuntimeException("No device available"); + // GraphicsDevice gd = devices[0]; + // mapFrame.setUndecorated(true); + // // http://ubuntuforums.org/showthread.php?t=820924 + // mapFrame.setResizable(true); + // gd.setFullScreenWindow(mapFrame); + mapFrame.setVisible(true); } }); + // Center on position in order to facten first rendering + centerOnPosition(); + // Rasters prepareJaiForRasters(); StyleBuilder styleBuilder = new StyleBuilder(); @@ -126,7 +156,11 @@ public class GisFieldViewer implements InitializingBean { } } - new Thread(new PositionUpdater()).start(); + } + + public void destroy() throws Exception { + if (mapFrame != null) + mapFrame.dispose(); } private void prepareJaiForRasters() { @@ -145,6 +179,37 @@ public class GisFieldViewer implements InitializingBean { } } + protected void receiveNewPosition(FieldPosition position) { + if (position != null && versatileZoomTool != null) { + positionProviderDisconnected = false; + currentPosition = position; + Point2D point2d = new DirectPosition2D(currentPosition + .getLocation().getCoordinate().x, currentPosition + .getLocation().getCoordinate().y); + versatileZoomTool.setFieldPosition(point2d); + drawPositionLocation(); + } else { + positionProviderDisconnected = true; + } + } + + protected void centerOnPosition() { + if (currentPosition == null) + return; + Envelope2D env = new Envelope2D(); + final double increment = 1d; + Coordinate positionCoo = currentPosition.getLocation().getCoordinate(); + env.setFrameFromDiagonal(positionCoo.x - increment, positionCoo.y + - increment, positionCoo.x + increment, positionCoo.y + + increment); + getMapPane().setDisplayArea(env); + + } + + protected JMapPane getMapPane() { + return mapPane; + } + public void setPositionProvider(PositionProvider positionProvider) { this.positionProvider = positionProvider; } @@ -166,26 +231,38 @@ public class GisFieldViewer implements InitializingBean { public void run() { MapLayer mapLayer = null; while (true) { - Position currentPosition = positionProvider.currentPosition(); - - if (mapPane.getDisplayArea().contains( - currentPosition.getLocation().getCoordinate())) { - SimpleFeature feature = POSITION - .buildFeature(currentPosition); - FeatureCollection collection = new DefaultFeatureCollection( - "Field Position " - + fieldPositionDateFormat - .format(currentPosition - .getTimestamp()), POSITION - .getFeatureType()); - collection.add(feature); - if (mapLayer != null) - mapPane.getMapContext().removeLayer(mapLayer); - Style style = SLD.createSimpleStyle(POSITION - .getFeatureType(), Color.RED); - mapLayer = new DefaultMapLayer(collection, style, ""); - mapPane.getMapContext().addLayer(mapLayer); + FieldPosition currentPosition = positionProvider + .currentPosition(); + + receiveNewPosition(currentPosition); + // versatileZoomTool.setFieldPosition(new + // Point2D(currentPosition + // .getLocation().getX(), currentPosition.getLocation() + // .getY())); + + if (currentPosition != null) { + + // if (mapPane.getDisplayArea().contains( + // currentPosition.getLocation().getCoordinate())) { + // SimpleFeature feature = POSITION + // .buildFeature(currentPosition); + // FeatureCollection + // collection = new DefaultFeatureCollection( + // "Field Position " + // + fieldPositionDateFormat + // .format(currentPosition + // .getTimestamp()), + // POSITION.getFeatureType()); + // collection.add(feature); + // if (mapLayer != null) + // mapPane.getMapContext().removeLayer(mapLayer); + // Style style = SLD.createSimpleStyle(POSITION + // .getFeatureType(), Color.RED); + // mapLayer = new DefaultMapLayer(collection, style, ""); + // mapPane.getMapContext().addLayer(mapLayer); + // } } + try { Thread.sleep(positionRefreshPeriod * 1000); } catch (InterruptedException e) { @@ -194,6 +271,70 @@ public class GisFieldViewer implements InitializingBean { } } } + + protected void drawPositionLocation() { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + if (currentPosition == null) + return; + + AffineTransform tr = getMapPane().getWorldToScreenTransform(); + DirectPosition2D geoCoords = new DirectPosition2D( + currentPosition.getLocation().getCoordinate().x, + currentPosition.getLocation().getCoordinate().y); + tr.transform(geoCoords, geoCoords); + geoCoords.setCoordinateReferenceSystem(getMapPane() + .getMapContext().getCoordinateReferenceSystem()); + + final int halfRefSize = 3; + Rectangle rect = new Rectangle((int) Math.round(geoCoords + .getX() + - halfRefSize), (int) Math.round(geoCoords.getY() + - halfRefSize), halfRefSize * 2 + 1, + halfRefSize * 2 + 1); + Graphics2D g2D = (Graphics2D) getMapPane().getGraphics(); + if (g2D == null) + return; + g2D.setColor(Color.WHITE); + if (positionProviderDisconnected) + g2D.setXORMode(Color.ORANGE); + else + g2D.setXORMode(Color.RED); + g2D.drawRect(rect.x, rect.y, rect.width, rect.height); + g2D.drawRect(rect.x - 1, rect.y - 1, rect.width + 2, + rect.height + 2); + } + }); + } + + private class CustomMapPaneListener extends MapPaneAdapter { + + @Override + public void onRenderingStopped(MapPaneEvent ev) { + drawPositionLocation(); + } + + @Override + public void onDisplayAreaChanged(MapPaneEvent ev) { + drawPositionLocation(); + } + + @Override + public void onRenderingProgress(MapPaneEvent ev) { + drawPositionLocation(); + } + + @Override + public void onRenderingStarted(MapPaneEvent ev) { + drawPositionLocation(); + } + + @Override + public void onResized(MapPaneEvent ev) { + drawPositionLocation(); + } + + } } // File rasterDir = new diff --git a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/VersatileZoomTool.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/VersatileZoomTool.java index 862e0a82d..796cb4f83 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/VersatileZoomTool.java +++ b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/VersatileZoomTool.java @@ -37,6 +37,8 @@ public class VersatileZoomTool extends AbstractZoomTool { private boolean computingZoomBox; private boolean panning; + private Point2D fieldPosition; + /** * Constructor */ @@ -69,19 +71,32 @@ public class VersatileZoomTool extends AbstractZoomTool { */ @Override public void onMouseClicked(MapMouseEvent e) { - centerMapToEvent(e); + if (SwingUtilities.isLeftMouseButton(e)) + centerMapToEvent(e, getZoom()); + else if (SwingUtilities.isRightMouseButton(e)) + centerMapToEvent(e, 1 / getZoom()); + else if (SwingUtilities.isMiddleMouseButton(e)) { + if (fieldPosition != null) { + Envelope2D env = new Envelope2D(); + final double increment = 1d; + env.setFrameFromDiagonal(fieldPosition.getX() - increment, + fieldPosition.getY() - increment, fieldPosition.getX() + + increment, fieldPosition.getY() + increment); + getMapPane().setDisplayArea(env); + } + } } - protected void centerMapToEvent(MapMouseEvent e) { + protected void centerMapToEvent(MapMouseEvent e, Double zoomArg) { Rectangle paneArea = getMapPane().getVisibleRect(); DirectPosition2D mapPos = e.getMapPosition(); double scale = getMapPane().getWorldToScreenTransform().getScaleX(); - // double newScale = scale * zoom; - // + double newScale = scale * zoomArg; + DirectPosition2D corner = new DirectPosition2D(mapPos.getX() - 0.5d - * paneArea.getWidth() / scale, mapPos.getY() + 0.5d - * paneArea.getHeight() / scale); + * paneArea.getWidth() / newScale, mapPos.getY() + 0.5d + * paneArea.getHeight() / newScale); Envelope2D newMapArea = new Envelope2D(); newMapArea.setFrameFromCenter(mapPos, corner); @@ -100,7 +115,8 @@ public class VersatileZoomTool extends AbstractZoomTool { if (SwingUtilities.isLeftMouseButton(ev)) { startDragPos = new DirectPosition2D(); startDragPos.setLocation(ev.getMapPosition()); - } else if (SwingUtilities.isMiddleMouseButton(ev)) { + } else if (SwingUtilities.isMiddleMouseButton(ev) + || SwingUtilities.isRightMouseButton(ev)) { panePos = ev.getPoint(); panning = true; } @@ -195,6 +211,10 @@ public class VersatileZoomTool extends AbstractZoomTool { }); } + public void setFieldPosition(Point2D fieldPosition) { + this.fieldPosition = fieldPosition; + } + /** * Custom drag box (hacked from JMapPane) so that we can change the behavior * depending on whether we pan or zoom. diff --git a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/Position.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/FieldPosition.java similarity index 81% rename from runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/Position.java rename to runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/FieldPosition.java index 7cc069329..540c53443 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/Position.java +++ b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/FieldPosition.java @@ -4,20 +4,20 @@ import java.util.Date; import com.vividsolutions.jts.geom.Point; -public class Position { +public class FieldPosition { private Point location; private Date timestamp; private String comment; - public Position() { + public FieldPosition() { } - public Position(Point location) { + public FieldPosition(Point location) { this.location = location; this.timestamp = new Date(); } - public Position(Point location, Date timestamp, String comment) { + public FieldPosition(Point location, Date timestamp, String comment) { this.location = location; this.timestamp = timestamp; this.comment = comment; diff --git a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelCall.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelCall.java index 4b0db1fd9..2b17f1bd9 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelCall.java +++ b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelCall.java @@ -46,6 +46,7 @@ public class GpsBabelCall extends SystemCall implements InitializingBean { setCommand(command); setStdOutLogLevel(LOG_STDOUT); + setExceptionOnFailed(true); } public final static void main(String[] args) { diff --git a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelPositionProvider.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelPositionProvider.java index 83aca1d84..36d5d2136 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelPositionProvider.java +++ b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelPositionProvider.java @@ -2,7 +2,9 @@ package org.argeo.slc.gpsbabel; import java.util.StringTokenizer; -import org.argeo.slc.gis.model.Position; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.gis.model.FieldPosition; import org.argeo.slc.jts.PositionProvider; import com.vividsolutions.jts.geom.Coordinate; @@ -10,6 +12,8 @@ import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; public class GpsBabelPositionProvider implements PositionProvider { + private Log log = LogFactory.getLog(GpsBabelPositionProvider.class); + private GpsBabelCall gpsBabelCall; private GeometryFactory geometryFactory = new GeometryFactory(); @@ -17,22 +21,39 @@ public class GpsBabelPositionProvider implements PositionProvider { private String inputFormat = "garmin,get_posn"; private String inputFile = "usb:"; + private Boolean silentlyFailing = false; + public void init() { gpsBabelCall = new GpsBabelCall(inputFormat, inputFile, "csv", "-"); } - public Position currentPosition() { + public FieldPosition currentPosition() { // lazy init if (gpsBabelCall == null) init(); - String output = gpsBabelCall.function(); + String output; + try { + output = gpsBabelCall.function(); + silentlyFailing = false; + } catch (Exception e) { + if (!silentlyFailing) { + log.warn(e.getMessage() + + ": " + + (e.getCause() != null ? e.getCause().getMessage() + : "")); + if (log.isTraceEnabled()) + e.printStackTrace(); + silentlyFailing = true; + } + return null; + } StringTokenizer st = new StringTokenizer(output, ","); Double latitude = Double.parseDouble(st.nextToken()); Double longitude = Double.parseDouble(st.nextToken()); Point position = geometryFactory.createPoint(new Coordinate(longitude, latitude)); - return new Position(position); + return new FieldPosition(position); } public void setInputFormat(String inputFormat) { diff --git a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/jts/PositionProvider.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/jts/PositionProvider.java index 808b71c5e..a842fcd02 100644 --- a/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/jts/PositionProvider.java +++ b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/jts/PositionProvider.java @@ -1,7 +1,8 @@ package org.argeo.slc.jts; -import org.argeo.slc.gis.model.Position; +import org.argeo.slc.gis.model.FieldPosition; public interface PositionProvider { - public Position currentPosition(); + /** @return the position or null if it cannot be retrieved */ + public FieldPosition currentPosition(); } -- 2.39.2