sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Show positional accuracy of coordinates under cursor using the information provided by `RenderedImage` property.
Date Wed, 24 Jun 2020 22:03:57 GMT
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 3489bf2  Show positional accuracy of coordinates under cursor using the information
provided by `RenderedImage` property.
3489bf2 is described below

commit 3489bf2def889137fbcbaa25335abae9f618c12f
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Thu Jun 25 00:02:38 2020 +0200

    Show positional accuracy of coordinates under cursor using the information provided by
`RenderedImage` property.
---
 .../apache/sis/gui/coverage/CoverageCanvas.java    | 28 ++++++++++-
 .../apache/sis/gui/coverage/CoverageControls.java  |  1 +
 .../java/org/apache/sis/gui/map/StatusBar.java     | 54 +++++++++++++++++-----
 .../org/apache/sis/internal/gui/GUIUtilities.java  | 29 ++++++++++++
 .../org/apache/sis/internal/gui/PropertyView.java  | 30 ++++++++++++
 5 files changed, 129 insertions(+), 13 deletions(-)

diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java
index 5a1f136..8006a07 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java
@@ -33,6 +33,8 @@ import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ObservableValue;
 import javafx.beans.value.WritableValue;
 import javafx.concurrent.Task;
+import javax.measure.Quantity;
+import javax.measure.quantity.Length;
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.util.FactoryException;
@@ -53,9 +55,12 @@ import org.apache.sis.image.PlanarImage;
 import org.apache.sis.image.Interpolation;
 import org.apache.sis.gui.map.MapCanvas;
 import org.apache.sis.gui.map.MapCanvasAWT;
+import org.apache.sis.gui.map.StatusBar;
+import org.apache.sis.internal.gui.GUIUtilities;
 import org.apache.sis.internal.gui.Resources;
 import org.apache.sis.internal.system.Modules;
 import org.apache.sis.util.logging.Logging;
