/*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001 by: EXSE, Department of Geography, University of Bonn http://www.giub.uni-bonn.de/exse/ lat/lon GmbH http://www.lat-lon.de It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/) SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite Institut de Recherche pour le D�veloppement / US-Espace mailto:seasnet@teledetection.fr 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; either version 2.1 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstr. 19 53115 Bonn Germany E-Mail: poth@lat-lon.de Klaus Greve Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: klaus.greve@uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.model.csct.ct; // OpenGIS (SEAS) dependencies import java.util.Locale; import javax.media.jai.ParameterList; import javax.media.jai.ParameterListDescriptor; import javax.media.jai.ParameterListDescriptorImpl; import javax.media.jai.ParameterListImpl; import javax.media.jai.util.Range; import org.deegree.model.csct.pt.Latitude; import org.deegree.model.csct.pt.Longitude; import org.deegree.model.csct.resources.Utilities; import org.deegree.model.csct.resources.XArray; import org.deegree.model.csct.resources.css.Resources; /** * Base class for {@link MathTransform} providers. * Instance of this class allow the creation of transform * objects from a classification name. * <br><br> * <strong>Note: this class is not part of OpenGIS specification and * may change in a future version. Do not rely strongly on it.</strong> * * @version 1.0 * @author Martin Desruisseaux */ public abstract class MathTransformProvider { /** * The zero value. */ private static final Double ZERO = new Double(0); /** * Range of positives values. Range goes * from 0 exclusive to positive infinity. */ protected static final Range POSITIVE_RANGE = new Range(Double.class, ZERO, false, null, false); /** * Range of longitude values. Range goes * from -180� to +180� inclusives. */ protected static final Range LONGITUDE_RANGE = new Range(Double.class, new Double(Longitude.MIN_VALUE), true, new Double(Longitude.MAX_VALUE), true); /** * Range of latitude values. Range goes * from -90� to +90� inclusives. */ protected static final Range LATITUDE_RANGE = new Range(Double.class, new Double(Latitude.MIN_VALUE), true, new Double(Latitude.MAX_VALUE), true); /** * Number of colunms in table {@link #properties} below. */ private static final int RECORD_LENGTH = 4; /** * A default parameter list descriptor for * map projections. This descriptor declare * <code>"semi_major"</code>, * <code>"semi_minor"</code>, * <code>"central_meridian"</code>, * <code>"latitude_of_origin"</code>, * <code>"false_easting"</code> and * <code>"false_northing"</code> parameters. */ public static final ParameterListDescriptor DEFAULT_PROJECTION_DESCRIPTOR = getDescriptor(new Object[] { "semi_major", Double.class, ParameterListDescriptor.NO_PARAMETER_DEFAULT, POSITIVE_RANGE, "semi_minor", Double.class, ParameterListDescriptor.NO_PARAMETER_DEFAULT, POSITIVE_RANGE, "central_meridian", Double.class, ZERO, LONGITUDE_RANGE, "latitude_of_origin", Double.class, ZERO, LATITUDE_RANGE, "false_easting", Double.class, ZERO, null, "false_northing", Double.class, ZERO, null, "scale_factor", Double.class, ZERO, null }); /** * The set parameters to use for {@link ParameterListDescriptor} construction, * or <code>null</code> if the descriptor is already constructed. */ private Object[] properties; /** * The parameter list descriptor. This object will * be constructed only the first time it is needed. */ private ParameterListDescriptor descriptor; /** * The classification name. This name do * not contains leading or trailing blanks. */ private final String classification; /** * Resources key for a human readable name. This * is used for {@link #getName} implementation. */ private final int nameKey; /** * Construct a new provider. * * @param classification The classification name. * @param inherit The parameter list descriptor to inherit from, or <code>null</code> * if there is none. All parameter descriptions from <code>inherit</code> will * be copied into this newly created <code>MathTransformProvider</code>. For * map projections, this argument may be {@link #DEFAULT_PROJECTION_DESCRIPTOR}. * Subclasses may add or change parameters in their constructor by invoking * {@link #put}. */ protected MathTransformProvider(final String classification, final ParameterListDescriptor inherit) {this(classification, -1, inherit);} /** * Construct a new provider. * * @param classification The classification name. * @param nameKey Resources key for a human readable name. * This is used for {@link #getName} implementation. * @param inherit The parameter list descriptor to inherit from, or <code>null</code> * if there is none. All parameter descriptions from <code>inherit</code> will * be copied into this newly created <code>MathTransformProvider</code>. For * map projections, this argument may be {@link #DEFAULT_PROJECTION_DESCRIPTOR}. * Subclasses may add or change parameters in their constructor by invoking * {@link #put}. */ MathTransformProvider(final String classification, final int nameKey, final ParameterListDescriptor inherit) { this.classification = classification.trim(); this.nameKey = nameKey; if (inherit!=null) { final String[] names = inherit.getParamNames(); final Class [] classes = inherit.getParamClasses(); final Object[] defaults = inherit.getParamDefaults(); properties = new Object[names.length*RECORD_LENGTH]; for (int i=0; i<names.length; i++) { final int j=i*RECORD_LENGTH; properties[j+0] = names [i]; properties[j+1] = classes [i]; properties[j+2] = defaults[i]; properties[j+3] = inherit.getParamValueRange(names[i]); } } else properties = new Object[0]; } /** * Adds or changes a parameter to this math transform provider. If this <code>MathTransformProvider</code> * has been constructed with {@link #DEFAULT_PROJECTION_DESCRIPTOR} as argument, then default values * are already provided for "semi_major", "semi_minor", "central_meridian" and "latitude_of_origin". * Subclasses may call this method in their constructor for adding or changing parameters. * * @param parameter The parameter name. * @param defaultValue The default value for this parameter, or {@link Double#NaN} if there is none. * @param range The range of legal values. May be one of the predefined constants * ({@link #POSITIVE_RANGE}, {@link #LONGITUDE_RANGE}, {@link #LATITUDE_RANGE}) * or any other {@link Range} object. May be <code>null</code> if all values * are valid for this parameter. * @throws IllegalStateException If {@link #getParameterList} has already been invoked prior to this call. */ protected final void put(final String parameter, final double defaultValue, final Range range) throws IllegalStateException {put(parameter, Double.class, wrap(defaultValue), range);} /** * Adds or changes an integer parameter to this math transform provider. * Support of integer values help to make the API clearer, but the true * OpenGIS's parameter class support only <code>double</code> values. * This is why this method is not yet public. Current SEAGIS version use * integer parameters only for matrix dimension and for a custom parameter * in geocentric transform. We hope the user will barely notice it... * * @param parameter The parameter name. * @param defaultValue The default value for this parameter. * @param range The range of legal values. This is up to the caller to * build is own range with integer values (predefined ranges * like {@link #POSITIVE_RANGE} will not work). * * @throws IllegalStateException If {@link #getParameterList} * has already been invoked prior to this call. */ final void putInt(final String parameter, final int defaultValue, final Range range) throws IllegalStateException {put(parameter, Integer.class, new Integer(defaultValue), range);} /** * Adds or changes a parameter to this math transform provider. * * @param parameter The parameter name. * @param type The parameter type. * @param defaultValue The default value for this parameter. * @param range The range of legal values. * * @throws IllegalStateException If {@link #getParameterList} * has already been invoked prior to this call. */ private synchronized void put(String parameter, final Class type, Object defaultValue, final Range range) throws IllegalStateException { if (properties==null) { // Construction is finished. throw new IllegalStateException(); } if (defaultValue!=null && range!=null) { // Slight optimization for reducing the amount of objects in the heap. Object check; if (defaultValue.equals(check=range.getMinValue())) defaultValue=check; if (defaultValue.equals(check=range.getMaxValue())) defaultValue=check; } parameter = parameter.trim(); final int end = properties.length; for (int i=0; i<end; i+=RECORD_LENGTH) { if (parameter.equalsIgnoreCase(properties[i].toString())) { properties[i+0] = parameter; properties[i+1] = type; properties[i+2] = defaultValue; properties[i+3] = range; return; } } properties = XArray.resize(properties, end+RECORD_LENGTH); properties[end+0] = parameter; properties[end+1] = type; properties[end+2] = defaultValue; properties[end+3] = range; } /** * Wrap the specified double value in an object. */ private static Object wrap(final double value) { if (Double.isNaN(value)) return ParameterListDescriptor.NO_PARAMETER_DEFAULT; if (value == Latitude.MIN_VALUE) return LATITUDE_RANGE.getMinValue(); if (value == Latitude.MAX_VALUE) return LATITUDE_RANGE.getMaxValue(); if (value == Longitude.MIN_VALUE) return LONGITUDE_RANGE.getMinValue(); if (value == Longitude.MAX_VALUE) return LONGITUDE_RANGE.getMaxValue(); if (value == 0) return ZERO; return new Double(value); } /** * Returns the parameter list descriptor for the specified properties list. */ private static ParameterListDescriptor getDescriptor(final Object[] properties) { final String[] names = new String[properties.length/RECORD_LENGTH]; final Class [] classes = new Class [names.length]; final Object[] defaults = new Object[names.length]; final Range [] ranges = new Range [names.length]; for (int i=0; i<names.length; i++) { final int j = i*RECORD_LENGTH; names [i] = (String)properties[j+0]; classes [i] = (Class)properties[j+1]; defaults[i] = properties[j+2]; ranges [i] = (Range)properties[j+3]; } return new ParameterListDescriptorImpl(null, names, classes, defaults, ranges); } /** * Returns the classification name. */ public String getClassName() {return classification;} /** * Returns a human readable name localized for the specified locale. * If no name is available for the specified locale, this method may * returns a name in an arbitrary locale. */ public String getName(final Locale locale) {return (nameKey>=0) ? Resources.getResources(locale).getString(nameKey) : getClassName();} /** * Returns the parameter list descriptor. */ final synchronized ParameterListDescriptor getParameterListDescriptor() { if (descriptor==null) { descriptor = getDescriptor(properties); properties = null; // No longer needed. } return descriptor; } /** * Returns a newly created parameter list. The set of parameter * depend of the transform this provider is for. Parameters may * have default values and a range of validity. */ public ParameterList getParameterList() {return new ParameterListImpl(getParameterListDescriptor());} /** * Returns a transform for the specified parameters. * * @param parameters The parameter values in standard units. * @return A {@link MathTransform} object of this classification. */ public abstract MathTransform create(final ParameterList parameters); /** * Returns a string representation for this provider. */ public String toString() {return Utilities.getShortClassName(this)+'['+getName(null)+']';} }