GisFieldViewer before leaving to field trip
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 9 May 2010 18:39:14 +0000 (18:39 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 9 May 2010 18:39:14 +0000 (18:39 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@3579 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/GisFieldViewer.java
runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/geotools/swing/VersatileZoomTool.java
runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/FieldPosition.java [new file with mode: 0644]
runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/Position.java [deleted file]
runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelCall.java
runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gpsbabel/GpsBabelPositionProvider.java
runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/jts/PositionProvider.java

index a79cfb5f9bc1e763d450726d64174e74b16758dd..b9eb10c5396124a4f46460c0ffc39be5746de20f 100644 (file)
@@ -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> POSITION = new BeanFeatureTypeBuilder<Position>(
-                       Position.class);
+       protected final static BeanFeatureTypeBuilder<FieldPosition> POSITION = new BeanFeatureTypeBuilder<FieldPosition>(
+                       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<SimpleFeatureType, SimpleFeature> 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<SimpleFeatureType, SimpleFeature>
+                                       // 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
index 862e0a82d020a963ba7e836b7daf9c95f3b02f8c..796cb4f83b905317a9c12229c1cd5cc691ac8a38 100644 (file)
@@ -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/FieldPosition.java b/runtime/org.argeo.slc.support.gis/src/main/java/org/argeo/slc/gis/model/FieldPosition.java
new file mode 100644 (file)
index 0000000..540c534
--- /dev/null
@@ -0,0 +1,50 @@
+package org.argeo.slc.gis.model;
+
+import java.util.Date;
+
+import com.vividsolutions.jts.geom.Point;
+
+public class FieldPosition {
+       private Point location;
+       private Date timestamp;
+       private String comment;
+
+       public FieldPosition() {
+       }
+
+       public FieldPosition(Point location) {
+               this.location = location;
+               this.timestamp = new Date();
+       }
+
+       public FieldPosition(Point location, Date timestamp, String comment) {
+               this.location = location;
+               this.timestamp = timestamp;
+               this.comment = comment;
+       }
+
+       public Point getLocation() {
+               return location;
+       }
+
+       public void setLocation(Point location) {
+               this.location = location;
+       }
+
+       public Date getTimestamp() {
+               return timestamp;
+       }
+
+       public void setTimestamp(Date timestamp) {
+               this.timestamp = timestamp;
+       }
+
+       public String getComment() {
+               return comment;
+       }
+
+       public void setComment(String comment) {
+               this.comment = comment;
+       }
+
+}
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/Position.java
deleted file mode 100644 (file)
index 7cc0693..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.argeo.slc.gis.model;
-
-import java.util.Date;
-
-import com.vividsolutions.jts.geom.Point;
-
-public class Position {
-       private Point location;
-       private Date timestamp;
-       private String comment;
-
-       public Position() {
-       }
-
-       public Position(Point location) {
-               this.location = location;
-               this.timestamp = new Date();
-       }
-
-       public Position(Point location, Date timestamp, String comment) {
-               this.location = location;
-               this.timestamp = timestamp;
-               this.comment = comment;
-       }
-
-       public Point getLocation() {
-               return location;
-       }
-
-       public void setLocation(Point location) {
-               this.location = location;
-       }
-
-       public Date getTimestamp() {
-               return timestamp;
-       }
-
-       public void setTimestamp(Date timestamp) {
-               this.timestamp = timestamp;
-       }
-
-       public String getComment() {
-               return comment;
-       }
-
-       public void setComment(String comment) {
-               this.comment = comment;
-       }
-
-}
index 4b0db1fd9ebaa80efc899a3d6d136135809e097a..2b17f1bd9ff8d9bfe06411ee7debbe1e82b20d29 100644 (file)
@@ -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) {
index 83aca1d845dc770348765a22c4761309604367fb..36d5d21361ffd7d3cfa8dac1919f5ddb2b5c1788 100644 (file)
@@ -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) {
index 808b71c5e943c8d35229c2ff6482ee2efea64650..a842fcd0233df3d8d1e9dc192fca7c8835c19095 100644 (file)
@@ -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();
 }