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
commit b4543619f15551bb5b6921caa6271b1015af47b5 Author: Martin Desruisseaux <[email protected]> AuthorDate: Mon Jun 20 12:08:27 2022 +0200 Use the mouse position as the point where change in target canvas should be the same (in "real world" units) as the change in source canvas. --- .../org/apache/sis/gui/map/GestureFollower.java | 41 +++++++++++++++++++--- .../org/apache/sis/portrayal/CanvasFollower.java | 38 +++++++++++++++----- .../org/apache/sis/geometry/DirectPosition2D.java | 14 +++++++- .../transform/ConcatenatedTransform2D.java | 2 +- .../transform/PassThroughTransform2D.java | 2 +- 5 files changed, 82 insertions(+), 15 deletions(-) diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/GestureFollower.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/GestureFollower.java index b5744dba25..ea294276ef 100644 --- a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/GestureFollower.java +++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/GestureFollower.java @@ -19,6 +19,7 @@ package org.apache.sis.gui.map; import java.awt.geom.Point2D; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; +import java.util.Optional; import java.util.logging.Logger; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; @@ -98,6 +99,12 @@ public class GestureFollower extends CanvasFollower implements EventHandler<Mous */ public final BooleanProperty cursorEnabled; + /** + * Whether the {@link #cursorSourcePosition} is valid. + * If {@code true}, then {@link #cursor} shall be non-null and should be visible. + */ + private boolean cursorSourceValid; + /** * Cursor position of the mouse over source canvas, expressed in coordinates of the source and target canvas. */ @@ -125,8 +132,8 @@ public class GestureFollower extends CanvasFollower implements EventHandler<Mous public GestureFollower(final MapCanvas source, final MapCanvas target) { super(source, target); super.setDisabled(true); - cursorSourcePosition = new Point2D.Double(Double.NaN, Double.NaN); - cursorTargetPosition = new Point2D.Double(Double.NaN, Double.NaN); + cursorSourcePosition = new Point2D.Double(); + cursorTargetPosition = new Point2D.Double(); transformEnabled = new SimpleBooleanProperty(this, "transformEnabled"); cursorEnabled = new SimpleBooleanProperty(this, "cursorEnabled"); transformEnabled.addListener((p,o,n) -> setDisabled(!n)); @@ -156,7 +163,9 @@ public class GestureFollower extends CanvasFollower implements EventHandler<Mous pane.addEventHandler(MouseEvent.MOUSE_EXITED, this); pane.addEventHandler(MouseEvent.MOUSE_MOVED, this); pane.addEventHandler(MouseEvent.MOUSE_DRAGGED, this); + cursorSourceValid = true; } else { + cursorSourceValid = false; pane.removeEventHandler(MouseEvent.MOUSE_ENTERED, this); pane.removeEventHandler(MouseEvent.MOUSE_EXITED, this); pane.removeEventHandler(MouseEvent.MOUSE_MOVED, this); @@ -167,6 +176,26 @@ public class GestureFollower extends CanvasFollower implements EventHandler<Mous } } + /** + * Returns the position for the mouse cursor in the source canvas if that position is known. + * This information is used when the source and target canvases do not use the same CRS. + * {@code GestureFollower} tries to transform the canvas views in such a way that the + * "real world" change is the same for both canvas at that location. + * + * <p>The returned value is "live"; it may change with mouse and gesture events. + * Callers should not modify that value, and copy it if they need to keep it.</p> + * + * @return mouse position in source canvas where displacements, zooms and rotations + * applied on the source canvas should be mirrored exactly on the target canvas. + */ + @Override + public Optional<Point2D> getSourceDisplayPOI() { + if (cursorSourceValid) { + return Optional.of(cursorSourcePosition); + } + return super.getSourceDisplayPOI(); + } + /** * Invoked when the mouse position changed. This method should be invoked only if * {@link #cursorEnabled} is {@code true} (this is not verified by this method). @@ -177,6 +206,7 @@ public class GestureFollower extends CanvasFollower implements EventHandler<Mous public void handle(final MouseEvent event) { cursorSourcePosition.x = event.getX(); cursorSourcePosition.y = event.getY(); + cursorSourceValid = true; final EventType<? extends MouseEvent> type = event.getEventType(); if (type == MouseEvent.MOUSE_MOVED) { updateCursorPosition(); @@ -199,8 +229,9 @@ public class GestureFollower extends CanvasFollower implements EventHandler<Mous cursor.setTranslateX(p.getX()); cursor.setTranslateY(p.getY()); } catch (TransformException e) { - Logging.recoverableException(Logger.getLogger(Modules.APPLICATION), GestureFollower.class, "handle", e); + cursorSourceValid = false; cursor.setVisible(false); + Logging.recoverableException(Logger.getLogger(Modules.APPLICATION), GestureFollower.class, "handle", e); } } @@ -231,9 +262,10 @@ public class GestureFollower extends CanvasFollower implements EventHandler<Mous @Override protected void transformedSource(final TransformChangeEvent event) { super.transformedSource(event); - if (cursor != null) { + if (cursorSourceValid) { final AffineTransform change = event.getDisplayChange2D().orElse(null); if (change == null) { + cursorSourceValid = false; cursor.setVisible(false); } else if (event.getReason() != TransformChangeEvent.Reason.INTERIM) { change.transform(cursorSourcePosition, cursorSourcePosition); @@ -242,6 +274,7 @@ public class GestureFollower extends CanvasFollower implements EventHandler<Mous change.inverseTransform(cursorSourcePosition, cursorSourcePosition); updateCursorPosition(); } catch (NoninvertibleTransformException e) { + cursorSourceValid = false; cursor.setVisible(false); } } diff --git a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasFollower.java b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasFollower.java index c8c0880d31..ffae15f06c 100644 --- a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasFollower.java +++ b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasFollower.java @@ -18,6 +18,7 @@ package org.apache.sis.portrayal; import java.util.Optional; import java.util.logging.Logger; +import java.awt.geom.Point2D; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; import java.beans.PropertyChangeEvent; @@ -34,6 +35,7 @@ import org.apache.sis.util.Disposable; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.NullArgumentException; import org.apache.sis.util.logging.Logging; +import org.apache.sis.geometry.DirectPosition2D; import org.apache.sis.internal.system.Modules; import org.apache.sis.internal.referencing.j2d.AffineTransform2D; import org.apache.sis.referencing.operation.matrix.AffineTransforms2D; @@ -246,15 +248,12 @@ public class CanvasFollower implements PropertyChangeListener, Disposable { * at that location only. At all other locations, the "real world" coordinate changes * may differ because of map projection deformations. * - * <p>The default implementation is as below. Subclasses can override this method for - * using a different point of interest, for example at the location of mouse cursor.</p> + * <p>The default implementation computes the value from {@link #getSourceDisplayPOI()} + * if present, or fallback on {@code source.getPointOfInterest(true)} otherwise. + * Subclasses can override this method for using a different point of interest.</p> * - * {@preformat java - * return source.getPointOfInterest(true); - * } - * - * The CRS associated to the position shall be {@link PlanarCanvas#getObjectiveCRS()}. - * For performance reason, this is not verified by this {@code CanvasFollower} class. + * <p>The CRS associated to the position shall be {@link PlanarCanvas#getObjectiveCRS()}. + * For performance reason, this is not verified by this {@code CanvasFollower} class.</p> * * @return objective coordinates in source canvas where displacements, zooms and rotations * applied on the source canvas should be mirrored exactly on the target canvas. @@ -262,9 +261,32 @@ public class CanvasFollower implements PropertyChangeListener, Disposable { * @see PlanarCanvas#getPointOfInterest(boolean) */ public DirectPosition getSourceObjectivePOI() { + final Point2D p = getSourceDisplayPOI().orElse(null); + if (p != null) try { + final DirectPosition2D poi = new DirectPosition2D(p); + source.objectiveToDisplay.inverseTransform(poi, poi); + return poi; + } catch (NoninvertibleTransformException e) { + canNotCompute("getSourceObjectivePOI", e); + } return source.getPointOfInterest(true); } + /** + * Returns the display coordinates of the Point Of Interest (POI) in source canvas. + * This method provides the same information than {@link #getSourceObjectivePOI()}, + * but in units that are more convenient for expressing the location of mouse cursor + * for example. + * + * <p>The default implementation returns an empty value.</p> + * + * @return display coordinates in source canvas where displacements, zooms and rotations + * applied on the source canvas should be mirrored exactly on the target canvas. + */ + public Optional<Point2D> getSourceDisplayPOI() { + return Optional.empty(); + } + /** * Returns the transform from source display coordinates to target display coordinates. * This transform may change every time that a zoom; translation or rotation is applied diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java index f07f7951dc..2e488f5c05 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java @@ -59,7 +59,7 @@ import static org.apache.sis.util.ArgumentChecks.ensureDimensionMatches; * Collections that do not rely on hash codes, like {@code ArrayList}, are safe in all cases.</p> * * @author Martin Desruisseaux (IRD, Geomatys) - * @version 0.3 + * @version 1.3 * * @see DirectPosition1D * @see GeneralDirectPosition @@ -96,6 +96,18 @@ public class DirectPosition2D extends Point2D.Double implements DirectPosition, this.crs = crs; } + /** + * Constructs a 2D position from the coordinates of the specified point. + * The CRS is initialized to {@code null}. + * + * @param p the point from which to copy the coordinate values. + * + * @since 1.3 + */ + public DirectPosition2D(final Point2D p) { + super(p.getX(), p.getY()); + } + /** * Constructs a 2D position from the specified coordinates. Despite their names, * the (<var>x</var>,<var>y</var>) coordinates don't need to be oriented toward diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java index 61207e1347..f7710f05de 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java @@ -100,7 +100,7 @@ final class ConcatenatedTransform2D extends ConcatenatedTransform implements Mat @Override public Matrix derivative(final Point2D point) throws TransformException { return super.derivative(point instanceof DirectPosition ? - (DirectPosition) point : new DirectPosition2D(point.getX(), point.getY())); + (DirectPosition) point : new DirectPosition2D(point)); } /** diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform2D.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform2D.java index 4915513f4d..cbec22f28b 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform2D.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform2D.java @@ -89,7 +89,7 @@ final class PassThroughTransform2D extends PassThroughTransform implements MathT @Override public Matrix derivative(final Point2D point) throws TransformException { return super.derivative(point instanceof DirectPosition ? - (DirectPosition) point : new DirectPosition2D(point.getX(), point.getY())); + (DirectPosition) point : new DirectPosition2D(point)); } /**
