sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 03/04: Enable parallel execution of isoline computation in JavaFX viewer.
Date Fri, 22 Jan 2021 23:43:05 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

commit cfd13790296f4501a6c5e1f27ef17112cd965e24
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sat Jan 23 00:34:47 2021 +0100

    Enable parallel execution of isoline computation in JavaFX viewer.
---
 .../apache/sis/gui/coverage/CoverageCanvas.java    | 15 ++++---
 .../apache/sis/gui/coverage/IsolineRenderer.java   | 51 ++++++++++++++++++----
 .../org/apache/sis/gui/coverage/RenderingData.java | 11 +++--
 3 files changed, 59 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 c2ae8f6..949c2ae 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
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.EnumMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.concurrent.Future;
 import java.util.function.Function;
 import java.io.IOException;
 import java.awt.Graphics2D;
@@ -67,6 +68,7 @@ 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.portrayal.RenderException;
+import org.apache.sis.internal.processing.image.Isolines;
 import org.apache.sis.internal.gui.BackgroundThreads;
 import org.apache.sis.internal.gui.GUIUtilities;
 import org.apache.sis.internal.gui.LogHandler;
@@ -657,7 +659,7 @@ public class CoverageCanvas extends MapCanvasAWT {
          */
         @Override
         @SuppressWarnings("PointlessBitwiseExpression")
-        protected void render() throws TransformException {
+        protected void render() throws Exception {
             final Long id = LogHandler.loadingStart(originator);
             try {
                 /*
@@ -697,12 +699,15 @@ public class CoverageCanvas extends MapCanvasAWT {
                         trace("render(): resampling result:%n\t%s", resampledImage);
                     }
                 }
-                prefetchedImage = data.prefetch(resampledImage, resampledToDisplay, displayBounds);
                 /*
-                 * Create isolines if requested.
+                 * Launch isolines creation if requested. We do this operation before `prefetch(…)`
+                 * because it will be executed in background threads while we process the
coverage.
+                 * We can not invoke it sooner because it needs some `resampleAndConvert(…)`
results.
                  */
-                if (isolines != null) {
-                    data.complete(isolines);
+                final Future<Isolines[]> newIsolines = data.generate(isolines);
+                prefetchedImage = data.prefetch(resampledImage, resampledToDisplay, displayBounds);
+                if (newIsolines != null) {
+                    IsolineRenderer.complete(isolines, newIsolines);
                 }
             } finally {
                 LogHandler.loadingStop(id);
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/IsolineRenderer.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/IsolineRenderer.java
index 12116c6..ebb3e83 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/IsolineRenderer.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/IsolineRenderer.java
@@ -22,6 +22,8 @@ import java.util.List;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Arrays;
+import java.util.concurrent.Future;
+import java.util.concurrent.ExecutionException;
 import java.awt.Shape;
 import java.awt.Color;
 import java.awt.Graphics2D;
@@ -265,11 +267,11 @@ final class IsolineRenderer {
     }
 
     /**
-     * Prepares a list of isolines to draw for all bands, initially populated with shapes
that are already available.
+     * Prepares a list of isolines to draw for each bands, initially populated with shapes
that are already available.
      * This method shall be invoked in JavaFX thread for having consistent information. The
snapshots returned by this
      * method will be completed and used in a background thread.
      *
-     * @return snapshots of information about isolines in all bands, or {@code null} if none.
+     * @return snapshots of information about isolines in each bands, or {@code null} if
none.
      */
     final Snapshot[] prepare() {
         assert Platform.isFxApplicationThread();
@@ -287,17 +289,18 @@ final class IsolineRenderer {
     /**
      * Continues isoline preparation by computing the missing Java2D shapes.
      * This method shall be invoked in a background thread. After this call,
+     * {@link #complete(Snapshot[], Future)} needs to be invoked before
      * isolines can be painted with {@link Snapshot#paint(Graphics2D, Rectangle2D)}.
      *
      * @param  snapshots  value of {@link #prepare()}. Shall not be {@code null}.
      * @param  data       the source of data. Used only if there is new isolines to compute.
      * @param  gridToCRS  transform from pixel coordinates to geometry coordinates, or {@code
null} if none.
      *                    Integer source coordinates are located at pixel centers.
-     * @return the {@code snapshots} array, potentially with less elements.
+     * @return result of isolines generation, or {@code null} if there is no isoline to compute.
      * @throws TransformException if an interpolated point can not be transformed using the
given transform.
      */
     @SuppressWarnings("UseOfSystemOutOrSystemErr")      // Used only for debugging.
-    static Snapshot[] complete(final Snapshot[] snapshots, final RenderedImage data, final
MathTransform gridToCRS)
+    static Future<Isolines[]> generate(final Snapshot[] snapshots, final RenderedImage
data, final MathTransform gridToCRS)
             throws TransformException
     {
         assert !Platform.isFxApplicationThread();
@@ -331,12 +334,31 @@ final class IsolineRenderer {
                     System.out.printf("\tFor band %d: %s%n", i, Arrays.toString(levels[i]));
                 }
             }
-            final Isolines[] isolines = Isolines.generate(data, levels, gridToCRS);
-            for (int i=0; i<numViews; i++) {
-                snapshots[i].complete(isolines[i]);
-            }
+            return Isolines.parallelGenerate(data, levels, gridToCRS);
+        }
+        return null;
+    }
+
+    /**
+     * Waits for completion of isolines generation if not already finished, then stores the
result.
+     * The {@code isolines} argument is the {@link #generate(Snapshot[], RenderedImage, MathTransform)}
+     * return value. Caller shall verify that {@code snapshots} is non-null.
+     *
+     * @param  snapshots    where to store the result of isoline computations.
+     * @param  newIsolines  the result of isolines generation, or {@code null} if none.
+     */
+    static void complete(final Snapshot[] snapshots, final Future<Isolines[]> newIsolines)
+            throws ExecutionException, InterruptedException
+    {
+        final Isolines[] isolines = newIsolines.get();
+        final int n = Math.min(snapshots.length, isolines.length);
+        int i;
+        for (i=0; i<n; i++) {
+            snapshots[i].complete(isolines[i]);
+        }
+        while (i < snapshots.length) {              // Clear remaining snapshots if any.
+            snapshots[i++].clear();
         }
-        return ArraysExt.resize(snapshots, numViews);
     }
 
     /**
@@ -403,6 +425,17 @@ final class IsolineRenderer {
         }
 
         /**
+         * Removes all isolines.
+         */
+        private void clear() {
+            isolines.clear();
+            missingLevels.clear();
+            newIsolines = null;
+            Arrays.fill(shapes, null);
+            count = 0;
+        }
+
+        /**
          * Adds an isoline level. This method shall be invoked in JavaFX thread.
          *
          * @param  value  the level value.
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/RenderingData.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/RenderingData.java
index 7dfb293..6e08f03 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/RenderingData.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/RenderingData.java
@@ -19,6 +19,7 @@ package org.apache.sis.gui.coverage;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.Future;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.awt.Graphics2D;
@@ -48,6 +49,7 @@ import org.apache.sis.image.ImageProcessor;
 import org.apache.sis.internal.coverage.j2d.ColorModelType;
 import org.apache.sis.internal.coverage.j2d.ImageUtilities;
 import org.apache.sis.internal.referencing.WraparoundApplicator;
+import org.apache.sis.internal.processing.image.Isolines;
 import org.apache.sis.internal.system.Modules;
 import org.apache.sis.io.TableAppender;
 import org.apache.sis.math.Statistics;
@@ -560,14 +562,15 @@ final class RenderingData implements Cloneable {
      * This method shall be invoked in a background thread after image rendering has been
completed (because this
      * method uses some image computation results).
      *
-     * @param  isolines  value of {@link IsolineRenderer#prepare()}. Shall not be {@code
null}.
-     * @return the {@code isolines} array, potentially with less elements.
+     * @param  isolines  value of {@link IsolineRenderer#prepare()}, or {@code null} if none.
+     * @return result of isolines generation, or {@code null} if there is no isoline to compute.
      * @throws TransformException if an interpolated point can not be transformed using the
given transform.
      */
-    final IsolineRenderer.Snapshot[] complete(final IsolineRenderer.Snapshot[] isolines)
throws TransformException {
+    final Future<Isolines[]> generate(final IsolineRenderer.Snapshot[] isolines) throws
TransformException {
+        if (isolines == null) return null;
         final MathTransform centerToObjective = PixelTranslation.translate(
                 cornerToObjective, PixelInCell.CELL_CORNER, PixelInCell.CELL_CENTER);
-        return IsolineRenderer.complete(isolines, data, centerToObjective);
+        return IsolineRenderer.generate(isolines, data, centerToObjective);
     }
 
     /**


Mime
View raw message