Class ContourPlot.PixelConvertingSpliterator<P extends ContourPlot.PixelBase,​T>

  • Type Parameters:
    P - the pixel type of the underlying Spliterator
    T - the type of elements returned by the PixelConvertingSpliterator
    All Implemented Interfaces:
    java.util.Spliterator<T>
    Enclosing class:
    ContourPlot

    public static class ContourPlot.PixelConvertingSpliterator<P extends ContourPlot.PixelBase,​T>
    extends java.lang.Object
    implements java.util.Spliterator<T>
    The PixelConvertingSpliterator enables iterating an ContourPlot.Img with a different datatype than ContourPlot.Pixel (ContourPlot.ImgBase.spliterator()). This can come in handy if a Consumer would be easier to write when not restricted to the Pixel datatype.

    For example, a specific operation should be applied to each pixel of the Img which is specified as a function that takes a 3-dimensional vector as argument with red, green and blue component e.g.
    applyOperation(Vector3D vec){...}}
    To obtain a spliterator of the Img that will accept a Consumer<Vector3D> a PixelConvertingSpliterator can be created from an ordinary Spliterator<Pixel> providing the following functions:

    • element allocator: a function to create (allocate) an object of the desired datatype (Vector3D in this example)
    • from Pixel converter: a function to convert a Pixel object to an object of the desired datatype e.g.
      void convertPixel(Pixel px, Vector3D vec)
    • to Pixel converter: a function to convert an object of the desired datatype to a Pixel object e.g.
      void convertVector(Vector3D vec, Pixel px)

    A PixelConvertingSpliterator<Vector3D> would then be created like this:
     
     Img img=loadImgFromSomewhere();
     Spliterator<Vector3D> split = new PixelConvertingSpliterator<>(
           img.spliterator(),
           ()->{return new Vector3D();},
           MyConverter::convertPixel,
           MyConverter::convertVector
           );
     StreamSupport.stream(split, true)
           .forEach(VectorOperations::applyOperation);
     

    The reason for not simply doing an 'on the fly' conversion inside a Spliterator<Pixel> or using the Stream.map(java.util.function.Function) function is, that these methods are prone to excessive object allocation (allocating a new object for every pixel). When using the PixelConvertingSpliterator there is only one object allocation per split, and the object will be reused for each pixel within that split.

    Since:
    1.4
    Author:
    hageldave
    • Constructor Detail

      • PixelConvertingSpliterator

        public PixelConvertingSpliterator​(java.util.Spliterator<? extends P> delegate,
                                          java.util.function.Supplier<T> elementAllocator,
                                          java.util.function.BiConsumer<P,​T> fromPixelConverter,
                                          java.util.function.BiConsumer<T,​P> toPixelConverter)
        Constructs a new PixelConvertingSpliterator.
        Parameters:
        delegate - the Spliterator<Pixel> this spliterator delegates to.
        elementAllocator - method for allocating an object of this spliterator's element type.
        fromPixelConverter - method for setting up an element of this spliterator according to its underlying pixel.
        toPixelConverter - method for adopting an underlying pixel value according to an element of this spliterator.
        Since:
        1.4
    • Method Detail

      • tryAdvance

        public boolean tryAdvance​(java.util.function.Consumer<? super T> action)
        Specified by:
        tryAdvance in interface java.util.Spliterator<P extends ContourPlot.PixelBase>
      • forEachRemaining

        public void forEachRemaining​(java.util.function.Consumer<? super T> action)
        Specified by:
        forEachRemaining in interface java.util.Spliterator<P extends ContourPlot.PixelBase>
      • trySplit

        public java.util.Spliterator<T> trySplit()
        Specified by:
        trySplit in interface java.util.Spliterator<P extends ContourPlot.PixelBase>
      • estimateSize

        public long estimateSize()
        Specified by:
        estimateSize in interface java.util.Spliterator<P extends ContourPlot.PixelBase>
      • characteristics

        public int characteristics()
        Specified by:
        characteristics in interface java.util.Spliterator<P extends ContourPlot.PixelBase>
      • getDoubletArrayElementSpliterator

        public static ContourPlot.PixelConvertingSpliterator<ContourPlot.PixelBase,​double[]> getDoubletArrayElementSpliterator​(java.util.Spliterator<? extends ContourPlot.PixelBase> pixelSpliterator)
        Example implementation of a PixelConvertingSpliterator<double[]>.

        The elements of the returned spliterator will be double[] of length 3 with normalized red, green and blue channels on index 0, 1 and 2.

        Code:

         
         Supplier<double[]> arrayAllocator = () -> {
            return new double[3];
         };
         BiConsumer<Pixel, double[]> convertToArray = (px, array) -> {
            array[0]=px.r_normalized();
            array[1]=px.g_normalized();
            array[2]=px.b_normalized();
         };
         BiConsumer<double[], Pixel> convertToPixel = (array, px) -> {
            px.setRGB_fromNormalized_preserveAlpha(
               // clamp values between zero and one
               Math.min(1, Math.max(0, array[0])),
               Math.min(1, Math.max(0, array[1])),
               Math.min(1, Math.max(0, array[2])));
         };
         PixelConvertingSpliterator<double[]> arraySpliterator = new PixelConvertingSpliterator<>(
            pixelSpliterator,
            arrayAllocator,
            convertToArray,
            convertToPixel);
         
         
        Parameters:
        pixelSpliterator - the Spliterator<Pixel> to which the returned spliterator delegates to.
        Returns:
        a spliterator with float[] elements consisting of normalized RGB channels.
        Since:
        1.4