Package org.geotools.coverage.grid

Source Code of org.geotools.coverage.grid.LookupTableFactory

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2003-2008, Open Source Geospatial Foundation (OSGeo)
*
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation;
*    version 2.1 of the License.
*
*    This library is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*    Lesser General Public License for more details.
*/
package org.geotools.coverage.grid;

import java.awt.image.DataBuffer;
import java.util.Arrays;
import java.util.Map;
import javax.media.jai.LookupTableJAI;
import static java.lang.Math.*;

import org.opengis.referencing.operation.MathTransform1D;
import org.opengis.referencing.operation.TransformException;
import org.geotools.util.WeakValueHashMap;


/**
* A factory for {@link LookupTableJAI} objects built from an array of {@link MathTransform1D}.
* This factory is used internally by {@link GridCoverageViews#create}.
*
* @since 2.1
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (IRD)
*/
final class LookupTableFactory {
    /**
     * The pool of {@link LookupTableJAI} objects already created.
     */
    private static final Map<LookupTableFactory,LookupTableJAI> pool =
            new WeakValueHashMap<LookupTableFactory,LookupTableJAI>();

    /**
     * The source data type. Should be one of {@link DataBuffer} constants.
     */
    private final int sourceType;

    /**
     * The target data type. Should be one of {@link DataBuffer} constants.
     */
    private final int targetType;

    /**
     * The math transforms for this key.
     */
    private final MathTransform1D[] transforms;

    /**
     * Create a new objet to use as a key in the {@link #pool}.
     *
     * @param sourceType The source data type. Should be one of {@link DataBuffer} constants.
     * @param targetType The target data type. Should be one of {@link DataBuffer} constants.
     * @param transforms The math transforms to apply.
     */
    private LookupTableFactory(final int sourceType,
                               final int targetType,
                               final MathTransform1D[] transforms)
    {
        this.sourceType = sourceType;
        this.targetType = targetType;
        this.transforms = transforms;
    }

