001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/ct/MathTransformProvider.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/exse/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification 012 (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/) 013 SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite 014 Institut de Recherche pour le D�veloppement / US-Espace 015 mailto:seasnet@teledetection.fr 016 017 018 This library is free software; you can redistribute it and/or 019 modify it under the terms of the GNU Lesser General Public 020 License as published by the Free Software Foundation; either 021 version 2.1 of the License, or (at your option) any later version. 022 023 This library is distributed in the hope that it will be useful, 024 but WITHOUT ANY WARRANTY; without even the implied warranty of 025 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 026 Lesser General Public License for more details. 027 028 You should have received a copy of the GNU Lesser General Public 029 License along with this library; if not, write to the Free Software 030 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 031 032 Contact: 033 034 Andreas Poth 035 lat/lon GmbH 036 Aennchenstr. 19 037 53115 Bonn 038 Germany 039 E-Mail: poth@lat-lon.de 040 041 Klaus Greve 042 Department of Geography 043 University of Bonn 044 Meckenheimer Allee 166 045 53115 Bonn 046 Germany 047 E-Mail: klaus.greve@uni-bonn.de 048 049 050 ---------------------------------------------------------------------------*/ 051 package org.deegree.model.csct.ct; 052 053 // OpenGIS (SEAS) dependencies 054 import java.util.Locale; 055 056 import javax.media.jai.ParameterList; 057 import javax.media.jai.ParameterListDescriptor; 058 import javax.media.jai.ParameterListDescriptorImpl; 059 import javax.media.jai.ParameterListImpl; 060 import javax.media.jai.util.Range; 061 062 import org.deegree.model.csct.pt.Latitude; 063 import org.deegree.model.csct.pt.Longitude; 064 import org.deegree.model.csct.resources.Utilities; 065 import org.deegree.model.csct.resources.XArray; 066 import org.deegree.model.csct.resources.css.Resources; 067 068 069 070 /** 071 * Base class for {@link MathTransform} providers. 072 * Instance of this class allow the creation of transform 073 * objects from a classification name. 074 * <br><br> 075 * <strong>Note: this class is not part of OpenGIS specification and 076 * may change in a future version. Do not rely strongly on it.</strong> 077 * 078 * @version 1.0 079 * @author Martin Desruisseaux 080 */ 081 public abstract class MathTransformProvider 082 { 083 /** 084 * The zero value. 085 */ 086 private static final Double ZERO = new Double(0); 087 088 /** 089 * Range of positives values. Range goes 090 * from 0 exclusive to positive infinity. 091 */ 092 protected static final Range POSITIVE_RANGE = new Range(Double.class, ZERO, false, null, false); 093 094 /** 095 * Range of longitude values. Range goes 096 * from -180� to +180� inclusives. 097 */ 098 protected static final Range LONGITUDE_RANGE = new Range(Double.class, new Double(Longitude.MIN_VALUE), true, new Double(Longitude.MAX_VALUE), true); 099 100 /** 101 * Range of latitude values. Range goes 102 * from -90� to +90� inclusives. 103 */ 104 protected static final Range LATITUDE_RANGE = new Range(Double.class, new Double(Latitude.MIN_VALUE), true, new Double(Latitude.MAX_VALUE), true); 105 106 /** 107 * Number of colunms in table {@link #properties} below. 108 */ 109 private static final int RECORD_LENGTH = 4; 110 111 /** 112 * A default parameter list descriptor for 113 * map projections. This descriptor declare 114 * <code>"semi_major"</code>, 115 * <code>"semi_minor"</code>, 116 * <code>"central_meridian"</code>, 117 * <code>"latitude_of_origin"</code>, 118 * <code>"false_easting"</code> and 119 * <code>"false_northing"</code> parameters. 120 */ 121 public static final ParameterListDescriptor DEFAULT_PROJECTION_DESCRIPTOR = getDescriptor(new Object[] 122 { 123 "semi_major", Double.class, ParameterListDescriptor.NO_PARAMETER_DEFAULT, POSITIVE_RANGE, 124 "semi_minor", Double.class, ParameterListDescriptor.NO_PARAMETER_DEFAULT, POSITIVE_RANGE, 125 "central_meridian", Double.class, ZERO, LONGITUDE_RANGE, 126 "latitude_of_origin", Double.class, ZERO, LATITUDE_RANGE, 127 "false_easting", Double.class, ZERO, null, 128 "false_northing", Double.class, ZERO, null, 129 "scale_factor", Double.class, ZERO, null 130 }); 131 132 /** 133 * The set parameters to use for {@link ParameterListDescriptor} construction, 134 * or <code>null</code> if the descriptor is already constructed. 135 */ 136 private Object[] properties; 137 138 /** 139 * The parameter list descriptor. This object will 140 * be constructed only the first time it is needed. 141 */ 142 private ParameterListDescriptor descriptor; 143 144 /** 145 * The classification name. This name do 146 * not contains leading or trailing blanks. 147 */ 148 private final String classification; 149 150 /** 151 * Resources key for a human readable name. This 152 * is used for {@link #getName} implementation. 153 */ 154 private final int nameKey; 155 156 /** 157 * Construct a new provider. 158 * 159 * @param classification The classification name. 160 * @param inherit The parameter list descriptor to inherit from, or <code>null</code> 161 * if there is none. All parameter descriptions from <code>inherit</code> will 162 * be copied into this newly created <code>MathTransformProvider</code>. For 163 * map projections, this argument may be {@link #DEFAULT_PROJECTION_DESCRIPTOR}. 164 * Subclasses may add or change parameters in their constructor by invoking 165 * {@link #put}. 166 */ 167 protected MathTransformProvider(final String classification, final ParameterListDescriptor inherit) 168 {this(classification, -1, inherit);} 169 170 /** 171 * Construct a new provider. 172 * 173 * @param classification The classification name. 174 * @param nameKey Resources key for a human readable name. 175 * This is used for {@link #getName} implementation. 176 * @param inherit The parameter list descriptor to inherit from, or <code>null</code> 177 * if there is none. All parameter descriptions from <code>inherit</code> will 178 * be copied into this newly created <code>MathTransformProvider</code>. For 179 * map projections, this argument may be {@link #DEFAULT_PROJECTION_DESCRIPTOR}. 180 * Subclasses may add or change parameters in their constructor by invoking 181 * {@link #put}. 182 */ 183 MathTransformProvider(final String classification, final int nameKey, final ParameterListDescriptor inherit) 184 { 185 this.classification = classification.trim(); 186 this.nameKey = nameKey; 187 if (inherit!=null) 188 { 189 final String[] names = inherit.getParamNames(); 190 final Class [] classes = inherit.getParamClasses(); 191 final Object[] defaults = inherit.getParamDefaults(); 192 properties = new Object[names.length*RECORD_LENGTH]; 193 for (int i=0; i<names.length; i++) 194 { 195 final int j=i*RECORD_LENGTH; 196 properties[j+0] = names [i]; 197 properties[j+1] = classes [i]; 198 properties[j+2] = defaults[i]; 199 properties[j+3] = inherit.getParamValueRange(names[i]); 200 } 201 } 202 else properties = new Object[0]; 203 } 204 205 /** 206 * Adds or changes a parameter to this math transform provider. If this <code>MathTransformProvider</code> 207 * has been constructed with {@link #DEFAULT_PROJECTION_DESCRIPTOR} as argument, then default values 208 * are already provided for "semi_major", "semi_minor", "central_meridian" and "latitude_of_origin". 209 * Subclasses may call this method in their constructor for adding or changing parameters. 210 * 211 * @param parameter The parameter name. 212 * @param defaultValue The default value for this parameter, or {@link Double#NaN} if there is none. 213 * @param range The range of legal values. May be one of the predefined constants 214 * ({@link #POSITIVE_RANGE}, {@link #LONGITUDE_RANGE}, {@link #LATITUDE_RANGE}) 215 * or any other {@link Range} object. May be <code>null</code> if all values 216 * are valid for this parameter. 217 * @throws IllegalStateException If {@link #getParameterList} has already been invoked prior to this call. 218 */ 219 protected final void put(final String parameter, final double defaultValue, final Range range) throws IllegalStateException 220 {put(parameter, Double.class, wrap(defaultValue), range);} 221 222 /** 223 * Adds or changes an integer parameter to this math transform provider. 224 * Support of integer values help to make the API clearer, but the true 225 * OpenGIS's parameter class support only <code>double</code> values. 226 * This is why this method is not yet public. Current SEAGIS version use 227 * integer parameters only for matrix dimension and for a custom parameter 228 * in geocentric transform. We hope the user will barely notice it... 229 * 230 * @param parameter The parameter name. 231 * @param defaultValue The default value for this parameter. 232 * @param range The range of legal values. This is up to the caller to 233 * build is own range with integer values (predefined ranges 234 * like {@link #POSITIVE_RANGE} will not work). 235 * 236 * @throws IllegalStateException If {@link #getParameterList} 237 * has already been invoked prior to this call. 238 */ 239 final void putInt(final String parameter, final int defaultValue, final Range range) throws IllegalStateException 240 {put(parameter, Integer.class, new Integer(defaultValue), range);} 241 242 /** 243 * Adds or changes a parameter to this math transform provider. 244 * 245 * @param parameter The parameter name. 246 * @param type The parameter type. 247 * @param defaultValue The default value for this parameter. 248 * @param range The range of legal values. 249 * 250 * @throws IllegalStateException If {@link #getParameterList} 251 * has already been invoked prior to this call. 252 */ 253 private synchronized void put(String parameter, final Class type, Object defaultValue, final Range range) throws IllegalStateException 254 { 255 if (properties==null) 256 { 257 // Construction is finished. 258 throw new IllegalStateException(); 259 } 260 if (defaultValue!=null && range!=null) 261 { 262 // Slight optimization for reducing the amount of objects in the heap. 263 Object check; 264 if (defaultValue.equals(check=range.getMinValue())) defaultValue=check; 265 if (defaultValue.equals(check=range.getMaxValue())) defaultValue=check; 266 } 267 parameter = parameter.trim(); 268 final int end = properties.length; 269 for (int i=0; i<end; i+=RECORD_LENGTH) 270 { 271 if (parameter.equalsIgnoreCase(properties[i].toString())) 272 { 273 properties[i+0] = parameter; 274 properties[i+1] = type; 275 properties[i+2] = defaultValue; 276 properties[i+3] = range; 277 return; 278 } 279 } 280 properties = XArray.resize(properties, end+RECORD_LENGTH); 281 properties[end+0] = parameter; 282 properties[end+1] = type; 283 properties[end+2] = defaultValue; 284 properties[end+3] = range; 285 } 286 287 /** 288 * Wrap the specified double value in an object. 289 */ 290 private static Object wrap(final double value) 291 { 292 if (Double.isNaN(value)) return ParameterListDescriptor.NO_PARAMETER_DEFAULT; 293 if (value == Latitude.MIN_VALUE) return LATITUDE_RANGE.getMinValue(); 294 if (value == Latitude.MAX_VALUE) return LATITUDE_RANGE.getMaxValue(); 295 if (value == Longitude.MIN_VALUE) return LONGITUDE_RANGE.getMinValue(); 296 if (value == Longitude.MAX_VALUE) return LONGITUDE_RANGE.getMaxValue(); 297 if (value == 0) return ZERO; 298 return new Double(value); 299 } 300 301 /** 302 * Returns the parameter list descriptor for the specified properties list. 303 */ 304 private static ParameterListDescriptor getDescriptor(final Object[] properties) 305 { 306 final String[] names = new String[properties.length/RECORD_LENGTH]; 307 final Class [] classes = new Class [names.length]; 308 final Object[] defaults = new Object[names.length]; 309 final Range [] ranges = new Range [names.length]; 310 for (int i=0; i<names.length; i++) 311 { 312 final int j = i*RECORD_LENGTH; 313 names [i] = (String)properties[j+0]; 314 classes [i] = (Class)properties[j+1]; 315 defaults[i] = properties[j+2]; 316 ranges [i] = (Range)properties[j+3]; 317 } 318 return new ParameterListDescriptorImpl(null, names, classes, defaults, ranges); 319 } 320 321 /** 322 * Returns the classification name. 323 */ 324 public String getClassName() 325 {return classification;} 326 327 /** 328 * Returns a human readable name localized for the specified locale. 329 * If no name is available for the specified locale, this method may 330 * returns a name in an arbitrary locale. 331 */ 332 public String getName(final Locale locale) 333 {return (nameKey>=0) ? Resources.getResources(locale).getString(nameKey) : getClassName();} 334 335 /** 336 * Returns the parameter list descriptor. 337 */ 338 final synchronized ParameterListDescriptor getParameterListDescriptor() 339 { 340 if (descriptor==null) 341 { 342 descriptor = getDescriptor(properties); 343 properties = null; // No longer needed. 344 } 345 return descriptor; 346 } 347 348 /** 349 * Returns a newly created parameter list. The set of parameter 350 * depend of the transform this provider is for. Parameters may 351 * have default values and a range of validity. 352 */ 353 public ParameterList getParameterList() 354 {return new ParameterListImpl(getParameterListDescriptor());} 355 356 /** 357 * Returns a transform for the specified parameters. 358 * 359 * @param parameters The parameter values in standard units. 360 * @return A {@link MathTransform} object of this classification. 361 */ 362 public abstract MathTransform create(final ParameterList parameters); 363 364 /** 365 * Returns a string representation for this provider. 366 */ 367 public String toString() 368 {return Utilities.getShortClassName(this)+'['+getName(null)+']';} 369 }