+import org.apache.sis.measure.Units;
 
 
 /**
@@ -122,11 +127,17 @@ public class CoverageCanvas extends MapCanvasAWT {
      * <p>Consider as final after {@link #createPropertyExplorer()} invocation.
      * This field may be removed in a future version if we revisit this API before making
public.</p>
      *
-     * @see #createPropertyExplorer
+     * @see #createPropertyExplorer()
      */
     private ImagePropertyExplorer imageProperty;
 
     /**
+     * The status bar associated to this {@code MapCanvas}.
+     * This is non-null only if this {@link CoverageCanvas} is used together with {@link
CoverageControls}.
+     */
+    StatusBar statusBar;
+
+    /**
      * Creates a new two-dimensional canvas for {@link RenderedImage}.
      */
     public CoverageCanvas() {
@@ -480,6 +491,21 @@ public class CoverageCanvas extends MapCanvasAWT {
         if (imageProperty != null) {
             imageProperty.setImage(worker.filteredImage, worker.getVisibleImageBounds());
         }
+        if (statusBar != null) {
+            final Object value = worker.filteredImage.getProperty(PlanarImage.POSITIONAL_ACCURACY_KEY);
+            Quantity<Length> accuracy = null;
+            if (value instanceof Quantity<?>[]) {
+                for (final Quantity<?> q : (Quantity<?>[]) value) {
+                    if (Units.isLinear(q.getUnit())) {
+                        accuracy = q.asType(Length.class);
+                        accuracy = GUIUtilities.shorter(accuracy, accuracy.getUnit().getConverterTo(Units.METRE)
+                                                                    .convert(accuracy.getValue().doubleValue()));
+                        break;
+                    }
+                }
+            }
+            statusBar.setLowestAccuracy(accuracy);
+        }
     }
 
     /**
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java
index eb46b51..05dc022 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java
@@ -86,6 +86,7 @@ final class CoverageControls extends Controls implements PropertyChangeListener
         view = new CoverageCanvas();
         view.setBackground(background);
         final StatusBar statusBar = new StatusBar(referenceSystems, view);
+        view.statusBar = statusBar;
         imageAndStatus = new BorderPane(view.getView());
         imageAndStatus.setBottom(statusBar.getView());
         /*
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java
index 5ae71fb..4e8c364 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java
@@ -48,6 +48,7 @@ import javafx.beans.property.ReadOnlyObjectPropertyBase;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
+import javax.measure.Quantity;
 import javax.measure.quantity.Length;
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.MismatchedDimensionException;
@@ -77,9 +78,9 @@ import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.gui.Widget;
 import org.apache.sis.gui.referencing.RecentReferenceSystems;
-import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.gui.BackgroundThreads;
 import org.apache.sis.internal.gui.ExceptionReporter;
+import org.apache.sis.internal.gui.GUIUtilities;
 import org.apache.sis.internal.gui.Resources;
 import org.apache.sis.internal.gui.Styles;
 import org.apache.sis.referencing.CRS;
@@ -299,6 +300,14 @@ public class StatusBar extends Widget implements EventHandler<MouseEvent>
{
     private double[] inflatePrecisions;
 
     /**
+     * The declared accuracy on ground, or {@code null} if unspecified.
+     *
+     * @see #getLowestAccuracy()
+     * @see #setLowestAccuracy(Quantity)
+     */
+    private Quantity<Length> lowestAccuracy;
+
+    /**
      * The object to use for formatting coordinate values.
      */
     private final CoordinateFormat format;
@@ -323,7 +332,7 @@ public class StatusBar extends Widget implements EventHandler<MouseEvent>
{
      * The {@link #position} text to show when the mouse is outside the canvas area.
      * This text is set to the axis abbreviations, for example "(φ, λ)".
      *
-     * @see #setFormatCRS(CoordinateReferenceSystem, Length)
+     * @see #setFormatCRS(CoordinateReferenceSystem, Quantity)
      */
     private String outsideText;
 
@@ -733,7 +742,7 @@ public class StatusBar extends Widget implements EventHandler<MouseEvent>
{
                  * The accuracy to show on the status bar, or {@code null} if none.
                  * This is computed after {@link CoordinateOperation} has been determined.
                  */
-                private Length accuracy;
+                private Quantity<Length> accuracy;
 
                 /**
                  * Invoked in a background thread for fetching transformation to target CRS.
@@ -743,12 +752,7 @@ public class StatusBar extends Widget implements EventHandler<MouseEvent>
{
                     final MathTransform value = super.call();
                     double a = CRS.getLinearAccuracy(getOperation());
                     if (a > 0) {
-                        final Unit<Length> unit;
-                        if      (a < 1)    unit = Units.CENTIMETRE;
-                        else if (a < 1000) unit = Units.METRE;
-                        else               unit = Units.KILOMETRE;
-                        a = Units.METRE.getConverterTo(unit).convert(Math.max(a, Formulas.LINEAR_TOLERANCE));
-                        accuracy = Quantities.create(a, unit);
+                        accuracy = GUIUtilities.shorter(null, a);
                     }
                     return value;
                 }
@@ -806,7 +810,7 @@ public class StatusBar extends Widget implements EventHandler<MouseEvent>
{
      * @param  finder    the completed task with the new {@link #objectiveToPositionCRS}.
      * @param  accuracy  the accuracy to show on the status bar, or {@code null} if none.
      */
-    private void setPositionCRS(final OperationFinder finder, final Length accuracy) {
+    private void setPositionCRS(final OperationFinder finder, final Quantity<Length>
accuracy) {
         setErrorMessage(null, null);
         setFormatCRS(finder.getTargetCRS(), accuracy);
         objectiveToPositionCRS = finder.getValue();
@@ -836,9 +840,9 @@ public class StatusBar extends Widget implements EventHandler<MouseEvent>
{
      *
      * @see #positionReferenceSystem
      */
-    private void setFormatCRS(final CoordinateReferenceSystem crs, final Length accuracy)
{
+    private void setFormatCRS(final CoordinateReferenceSystem crs, final Quantity<Length>
accuracy) {
         format.setDefaultCRS(crs);
-        format.setGroundAccuracy(accuracy);
+        format.setGroundAccuracy(Quantities.max(accuracy, lowestAccuracy));
         String text = IdentifiedObjects.getDisplayName(crs, getLocale());
         Tooltip tp = null;
         if (text != null) {
@@ -960,6 +964,32 @@ public class StatusBar extends Widget implements EventHandler<MouseEvent>
{
     }
 
     /**
+     * Returns the lowest value appended as "± <var>accuracy</var>" after the
coordinate values.
+     * This is the last value specified to {@link #setLowestAccuracy(Quantity)}.
+     *
+     * @return the lowest accuracy to append after the coordinate values, or {@code null}
if none.
+     *
+     * @see CoordinateFormat#getGroundAccuracy()
+     */
+    public Quantity<Length> getLowestAccuracy() {
+        return lowestAccuracy;
+    }
+
+    /**
+     * Specifies an uncertainty to append as "± <var>accuracy</var>" after the
coordinate values.
+     * If user has selected (e.g. by contextual menu) a CRS causing the use of a coordinate
transformation,
+     * then the accuracy actually shown by {@code StatusBar} will be the greatest value between
the accuracy
+     * specified to this method and the coordinate transformation accuracy.
+     *
+     * @param  accuracy  the lowest accuracy to append after the coordinate values, or {@code
null} if none.
+     *
+     * @see CoordinateFormat#setGroundAccuracy(Quantity)
+     */
+    public void setLowestAccuracy(final Quantity<Length> accuracy) {
+        lowestAccuracy = accuracy;
+    }
+
+    /**
      * Returns the coordinates given to the last call to {@link #setLocalCoordinates(double,
double)},
      * or an empty value if those coordinates are not visible.
      *
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/GUIUtilities.java
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/GUIUtilities.java
index 21c4866..eb346ef 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/GUIUtilities.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/GUIUtilities.java
@@ -29,6 +29,12 @@ import javafx.scene.control.MenuItem;
 import javafx.scene.shape.Rectangle;
 import javafx.scene.layout.Pane;
 import javafx.stage.Window;
+import javax.measure.Unit;
+import javax.measure.Quantity;
+import javax.measure.quantity.Length;
+import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.measure.Quantities;
+import org.apache.sis.measure.Units;
 import org.apache.sis.util.Static;
 
 
@@ -270,4 +276,27 @@ public final class GUIUtilities extends Static {
         lcs.addAll(   suffix);
         return lcs;
     }
+
+    /**
+     * Modify the quantity unit for showing a smaller value.
+     *
+     * @param  quantity  the quantity to modify, or {@code null}.
+     * @param  m         the quantity value in metres.
+     * @return the simplified quantity.
+     */
+    public static Quantity<Length> shorter(final Quantity<Length> quantity, double
m) {
+        final Unit<Length> unit;
+        if (m < 1) {
+            unit = Units.CENTIMETRE;
+        } else if (m < 1000) {
+            unit = Units.METRE;
+        } else {
+            unit = Units.KILOMETRE;
+        }
+        if (quantity != null && unit.equals(quantity.getUnit())) {
+            return quantity;
+        }
+        m = Units.METRE.getConverterTo(unit).convert(Math.max(m, Formulas.LINEAR_TOLERANCE));
+        return Quantities.create(m, unit);
+    }
 }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
index 50c719b..933175b 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
@@ -18,6 +18,8 @@ package org.apache.sis.internal.gui;
 
 import java.util.Locale;
 import java.util.Objects;
+import java.util.Collection;
+import java.lang.reflect.Array;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -32,6 +34,7 @@ import javafx.concurrent.Task;
 import javafx.scene.Node;
 import javafx.scene.text.Font;
 import javafx.scene.control.Label;
+import javafx.scene.control.ListView;
 import javafx.scene.control.TextArea;
 import javafx.scene.image.ImageView;
 import javafx.scene.layout.Background;
@@ -74,6 +77,12 @@ public final class PropertyView extends CompoundFormat<Object> {
     private TextArea textView;
 
     /**
+     * Shows the {@linkplain #value} as a list.
+     * This is built only when first needed.
+     */
+    private ListView<String> listView;
+
+    /**
      * Shows the {@linkplain #value} as an image.
      * This is built only when first needed.
      */
@@ -207,6 +216,10 @@ public final class PropertyView extends CompoundFormat<Object>
{
                 content = setImage((RenderedImage) newValue);
             } else if (newValue instanceof Throwable) {
                 content = setText((Throwable) newValue);
+            } else if (newValue instanceof Collection<?>) {
+                content = setList(((Collection<?>) newValue).toArray());
+            } else if (newValue.getClass().isArray()) {
+                content = setList(newValue);
             } else {
                 content = setText(formatValue(newValue));
             }
@@ -240,6 +253,23 @@ public final class PropertyView extends CompoundFormat<Object>
{
     }
 
     /**
+     * Sets the property value to the given array.
+     */
+    private Node setList(final Object array) {
+        ListView<String> node = listView;
+        if (node == null) {
+            node = new ListView<>();
+            listView = node;
+        }
+        final String[] list = new String[Array.getLength(array)];
+        for (int i=0; i<list.length; i++) {
+            list[i] = formatValue(Array.get(array, i));
+        }
+        listView.getItems().setAll(list);
+        return node;
+    }
+
+    /**
      * Sets the property value to the given image.
      */
     private Node setImage(final RenderedImage image) {


Mime
View raw message