    /**
     * Gets a lookup factory
     *
     * @param  sourceType The source data type. Should be one of {@link DataBuffer} constants.
     * @param  targetType The target data type. Should be one of {@link DataBuffer} constants.
     * @param  transforms The math transforms to apply.
     * @return The lookup table, or {@code null} if this method can't build a lookup
     *         table for the supplied parameters.
     * @throws TransformException if a transformation failed.
     */
    public static LookupTableJAI create(final int sourceType,
                                        final int targetType,
                                        final MathTransform1D[] transforms)
            throws TransformException
    {
        /*
         * Argument check. Null values are legal but can't be processed by this method.
         */
      final int nbands = transforms.length;
        for (int i=0; i<nbands; i++) {
            if (transforms[i] == null) {
                return null;
            }
        }
        synchronized (pool) {
            /*
             * Checks if a table is already available in the cache. Since tables may be 64 kb big,
             * sharing tables may save a significant amount of memory if there is many images.
             */
            final LookupTableFactory key = new LookupTableFactory(sourceType, targetType, transforms);
            LookupTableJAI table = pool.get(key);
            if (table != null) {
                return table;
            }
            /*
             * Computes the table's size according the source datatype. For datatype 'short' (signed
             * or unsigned), we will create the table only if the target datatype is 'byte' in order
             * to avoid to use too much memory for the table. The memory consumed for a table from
             * source datatype 'short' to target datatype 'byte' is 64 ko.
             */
            final int length;
            final int offset;
            switch (sourceType) {
                default: {
                    return null;
                }
                case DataBuffer.TYPE_BYTE: {
                    length = 0x100;
                    offset = 0;
                    break;
                }
                case DataBuffer.TYPE_SHORT:
                case DataBuffer.TYPE_USHORT: {
                    if (targetType != DataBuffer.TYPE_BYTE) {
                        // Avoid to use too much memory for the table.
                        return null;
                    }
                    length = 0x10000;
                    offset = (sourceType == DataBuffer.TYPE_SHORT) ? Short.MIN_VALUE : 0;
                    break;
                }
            }
            /*
             * Builds the table according the target datatype.
             */
            switch (targetType) {
                default: {
                    return null;
                }
                case DataBuffer.TYPE_DOUBLE: {
                    final double[][]  data = new double[nbands][];
                    final double[]  buffer = new double[length];
                    for (int i=length; --i>=0;) {
                        buffer[i] = i;
                    }
                    for (int i=nbands; --i>=0;) {
                        final double[] array = (i==0) ? buffer : buffer.clone();
                        transforms[i].transform(array, 0, array, 0, array.length);
                        data[i] = array;
                    }
                    table = new LookupTableJAI(data, offset);
                    break;
                }
                case DataBuffer.TYPE_FLOAT: {
                    final float[][]  data = new float[nbands][];
                    final float[]  buffer = new float[length];
                    for (int i=length; --i>=0;) {
                        buffer[i] = i;
                    }
                    for (int i=transforms.length; --i>=0;) {
                        final float[] array = (i == 0) ? buffer : buffer.clone();
                        transforms[i].transform(array, 0, array, 0, length);
                        data[i] = array;
                    }
                    table = new LookupTableJAI(data, offset);
                    break;
                }
                case DataBuffer.TYPE_INT: {
                    final int[][] data = new int[nbands][];
                    for (int i=nbands; --i>=0;) {
                        final MathTransform1D tr = transforms[i];
                        final int[] array = new int[length];
                        for (int j=length; --j>=0;) {
                            array[j] = (int) min(max(round(tr.transform(j+offset)),
                                    Integer.MIN_VALUE), Integer.MAX_VALUE);
                        }
                        data[i] = array;
                    }
                    table = new LookupTableJAI(data, offset);
                    break;
                }
                case DataBuffer.TYPE_SHORT:
                case DataBuffer.TYPE_USHORT: {
                    final int minimum, maximum;
                    if (targetType == DataBuffer.TYPE_SHORT) {
                        minimum = Short.MIN_VALUE;
                        maximum = Short.MAX_VALUE;
                    } else {
                        minimum = 0;
                        maximum = 0xFFFF;
                    }
                    final short[][] data = new short[nbands][];
                    for (int i=nbands; --i>=0;) {
                        final MathTransform1D tr = transforms[i];
                        final short[] array = new short[length];
                        for (int j=length; --j>=0;) {
                            array[j] = (short) min(max(round(tr.transform(j+offset)), minimum), maximum);
                        }
                        data[i] = array;
                    }
                    table = new LookupTableJAI(data, offset, minimum!=0);
                    break;
                }
                case DataBuffer.TYPE_BYTE: {
                    final byte[][] data = new byte[nbands][];
                    for (int i=nbands; --i>=0;) {
                        final MathTransform1D tr = transforms[i];
                        final byte[] array = new byte[length];
                        for (int j=length; --j>=0;) {
                            array[j] = (byte) min(max(round(tr.transform(j+offset)), 0), 0xFF);
                        }
                        data[i] = array;
                    }
                    table = new LookupTableJAI(data, offset);
                    break;
                }
            }
            pool.put(key, table);
            return table;
        }
    }

    /**
     * Returns a hash code value for this key. This is for internal use by
     * {@code LookupTableFactory} and is public only as an implementation side effect.
     */
    @Override
    public int hashCode() {
        int code = sourceType + 37*targetType;
        code += Arrays.hashCode(transforms);
        return code;
    }

    /**
     * Compares the specified object with this key for equality. This is for internal use by
     * {@code LookupTableFactory} and is public only as an implementation side effect.
     */
    @Override
    public boolean equals(final Object other) {
        if (other instanceof LookupTableFactory) {
            final LookupTableFactory that = (LookupTableFactory) other;
            return this.sourceType == that.sourceType &&
                   this.targetType == that.targetType &&
                   Arrays.equals(this.transforms, that.transforms);
        }
        return false;
    }
}
TOP

Related Classes of org.geotools.coverage.grid.LookupTableFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.