java.lang.Object
org.apache.sis.internal.processing.isoline.Isolines

public final class Isolines extends Object
Creates isolines at specified levels from grid values provided in a RenderedImage. Isolines are created by calls to the generate(…) static method.
Since:
1.1
Version:
1.3
See Also:
  • Field Details

    • levels

      private final Tracer.Level[] levels
      Isoline data for each level, sorted in ascending order of Tracer.Level.value.
    • LISTENER

      @Debug private static final BiConsumer<String,Isolines> LISTENER
      A consumer to notify about the current state of isoline generation, or null if none. This is used for debugging purposes only. This field is temporarily set to a non-null value when using StepsViewer (in test package) for following an isoline generation step by step.
  • Constructor Details

    • Isolines

      private Isolines(Tracer tracer, int band, double[] values, int width)
      Creates an initially empty set of isolines for the given levels. The given values array should be one of the arrays validated by cloneAndSort(double[][]).
  • Method Details

    • cloneAndSort

      private static double[][] cloneAndSort(double[][] levels)
      Ensures that the given arrays are sorted and contains no NaN value.
    • setMaskBit

      private void setMaskBit(double value, int bit)
      Sets the specified bit on Tracer.Level.isDataAbove for all levels lower than given value.

      How strict equalities are handled

      Sample values exactly equal to the isoline value are handled as if they were greater. It does not matter for interpolations: we could flip this convention randomly, the interpolated points would still the same. However, it could change the way line segments are assembled in a single polyline, but the algorithm stay consistent if we always apply the same rule for all points.

      How NaN values are handled

      Double.NaN sample values are considered higher than any level values. The algorithm does not need special attention for those values; bit patterns will be computed in a consistent way, and interpolations will produce NaN values and append them to polylines like real values. Those NaN values will be filtered out in the final stage, when copying coordinates in Path2D objects.
      Parameters:
      value - a sample values from the image.
      bit - 1, 2, 4 or 8.
      See Also:
    • generate

      public static Isolines[] generate(RenderedImage data, double[][] levels, org.opengis.referencing.operation.MathTransform gridToCRS) throws org.opengis.referencing.operation.TransformException
      Generates isolines at the specified levels computed from data provided by the given image. Isolines will be created for every bands in the given image. This method performs all computation sequentially in current thread.
      Parameters:
      data - image providing source values.
      levels - values for which to compute isolines. An array should be provided for each band. If there is more bands than levels.length, the last array is reused for all remaining bands.
      gridToCRS - transform from pixel coordinates to geometry coordinates, or null if none. Integer source coordinates are located at pixel centers.
      Returns:
      the isolines for each band in the given image.
      Throws:
      org.opengis.referencing.operation.TransformException - if an interpolated point cannot be transformed using the given transform.
    • parallelGenerate

      public static Future<Isolines[]> parallelGenerate(RenderedImage data, double[][] levels, org.opengis.referencing.operation.MathTransform gridToCRS)
      Generates isolines in background using an arbitrary number of processors. This method returns immediately (i.e. the current thread is not used for isoline computation). The result will become available at a later time in the Future object.
      Parameters:
      data - image providing source values.
      levels - values for which to compute isolines. An array should be provided for each band. If there is more bands than levels.length, the last array is reused for all remaining bands.
      gridToCRS - transform from pixel coordinates to geometry coordinates, or null if none. Integer source coordinates are located at pixel centers.
      Returns:
      a Future representing pending completion of isoline computation.
    • merge

      static void merge(Isolines[] isolines, Isolines[] neighbor) throws org.opengis.referencing.operation.TransformException
      Merges results of two partial computations (tiles). This is invoked only in multi-threaded isoline computation. The isolines instances are modified in-place. The neighbor instances can be discarded after the merge.
      Parameters:
      isolines - the first set of isolines to merge.
      neighbor - another set of isolines close to the first set.
      Throws:
      org.opengis.referencing.operation.TransformException
      See Also:
    • iterators

      static PixelIterator.Builder iterators()
      Returns a provider of PixelIterator suitable to isoline computations. It is critical that iterators use SequenceType.LINEAR iterator order.
    • flush

      static Isolines[] flush(Isolines[] isolines) throws org.opengis.referencing.operation.TransformException
      Creates all polylines that were still pending. This method should be the very last step, when all other computations finished. Pending polylines are sequences of points not yet stored in geometry objects because they were waiting to see if additional points would close them as polygons. This flush() method is invoked when we know that it will not be the case because there are no more points to add.
      Parameters:
      isolines - the isolines for which to write pending polylines.
      Returns:
      the isolines array, returned for convenience.
      Throws:
      org.opengis.referencing.operation.TransformException - if an error occurred during polylines creation.
    • generate

      static Isolines[] generate(PixelIterator iterator, double[][] levels, org.opengis.referencing.operation.MathTransform gridToCRS) throws org.opengis.referencing.operation.TransformException
      Generates isolines for the specified levels in the region traversed by the given iterator. This is the implementation of generate(RenderedImage, double[][], MathTransform) but potentially on a sub-region for parallel "fork-join" execution.
      Throws:
      org.opengis.referencing.operation.TransformException
    • polylines

      public final NavigableMap<Double,Shape> polylines()
      Returns the polylines for each level specified to the generate(…) method.
      Returns:
      the polylines for each level.
    • toArray

      static NavigableMap<Double,Shape>[] toArray(Isolines[] isolines)
      Returns the isolines for each band, then for each values in the band.
      Parameters:
      isolines - result of generate(…) or parallelGenerate(…) method call.
      Returns:
      isoline shapes for each values in each band.
    • toList

      public static List<NavigableMap<Double,Shape>> toList(Isolines[] isolines)
      Returns the isolines for each band, then for each values in the band.
      Parameters:
      isolines - result of generate(…) or parallelGenerate(…) method call.
      Returns:
      isoline shapes for each values in each band.
    • toList

      public static List<NavigableMap<Double,Shape>> toList(Future<Isolines[]> isolines)
      Returns deferred isolines for each band, then for each values in the band. The Future result is requested the first time that List.get(int) is invoked.
      Parameters:
      isolines - result of generate(…) or parallelGenerate(…) method call.
      Returns:
      isoline shapes for each values in each band.
    • toRawPath

      @Debug final Map<PolylineStage,Path2D> toRawPath()
      Returns the pixel coordinates of all level, for debugging purposes only. The
      invalid reference
      #gridToCRS
      transform is not applied by this method. For avoiding confusing behavior, that transform should be null.
      Returns:
      the pixel coordinates.