You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2020/06/15 17:31:11 UTC
[sis] 05/05: Take axis directions in account when computing the
initial "objective to CRS". This change fixes the image flipping.
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 0265dc639a6b3c0a54a95f78b16212d8ffdab7f9
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Mon Jun 15 18:15:06 2020 +0200
Take axis directions in account when computing the initial "objective to CRS".
This change fixes the image flipping.
---
.../apache/sis/gui/coverage/CoverageCanvas.java | 14 ++++--
.../java/org/apache/sis/gui/map/MapCanvas.java | 56 ++++++++++++++++++----
.../java/org/apache/sis/image/ImageProcessor.java | 10 ++--
3 files changed, 62 insertions(+), 18 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 1ddcbe2..a3ff962 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
@@ -471,8 +471,11 @@ public class CoverageCanvas extends MapCanvasAWT {
* This update is applied by {@link #cacheRenderingData(Worker)}.
*/
final void setOperation(final ImageOperation selection) {
- data.selectedDerivative = data.selectedDerivative.setOperation(selection);
- requestRepaint();
+ final ImageDerivative sd = data.selectedDerivative;
+ data.selectedDerivative = sd.setOperation(selection);
+ if (data.selectedDerivative != sd) {
+ requestRepaint();
+ }
}
/**
@@ -480,8 +483,11 @@ public class CoverageCanvas extends MapCanvasAWT {
* The sample values are assumed the same; only the image appearance is modified.
*/
final void setStyling(final Stretching selection) {
- data.selectedDerivative = data.selectedDerivative.setStyling(selection);
- requestRepaint();
+ final ImageDerivative sd = data.selectedDerivative;
+ data.selectedDerivative = sd.setStyling(selection);
+ if (data.selectedDerivative != sd) {
+ requestRepaint();
+ }
}
/**
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java
index 1d26b16..9ba1b84 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java
@@ -17,6 +17,7 @@
package org.apache.sis.gui.map;
import java.util.Locale;
+import java.util.Arrays;
import java.util.Objects;
import java.awt.geom.AffineTransform;
import javafx.geometry.Bounds;
@@ -41,6 +42,7 @@ import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Affine;
import javafx.scene.transform.NonInvertibleTransformException;
import org.opengis.geometry.Envelope;
+import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.TransformException;
@@ -48,15 +50,18 @@ import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.referencing.operation.matrix.MatrixSIS;
import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.apache.sis.referencing.operation.transform.LinearTransform;
+import org.apache.sis.referencing.cs.CoordinateSystems;
import org.apache.sis.geometry.Envelope2D;
import org.apache.sis.geometry.ImmutableEnvelope;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.internal.util.Numerics;
import org.apache.sis.internal.system.Modules;
import org.apache.sis.internal.gui.BackgroundThreads;
+import org.apache.sis.internal.referencing.AxisDirections;
import org.apache.sis.portrayal.PlanarCanvas;
import org.apache.sis.portrayal.RenderException;
@@ -519,6 +524,30 @@ public abstract class MapCanvas extends PlanarCanvas {
}
/**
+ * Given axis directions in the objective CRS, returns axis directions in display CRS.
+ * This method will typically reverse the North direction to a South direction because
+ * <var>y</var> axis is oriented toward down. It may also swap axis order.
+ *
+ * <p>The rules implemented in this method are empirical and may be augmented in any future version.
+ * This method may become {@code protected} if a future version if we want to allow user to override
+ * with her own rules.</p>
+ *
+ * @param srcAxes axis directions in objective CRS.
+ * @return axis directions in display CRS.
+ */
+ private static AxisDirection[] toDisplayDirections(final AxisDirection[] srcAxes) {
+ final AxisDirection[] dstAxes = Arrays.copyOf(srcAxes, 2);
+ if (AxisDirections.absolute(dstAxes[0]) == AxisDirection.NORTH &&
+ AxisDirections.absolute(dstAxes[1]) == AxisDirection.EAST)
+ {
+ ArraysExt.swap(dstAxes, 0, 1);
+ }
+ if (AxisDirections.absolute(dstAxes[0]) == AxisDirection.WEST) dstAxes[0] = AxisDirection.EAST;
+ if (AxisDirections.absolute(dstAxes[1]) == AxisDirection.NORTH) dstAxes[1] = AxisDirection.SOUTH;
+ return dstAxes;
+ }
+
+ /**
* Invoked in JavaFX thread for creating a renderer to be executed in a background thread.
* Subclasses shall copy in this method all {@code MapCanvas} properties that the background thread
* will need for performing the rendering process.
@@ -691,23 +720,34 @@ public abstract class MapCanvas extends PlanarCanvas {
final GridExtent extent = new GridExtent(null,
new long[] {Math.round(target.getMinX()), Math.round(target.getMinY())},
new long[] {Math.round(target.getMaxX()), Math.round(target.getMaxY())}, false);
-
+ /*
+ * If `setObjectiveBounds(…)` has been invoked (as it should be), initialize the affine
+ * transform to values which will allow this canvas to contain fully the objective bounds.
+ * Otherwise the transform is initialized to an identity transform (should not happen often).
+ * If a CRS is present, it is used for deciding if we need to swap or flip axes.
+ */
+ CoordinateReferenceSystem objectiveCRS;
final LinearTransform crsToDisplay;
- CoordinateReferenceSystem crs;
if (objectiveBounds != null) {
- final MatrixSIS m = Matrices.createTransform(objectiveBounds, target);
+ objectiveCRS = objectiveBounds.getCoordinateReferenceSystem();
+ final MatrixSIS m;
+ if (objectiveCRS != null) {
+ AxisDirection[] srcAxes = CoordinateSystems.getAxisDirections(objectiveCRS.getCoordinateSystem());
+ m = Matrices.createTransform(objectiveBounds, srcAxes, target, toDisplayDirections(srcAxes));
+ } else {
+ m = Matrices.createTransform(objectiveBounds, target);
+ }
Matrices.forceUniformScale(m, 0, new double[] {target.getCenterX(), target.getCenterY()});
crsToDisplay = MathTransforms.linear(m);
- crs = objectiveBounds.getCoordinateReferenceSystem();
- if (crs == null) {
- crs = extent.toEnvelope(crsToDisplay.inverse()).getCoordinateReferenceSystem();
+ if (objectiveCRS == null) {
+ objectiveCRS = extent.toEnvelope(crsToDisplay.inverse()).getCoordinateReferenceSystem();
// CRS computed above should not be null.
}
} else {
+ objectiveCRS = getDisplayCRS();
crsToDisplay = MathTransforms.identity(BIDIMENSIONAL);
- crs = getDisplayCRS();
}
- setGridGeometry(new GridGeometry(extent, PixelInCell.CELL_CORNER, crsToDisplay.inverse(), crs));
+ setGridGeometry(new GridGeometry(extent, PixelInCell.CELL_CORNER, crsToDisplay.inverse(), objectiveCRS));
transform.setToIdentity();
}
} catch (TransformException | RenderException ex) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/ImageProcessor.java b/core/sis-feature/src/main/java/org/apache/sis/image/ImageProcessor.java
index 72a1bee..1d374b9 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/ImageProcessor.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/ImageProcessor.java
@@ -600,16 +600,14 @@ public class ImageProcessor implements Cloneable {
}
}
}
- resampled = new ResampledImage(source, bounds, toSource, interpolation,
- (float) getPositionalAccuracy(Units.PIXEL), fillValues);
+ resampled = unique(new ResampledImage(source, bounds, toSource, interpolation,
+ (float) getPositionalAccuracy(Units.PIXEL), fillValues));
break;
}
if (cm != null && !cm.equals(resampled.getColorModel())) {
- resampled = new RecoloredImage(resampled, cm);
- } else if (!(resampled instanceof ResampledImage)) {
- return resampled; // Do not cache user-provided image.
+ resampled = unique(new RecoloredImage(resampled, cm));
}
- return unique(resampled);
+ return resampled; // Do not cache user-provided image.
}
/**