001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2004, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.referencing.operation;
018:
019: // J2SE dependencies and extensions
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025: import javax.units.Unit;
026:
027: // OpenGIS dependencies
028: import org.opengis.metadata.citation.Citation;
029: import org.opengis.parameter.GeneralParameterDescriptor;
030: import org.opengis.parameter.GeneralParameterValue;
031: import org.opengis.parameter.InvalidParameterCardinalityException;
032: import org.opengis.parameter.InvalidParameterNameException;
033: import org.opengis.parameter.InvalidParameterValueException;
034: import org.opengis.parameter.ParameterDescriptor;
035: import org.opengis.parameter.ParameterDescriptorGroup;
036: import org.opengis.parameter.ParameterNotFoundException;
037: import org.opengis.parameter.ParameterValue;
038: import org.opengis.parameter.ParameterValueGroup;
039: import org.opengis.referencing.FactoryException;
040: import org.opengis.referencing.IdentifiedObject;
041: import org.opengis.referencing.ReferenceIdentifier;
042: import org.opengis.referencing.operation.MathTransform;
043: import org.opengis.referencing.operation.OperationMethod;
044: import org.opengis.referencing.operation.Operation;
045: import org.opengis.referencing.operation.Projection;
046: import org.opengis.util.GenericName;
047:
048: // Geotools dependencies
049: import org.geotools.metadata.iso.citation.Citations;
050: import org.geotools.parameter.DefaultParameterDescriptor;
051: import org.geotools.parameter.DefaultParameterDescriptorGroup;
052: import org.geotools.resources.Utilities;
053: import org.geotools.resources.XArray;
054: import org.geotools.resources.i18n.Errors;
055: import org.geotools.resources.i18n.ErrorKeys;
056: import org.geotools.referencing.wkt.Formatter;
057: import org.geotools.referencing.operation.transform.MathTransformProxy;
058:
059: /**
060: * An {@linkplain DefaultOperationMethod operation method} capable to creates a
061: * {@linkplain MathTransform math transform} from set of
062: * {@linkplain GeneralParameterValue parameter values}.
063: * Implementations of this class should be listed in the following file:
064: *
065: * <blockquote>
066: * <P>{@code META-INF/services/org.geotools.referencing.operation.MathTransformProvider}</P>
067: * </blockquote>
068: * <P>
069: * The {@linkplain DefaultMathTransformFactory math transform factory} will parse this file in order
070: * to gets all available providers on a system. If this file is bundle in many JAR files, the
071: * {@linkplain DefaultCoordinateOperationFactory math transform factory} will read all of them.
072: *
073: * @since 2.0
074: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/MathTransformProvider.java $
075: * @version $Id: MathTransformProvider.java 25262 2007-04-23 21:11:16Z desruisseaux $
076: * @author Martin Desruisseaux
077: */
078: public abstract class MathTransformProvider extends
079: DefaultOperationMethod {
080: /**
081: * Serial number for interoperability with different versions.
082: */
083: private static final long serialVersionUID = 7530475536803158473L;
084:
085: /**
086: * Constructs a math transform provider from a set of parameters. The provider
087: * {@linkplain #getIdentifiers identifiers} will be the same than the parameter
088: * ones.
089: *
090: * @param sourceDimensions Number of dimensions in the source CRS of this operation method.
091: * @param targetDimensions Number of dimensions in the target CRS of this operation method.
092: * @param parameters The set of parameters (never {@code null}).
093: */
094: public MathTransformProvider(final int sourceDimensions,
095: final int targetDimensions,
096: final ParameterDescriptorGroup parameters) {
097: this (toMap(parameters), sourceDimensions, targetDimensions,
098: parameters);
099: }
100:
101: /**
102: * Constructs a math transform provider from a set of properties.
103: * The properties map is given unchanged to the
104: * {@linkplain DefaultOperationMethod#DefaultOperationMethod(Map,int,int,ParameterDescriptorGroup)
105: * super-class constructor}.
106: *
107: * @param properties Set of properties. Should contains at least <code>"name"</code>.
108: * @param sourceDimensions Number of dimensions in the source CRS of this operation method.
109: * @param targetDimensions Number of dimensions in the target CRS of this operation method.
110: * @param parameters The set of parameters (never {@code null}).
111: */
112: public MathTransformProvider(final Map properties,
113: final int sourceDimensions, final int targetDimensions,
114: final ParameterDescriptorGroup parameters) {
115: super (properties, sourceDimensions, targetDimensions,
116: parameters);
117: }
118:
119: /**
120: * Work around for RFE #4093999 in Sun's bug database
121: * ("Relax constraint on placement of this()/super() call in constructors").
122: */
123: private static Map toMap(final IdentifiedObject parameters) {
124: ensureNonNull("parameters", parameters);
125: final Map properties = new HashMap(4);
126: properties.put(NAME_KEY, parameters.getName());
127: properties.put(IDENTIFIERS_KEY, parameters.getIdentifiers()
128: .toArray(EMPTY_IDENTIFIER_ARRAY));
129: properties.put(ALIAS_KEY, parameters.getAlias().toArray(
130: EMPTY_ALIAS_ARRAY));
131: return properties;
132: }
133:
134: /**
135: * Returns the operation type. It may be
136: * <code>{@linkplain org.opengis.referencing.operation.Operation}.class</code>,
137: * <code>{@linkplain org.opengis.referencing.operation.Conversion}.class</code>,
138: * <code>{@linkplain org.opengis.referencing.operation.Projection}.class</code>,
139: * <cite>etc</cite>.
140: *
141: * The default implementation returns {@code Operation.class}.
142: * Subclass should overrides this methods and returns the appropriate
143: * OpenGIS interface type (<strong>not</strong> the implementation type).
144: */
145: public Class getOperationType() {
146: return Operation.class;
147: }
148:
149: /**
150: * Creates a math transform from the specified group of parameter values.
151: * Subclasses can implements this method as in the example below:
152: *
153: * <blockquote><pre>
154: * double semiMajor = values.parameter("semi_major").doubleValue(SI.METER);
155: * double semiMinor = values.parameter("semi_minor").doubleValue(SI.METER);
156: * // etc...
157: * return new MyTransform(semiMajor, semiMinor, ...);
158: * </pre></blockquote>
159: *
160: * @param values The group of parameter values.
161: * @return The created math transform.
162: * @throws InvalidParameterNameException if the values contains an unknow parameter.
163: * @throws ParameterNotFoundException if a required parameter was not found.
164: * @throws InvalidParameterValueException if a parameter has an invalid value.
165: * @throws FactoryException if the math transform can't be created for some other reason
166: * (for example a required file was not found).
167: *
168: * @see MathTransformProvider.Delegate
169: */
170: protected abstract MathTransform createMathTransform(
171: ParameterValueGroup values)
172: throws InvalidParameterNameException,
173: ParameterNotFoundException, InvalidParameterValueException,
174: FactoryException;
175:
176: /**
177: * Constructs a parameter descriptor from a set of alias. The parameter is
178: * identified by codes provided by one or more authorities. Common authorities are
179: * {@link Citations#OGC OGC} and {@link Citations#EPSG EPSG} for example.
180: *
181: * <P>The first entry in the {@code identifiers} array is both the
182: * {@linkplain ParameterDescriptor#getName main name} and the
183: * {@linkplain ParameterDescriptor#getIdentifiers identifiers}.
184: * All others are {@linkplain ParameterDescriptor#getAlias aliases}.</P>
185: *
186: * @param identifiers The parameter identifiers. Most contains at least one entry.
187: * @param defaultValue The default value for the parameter, or {@link Double#NaN} if none.
188: * @param minimum The minimum parameter value, or {@link Double#NEGATIVE_INFINITY} if none.
189: * @param maximum The maximum parameter value, or {@link Double#POSITIVE_INFINITY} if none.
190: * @param unit The unit for default, minimum and maximum values.
191: */
192: protected static ParameterDescriptor createDescriptor(
193: final ReferenceIdentifier[] identifiers,
194: final double defaultValue, final double minimum,
195: final double maximum, final Unit unit) {
196: return new DefaultParameterDescriptor(toMap(identifiers),
197: defaultValue, minimum, maximum, unit, true);
198: }
199:
200: /**
201: * Constructs an optional parameter descriptor from a set of alias.
202: * The parameter is identified as with {@link #createDescriptor}.
203: *
204: * @param identifiers The parameter identifiers. Most contains at least one entry.
205: * @param minimum The minimum parameter value, or {@link Double#NEGATIVE_INFINITY} if none.
206: * @param maximum The maximum parameter value, or {@link Double#POSITIVE_INFINITY} if none.
207: * @param unit The unit for default, minimum and maximum values.
208: */
209: protected static ParameterDescriptor createOptionalDescriptor(
210: final ReferenceIdentifier[] identifiers,
211: final double minimum, final double maximum, final Unit unit) {
212: return new DefaultParameterDescriptor(toMap(identifiers),
213: Double.NaN, minimum, maximum, unit, false);
214: }
215:
216: /**
217: * Constructs a parameter group from a set of alias. The parameter group is
218: * identified by codes provided by one or more authorities. Common authorities are
219: * {@link Citations#OGC OGC} and {@link Citations#EPSG EPSG} for example.
220: * <P>
221: * Special rules:
222: * <ul>
223: * <li>The first entry in the {@code identifiers} array is the
224: * {@linkplain ParameterDescriptorGroup#getName primary name}.</li>
225: * <li>If a an entry do not implements the {@link GenericName} interface, it is
226: * an {@linkplain ParameterDescriptorGroup#getIdentifiers identifiers}.</li>
227: * <li>All others are {@linkplain ParameterDescriptorGroup#getAlias aliases}.</li>
228: * </ul>
229: *
230: * @param identifiers The operation identifiers. Most contains at least one entry.
231: * @param parameters The set of parameters, or {@code null} or an empty array if none.
232: */
233: protected static ParameterDescriptorGroup createDescriptorGroup(
234: final ReferenceIdentifier[] identifiers,
235: final GeneralParameterDescriptor[] parameters) {
236: return new DefaultParameterDescriptorGroup(toMap(identifiers),
237: parameters);
238: }
239:
240: /**
241: * Put the identifiers into a properties map suitable for {@link IdentifiedObject}
242: * constructor.
243: */
244: private static Map toMap(final ReferenceIdentifier[] identifiers) {
245: ensureNonNull("identifiers", identifiers);
246: if (identifiers.length == 0) {
247: throw new IllegalArgumentException(Errors
248: .format(ErrorKeys.EMPTY_ARRAY));
249: }
250: int idCount = 0;
251: int aliasCount = 0;
252: ReferenceIdentifier[] id = new ReferenceIdentifier[identifiers.length];
253: GenericName[] alias = new GenericName[identifiers.length];
254: for (int i = 0; i < identifiers.length; i++) {
255: final ReferenceIdentifier candidate = identifiers[i];
256: if (candidate instanceof GenericName) {
257: alias[aliasCount++] = (GenericName) candidate;
258: } else {
259: id[idCount++] = candidate;
260: }
261: }
262: id = (ReferenceIdentifier[]) XArray.resize(id, idCount);
263: alias = (GenericName[]) XArray.resize(alias, aliasCount);
264: final Map properties = new HashMap(4, 0.8f);
265: properties.put(NAME_KEY, identifiers[0]);
266: properties.put(IDENTIFIERS_KEY, id);
267: properties.put(ALIAS_KEY, alias);
268: return properties;
269: }
270:
271: /**
272: * Ensures that the given set of parameters contains only valid values.
273: * This method compares all parameter names against the names declared in the
274: * {@linkplain #getParameters operation method parameter descriptor}. If an unknow
275: * parameter name is found, then an {@link InvalidParameterNameException} is thrown.
276: * This method also ensures that all values are assignable to the
277: * {@linkplain ParameterDescriptor#getValueClass expected class}, are between the
278: * {@linkplain ParameterDescriptor#getMinimumValue minimum} and
279: * {@linkplain ParameterDescriptor#getMaximumValue maximum} values and are one of the
280: * {@linkplain ParameterDescriptor#getValidValues set of valid values}.
281: * If the value fails any of those tests, then an
282: * {@link InvalidParameterValueException} is thrown.
283: *
284: * @param values The parameters values to check.
285: * @return The parameter values to use for {@linkplain MathTransform math transform}
286: * construction. May be different than the supplied {@code values}
287: * argument if some missing values needed to be filled with default values.
288: * @throws InvalidParameterNameException if a parameter name is unknow.
289: * @throws InvalidParameterValueException if a parameter has an invalid value.
290: */
291: protected ParameterValueGroup ensureValidValues(
292: final ParameterValueGroup values)
293: throws InvalidParameterNameException,
294: InvalidParameterValueException {
295: final ParameterDescriptorGroup parameters = getParameters();
296: final GeneralParameterDescriptor descriptor = values
297: .getDescriptor();
298: if (parameters.equals(descriptor)) {
299: /*
300: * Since the "official" parameter descriptor was used, the descriptor should
301: * have already enforced argument validity. Consequently, there is no need to
302: * performs the check and we will avoid it as a performance enhancement.
303: */
304: return values;
305: }
306: /*
307: * Copy the all values from the user-supplied group to the provider-supplied group.
308: * The provider group should performs all needed checks. Furthermore, it is suppliers
309: * responsability to know about alias (e.g. OGC, EPSG, ESRI), while the user will
310: * probably use the name from only one authority. With a copy, we gives a chances to
311: * the provider-supplied parameters to uses its alias for understanding the user
312: * parameter names.
313: */
314: final ParameterValueGroup copy = (ParameterValueGroup) parameters
315: .createValue();
316: copy(values, copy);
317: return copy;
318: }
319:
320: /**
321: * Implementation of {@code ensureValidValues}, to be invoked recursively
322: * if the specified values contains sub-groups of values. This method copy all
323: * values from the user-supplied parameter values into the provider-supplied
324: * one. The provider one should understand alias, and performs name conversion
325: * as well as argument checking on the fly.
326: *
327: * @param values The parameters values to copy.
328: * @param copy The parameters values where to put the copy.
329: * @throws InvalidParameterNameException if a parameter name is unknow.
330: * @throws InvalidParameterValueException if a parameter has an invalid value.
331: */
332: private static void copy(final ParameterValueGroup values,
333: final ParameterValueGroup copy)
334: throws InvalidParameterNameException,
335: InvalidParameterValueException {
336: for (final Iterator it = values.values().iterator(); it
337: .hasNext();) {
338: final GeneralParameterValue value = (GeneralParameterValue) it
339: .next();
340: final String name = value.getDescriptor().getName()
341: .getCode();
342: if (value instanceof ParameterValueGroup) {
343: /*
344: * Contains sub-group - invokes 'copy' recursively.
345: */
346: final GeneralParameterDescriptor descriptor;
347: descriptor = ((ParameterDescriptorGroup) copy
348: .getDescriptor()).descriptor(name);
349: if (descriptor instanceof ParameterDescriptorGroup) {
350: final ParameterValueGroup groups = (ParameterValueGroup) descriptor
351: .createValue();
352: copy((ParameterValueGroup) value, groups);
353: values.groups(name).add(groups);
354: continue;
355: } else {
356: throw new InvalidParameterNameException(Errors
357: .format(ErrorKeys.UNEXPECTED_PARAMETER_$1,
358: name), name);
359: }
360: }
361: /*
362: * Single parameter - copy the value, with special care for value with units.
363: */
364: final ParameterValue source = (ParameterValue) value;
365: final ParameterValue target;
366: try {
367: target = copy.parameter(name);
368: } catch (ParameterNotFoundException cause) {
369: final InvalidParameterNameException exception = new InvalidParameterNameException(
370: Errors
371: .format(
372: ErrorKeys.UNEXPECTED_PARAMETER_$1,
373: name), name);
374: exception.initCause(cause);
375: throw exception;
376: }
377: final Object v = source.getValue();
378: final Unit unit = source.getUnit();
379: if (unit == null) {
380: target.setValue(v);
381: } else if (v instanceof Number) {
382: target.setValue(((Number) v).doubleValue(), unit);
383: } else if (v instanceof double[]) {
384: target.setValue((double[]) v, unit);
385: } else {
386: throw new InvalidParameterValueException(Errors.format(
387: ErrorKeys.ILLEGAL_ARGUMENT_$2, name, v), name,
388: v);
389: }
390: }
391: }
392:
393: /**
394: * Returns the parameter value for the specified operation parameter.
395: * This convenience method is used by subclasses for initializing
396: * {@linkplain MathTransform math transform} from a set of parameters.
397: *
398: * @param param The parameter to look for.
399: * @param group The parameter value group to search into.
400: * @return The requested parameter value.
401: * @throws ParameterNotFoundException if the parameter is not found.
402: */
403: private static ParameterValue getParameter(
404: final ParameterDescriptor param,
405: final ParameterValueGroup group)
406: throws ParameterNotFoundException {
407: /*
408: * Search for an identifier matching the group's authority, if any.
409: * This is needed if the parameter values group was created from an
410: * EPSG database for example: we need to use the EPSG names instead
411: * of the OGC ones.
412: */
413: String name = getName(param, group.getDescriptor().getName()
414: .getAuthority());
415: if (name == null) {
416: name = param.getName().getCode();
417: }
418: if (param.getMinimumOccurs() != 0) {
419: return group.parameter(name);
420: }
421: /*
422: * The parameter is optional. We don't want to invokes 'parameter(name)', because we don't
423: * want to create a new parameter is the user didn't supplied one. Search the parameter
424: * ourself (so we don't create any), and returns null if we don't find any.
425: *
426: * TODO: A simplier solution would be to add a 'isDefined' method in GeoAPI,
427: * or something similar.
428: */
429: final GeneralParameterDescriptor search;
430: search = ((ParameterDescriptorGroup) group.getDescriptor())
431: .descriptor(name);
432: if (search instanceof ParameterDescriptor) {
433: for (final Iterator it = group.values().iterator(); it
434: .hasNext();) {
435: final GeneralParameterValue candidate = (GeneralParameterValue) it
436: .next();
437: if (search.equals(candidate.getDescriptor())) {
438: return (ParameterValue) candidate;
439: }
440: }
441: }
442: return null;
443: }
444:
445: /**
446: * Returns the parameter value for the specified operation parameter.
447: * This convenience method is used by subclasses for initializing
448: * {@linkplain MathTransform math transform} from a set of parameters.
449: *
450: * @param param The parameter to look for.
451: * @param group The parameter value group to search into.
452: * @return The requested parameter value, or {@code null} if {@code param} is
453: * {@linkplain #createOptionalDescriptor optional} and the user didn't
454: * provided any value.
455: * @throws ParameterNotFoundException if the parameter is not found.
456: *
457: * @todo Move to the {@link org.geotools.parameter.Parameters} class.
458: */
459: protected static Object value(final ParameterDescriptor param,
460: final ParameterValueGroup group)
461: throws ParameterNotFoundException {
462: final ParameterValue value = getParameter(param, group);
463: return (value != null) ? value.getValue() : null;
464: }
465:
466: /**
467: * Returns the parameter value for the specified operation parameter.
468: * This convenience method is used by subclasses for initializing
469: * {@linkplain MathTransform math transform} from a set of parameters.
470: *
471: * @param param The parameter to look for.
472: * @param group The parameter value group to search into.
473: * @return The requested parameter value, or {@code null} if {@code param} is
474: * {@linkplain #createOptionalDescriptor optional} and the user didn't
475: * provided any value.
476: * @throws ParameterNotFoundException if the parameter is not found.
477: *
478: * @todo Move to the {@link org.geotools.parameter.Parameters} class.
479: */
480: protected static String stringValue(
481: final ParameterDescriptor param,
482: final ParameterValueGroup group)
483: throws ParameterNotFoundException {
484: final ParameterValue value = getParameter(param, group);
485: return (value != null) ? value.stringValue() : null;
486: }
487:
488: /**
489: * Returns the parameter value for the specified operation parameter.
490: * This convenience method is used by subclasses for initializing
491: * {@linkplain MathTransform math transform} from a set of parameters.
492: *
493: * @param param The parameter to look for.
494: * @param group The parameter value group to search into.
495: * @return The requested parameter value, or {@code 0} if {@code param} is
496: * {@linkplain #createOptionalDescriptor optional} and the user didn't
497: * provided any value.
498: * @throws ParameterNotFoundException if the parameter is not found.
499: *
500: * @todo Move to the {@link org.geotools.parameter.Parameters} class.
501: */
502: protected static int intValue(final ParameterDescriptor param,
503: final ParameterValueGroup group)
504: throws ParameterNotFoundException {
505: final ParameterValue value = getParameter(param, group);
506: return (value != null) ? value.intValue() : 0;
507: }
508:
509: /**
510: * Returns the parameter value for the specified operation parameter.
511: * Values are automatically converted into the standard units specified
512: * by the supplied {@code param} argument.
513: * This convenience method is used by subclasses for initializing
514: * {@linkplain MathTransform math transform} from a set of parameters.
515: *
516: * @param param The parameter to look for.
517: * @param group The parameter value group to search into.
518: * @return The requested parameter value, or {@code NaN} if {@code param} is
519: * {@linkplain #createOptionalDescriptor optional} and the user didn't
520: * provided any value.
521: * @throws ParameterNotFoundException if the parameter is not found.
522: *
523: * @todo Move to the {@link org.geotools.parameter.Parameters} class.
524: */
525: protected static double doubleValue(
526: final ParameterDescriptor param,
527: final ParameterValueGroup group)
528: throws ParameterNotFoundException {
529: final Unit unit = param.getUnit();
530: final ParameterValue value = getParameter(param, group);
531: return (value == null) ? Double.NaN : (unit != null) ? value
532: .doubleValue(unit) : value.doubleValue();
533: }
534:
535: /**
536: * Format the inner part of a
537: * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
538: * Known Text</cite> (WKT)</A> element.
539: *
540: * @param formatter The formatter to use.
541: * @return The WKT element name.
542: */
543: protected String formatWKT(final Formatter formatter) {
544: final Class type = getOperationType();
545: if (Projection.class.isAssignableFrom(type)) {
546: return super .formatWKT(formatter);
547: }
548: formatter.setInvalidWKT(OperationMethod.class);
549: return "OperationMethod";
550: }
551:
552: /**
553: * The result of a call to {@link MathTransformProvider#createMathTransform createMathTransform}.
554: * This class encapsulates a reference to the {@linkplain #method originating provider}
555: * as well as the {@linkplain #transform created math transform}. This information is needed
556: * when a provider delegates the work to an other provider according the parameter values.
557: * For example a generic instance of
558: * {@link org.geotools.referencing.operation.transform.ProjectiveTransform.ProviderAffine
559: * ProviderAffine} may delegates the creation of an <cite>affine transform</cite> to an other
560: * {@code ProviderAffine} instance with <cite>source</cite> and <cite>target</cite> dimensions
561: * matching the supplied parameters, because those dimensions determine the set of legal
562: * <code>"elt_<var>j</var>_<var>i</var>"</code> parameters.
563: * <p>
564: * Most {@linkplain MathTransformProvider math transform provider} do not delegate their work
565: * to an other one, and consequently do not need this class.
566: * <p>
567: * Future Geotools version may extends this class for handling more information than just the
568: * {@linkplain #transform transform} creator. This class is more convenient than adding new
569: * methods right into {@link MathTransformProvider}, because it is sometime difficult for a
570: * provider to infer all the conditions prevaling when
571: * {@link MathTransformProvider#createMathTransform createMathTransform} was executed.
572: * Furthermore, it avoid to pollute {@code MathTransformProvider} with methods unused
573: * for the vast majority of providers.
574: *
575: * @version $Id: MathTransformProvider.java 25262 2007-04-23 21:11:16Z desruisseaux $
576: * @author Martin Desruisseaux
577: *
578: * @since 2.2
579: */
580: protected static final class Delegate extends MathTransformProxy {
581: /**
582: * The provider for the {@linkplain #transform transform}.
583: */
584: public final OperationMethod method;
585:
586: /**
587: * Encapsulates the math transform created by the specified provider.
588: */
589: public Delegate(final MathTransform transform,
590: final OperationMethod method) {
591: super (transform);
592: this .method = method;
593: ensureNonNull("transform", transform);
594: ensureNonNull("method", method);
595: }
596: }
597: }
|