001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2001, Institut de Recherche pour le Developpement
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: * This package contains documentation from OpenGIS specifications.
018: * OpenGIS consortium's work is fully acknowledged here.
019: */
020: package org.geotools.referencing.operation;
021:
022: // J2SE dependencies
023: import java.text.ParseException;
024: import java.util.Arrays;
025: import java.util.Collection;
026: import java.util.Collections;
027: import java.util.Iterator;
028: import java.util.Set;
029: import java.util.HashSet;
030: import java.util.TreeSet;
031:
032: // OpenGIS dependencies
033: import org.opengis.metadata.Identifier;
034: import org.opengis.metadata.citation.Citation;
035: import org.opengis.parameter.ParameterValueGroup;
036: import org.opengis.parameter.ParameterDescriptorGroup;
037: import org.opengis.referencing.FactoryException;
038: import org.opengis.referencing.NoSuchIdentifierException;
039: import org.opengis.referencing.operation.Conversion;
040: import org.opengis.referencing.operation.MathTransform;
041: import org.opengis.referencing.operation.MathTransformFactory;
042: import org.opengis.referencing.operation.Matrix;
043: import org.opengis.referencing.operation.Operation;
044: import org.opengis.referencing.operation.OperationMethod;
045: import org.opengis.referencing.operation.Projection;
046:
047: // Geotools dependencies
048: import org.geotools.metadata.iso.citation.Citations;
049: import org.geotools.factory.Hints;
050: import org.geotools.factory.FactoryRegistry;
051: import org.geotools.parameter.ParameterWriter;
052: import org.geotools.referencing.AbstractIdentifiedObject;
053: import org.geotools.referencing.factory.ReferencingFactory;
054: import org.geotools.referencing.operation.transform.ConcatenatedTransform;
055: import org.geotools.referencing.operation.transform.PassThroughTransform;
056: import org.geotools.referencing.operation.transform.ProjectiveTransform;
057: import org.geotools.referencing.wkt.MathTransformParser;
058: import org.geotools.referencing.wkt.Symbols;
059: import org.geotools.resources.Arguments;
060: import org.geotools.resources.LazySet;
061: import org.geotools.resources.i18n.Errors;
062: import org.geotools.resources.i18n.ErrorKeys;
063: import org.geotools.util.CanonicalSet;
064:
065: /**
066: * Low level factory for creating {@linkplain MathTransform math transforms}.
067: * Many high level GIS applications will never need to use this factory directly;
068: * they can use a {@linkplain DefaultCoordinateOperationFactory coordinate operation factory}
069: * instead. However, the {@code MathTransformFactory} interface can be used directly
070: * by applications that wish to transform other types of coordinates (e.g. color coordinates,
071: * or image pixel coordinates).
072: * <P>
073: * A {@linkplain MathTransform math transform} is an object that actually does
074: * the work of applying formulae to coordinate values. The math transform does
075: * not know or care how the coordinates relate to positions in the real world.
076: * This lack of semantics makes implementing {@code MathTransformFactory}
077: * significantly easier than it would be otherwise.
078: *
079: * For example the affine transform applies a matrix to the coordinates
080: * without knowing how what it is doing relates to the real world. So if
081: * the matrix scales <var>Z</var> values by a factor of 1000, then it could
082: * be converting meters into millimeters, or it could be converting kilometers
083: * into meters.
084: * <P>
085: * Because {@linkplain MathTransform math transforms} have low semantic value
086: * (but high mathematical value), programmers who do not have much knowledge
087: * of how GIS applications use coordinate systems, or how those coordinate
088: * systems relate to the real world can implement {@code MathTransformFactory}.
089: * The low semantic content of {@linkplain MathTransform math transforms} also
090: * means that they will be useful in applications that have nothing to do with
091: * GIS coordinates. For example, a math transform could be used to map color
092: * coordinates between different color spaces, such as converting (red, green, blue)
093: * colors into (hue, light, saturation) colors.
094: * <P>
095: * Since a {@linkplain MathTransform math transform} does not know what its source
096: * and target coordinate systems mean, it is not necessary or desirable for a math
097: * transform object to keep information on its source and target coordinate systems.
098: *
099: * @since 2.1
100: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/DefaultMathTransformFactory.java $
101: * @version $Id: DefaultMathTransformFactory.java 27994 2007-11-22 21:49:01Z desruisseaux $
102: * @author Martin Desruisseaux
103: *
104: * @tutorial http://docs.codehaus.org/display/GEOTOOLS/Coordinate+Transformation+Parameters
105: */
106: public class DefaultMathTransformFactory extends ReferencingFactory
107: implements MathTransformFactory {
108: /**
109: * The hints to provide to math transform providers. Null for now, but may be non-null
110: * in some future version.
111: */
112: private static final Hints HINTS = null;
113:
114: /**
115: * The object to use for parsing <cite>Well-Known Text</cite> (WKT) strings.
116: * Will be created only when first needed.
117: */
118: private transient MathTransformParser parser;
119:
120: /**
121: * The last value returned by {@link #getProvider}. Stored as an
122: * optimization since the same provider is often asked many times.
123: */
124: private transient MathTransformProvider lastProvider;
125:
126: /**
127: * The operation method for the last transform created.
128: */
129: private final ThreadLocal/*<OperationMethod>*/lastMethod = new ThreadLocal();
130:
131: /**
132: * A pool of math transform. This pool is used in order to
133: * returns instance of existing math transforms when possible.
134: */
135: private final CanonicalSet pool = new CanonicalSet();
136:
137: /**
138: * The service registry for finding {@link MathTransformProvider} implementations.
139: */
140: private final FactoryRegistry registry;
141:
142: /**
143: * Constructs a default {@link MathTransform math transform} factory.
144: */
145: public DefaultMathTransformFactory() {
146: this (new Class[] { MathTransformProvider.class });
147: }
148:
149: /**
150: * Constructs a default {@link MathTransform math transform} factory using the
151: * specified {@linkplain MathTransformProvider transform providers} categories.
152: *
153: * @param categories The providers categories, as implementations
154: * of {@link MathTransformProvider}.
155: */
156: private DefaultMathTransformFactory(final Class[] categories) {
157: registry = new FactoryRegistry(Arrays.asList(categories));
158: }
159:
160: /**
161: * Returns the vendor responsible for creating this factory implementation. Many implementations
162: * may be available for the same factory interface. The default implementation returns
163: * {@linkplain Citations#GEOTOOLS Geotools}.
164: *
165: * @return The vendor for this factory implementation.
166: */
167: public Citation getVendor() {
168: return Citations.GEOTOOLS;
169: }
170:
171: /**
172: * Returns a set of available methods for {@linkplain MathTransform math transforms}. For
173: * each element in this set, the {@linkplain OperationMethod#getName operation method name}
174: * must be known to the {@link #getDefaultParameters} method in this factory.
175: * The set of available methods is implementation dependent.
176: *
177: * @param type <code>{@linkplain Operation}.class</code> for fetching all operation methods,
178: * or <code>{@linkplain Projection}.class</code> for fetching only map projection
179: * methods.
180: * @return All {@linkplain MathTransform math transform} methods available in this factory.
181: *
182: * @see #getDefaultParameters
183: * @see #createParameterizedTransform
184: */
185: public Set/*<OperationMethod>*/getAvailableMethods(final Class type) {
186: return new LazySet(registry.getServiceProviders(
187: MathTransformProvider.class,
188: (type != null) ? new MethodFilter(type) : null, HINTS));
189: }
190:
191: /**
192: * A filter for the set of available operations.
193: */
194: private static final class MethodFilter implements
195: FactoryRegistry.Filter {
196: /**
197: * The expected type ({@code Projection.class}) for projections).
198: */
199: private final Class type;
200:
201: /**
202: * Constructs a filter for the set of math operations methods.
203: */
204: public MethodFilter(final Class type) {
205: this .type = type;
206: }
207:
208: /**
209: * Returns {@code true} if the specified element should be included. If the type is
210: * unknown, conservatively returns {@code true}.
211: */
212: public boolean filter(final Object element) {
213: if (element instanceof MathTransformProvider) {
214: final Class t = ((MathTransformProvider) element)
215: .getOperationType();
216: if (t != null && !type.isAssignableFrom(t)) {
217: return false;
218: }
219: }
220: return true;
221: }
222: }
223:
224: /**
225: * Returns the operation method used for the latest call to
226: * {@link #createParameterizedTransform createParameterizedTransform}
227: * in the currently running thread. Returns {@code null} if not applicable.
228: *
229: * @see #createParameterizedTransform
230: *
231: * @since 2.4
232: */
233: public OperationMethod getLastMethodUsed() {
234: return (OperationMethod) lastMethod.get();
235: }
236:
237: /**
238: * @deprecated Renamed as {@link #getLastMethodUsed}.
239: */
240: public OperationMethod getLastUsedMethod() {
241: return getLastMethodUsed();
242: }
243:
244: /**
245: * Returns the operation method for the specified name.
246: *
247: * @param name The case insensitive {@linkplain Identifier#getCode identifier code}
248: * of the operation method to search for (e.g. {@code "Transverse_Mercator"}).
249: * @return The operation method.
250: * @throws NoSuchIdentifierException if there is no operation method registered for the
251: * specified name.
252: *
253: * @since 2.2
254: */
255: public OperationMethod getOperationMethod(final String name)
256: throws NoSuchIdentifierException {
257: return getProvider(name);
258: }
259:
260: /**
261: * Returns the math transform provider for the specified operation method.
262: * This provider can be used in order to query parameter for a method name
263: * (e.g. <code>getProvider("Transverse_Mercator").getParameters()</code>),
264: * or any of the alias in a given locale.
265: *
266: * @param method The case insensitive {@linkplain Identifier#getCode identifier code}
267: * of the operation method to search for (e.g. {@code "Transverse_Mercator"}).
268: * @return The math transform provider.
269: * @throws NoSuchIdentifierException if there is no provider registered for the specified
270: * method.
271: */
272: private synchronized MathTransformProvider getProvider(
273: final String method) throws NoSuchIdentifierException {
274: MathTransformProvider provider = lastProvider; // Avoid synchronization
275: if (provider != null && provider.nameMatches(method)) {
276: return provider;
277: }
278: final Iterator providers = registry.getServiceProviders(
279: MathTransformProvider.class, null, HINTS);
280: while (providers.hasNext()) {
281: provider = (MathTransformProvider) providers.next();
282: if (provider.nameMatches(method)) {
283: return lastProvider = provider;
284: }
285: }
286: throw new NoSuchIdentifierException(Errors.format(
287: ErrorKeys.NO_TRANSFORM_FOR_CLASSIFICATION_$1, method),
288: method);
289: }
290:
291: /**
292: * Returns the default parameter values for a math transform using the given method.
293: * The method argument is the name of any operation method returned by the
294: * {@link #getAvailableMethods} method. A typical example is
295: * <code>"<A HREF="http://www.remotesensing.org/geotiff/proj_list/transverse_mercator.html">Transverse_Mercator</A>"</code>).
296: *
297: * <P>This method creates new parameter instances at every call. It is intented to be modified
298: * by the user before to be passed to <code>{@linkplain #createParameterizedTransform
299: * createParameterizedTransform}(parameters)</code>.</P>
300: *
301: * @param method The case insensitive name of the method to search for.
302: * @return The default parameter values.
303: * @throws NoSuchIdentifierException if there is no transform registered for the specified
304: * method.
305: *
306: * @see #getAvailableMethods
307: * @see #createParameterizedTransform
308: * @see org.geotools.referencing.operation.transform.AbstractMathTransform#getParameterValues
309: */
310: public ParameterValueGroup getDefaultParameters(final String method)
311: throws NoSuchIdentifierException {
312: // Remove the cast when we will be allowed to compile for J2SE 1.5.
313: return (ParameterValueGroup) getProvider(method)
314: .getParameters().createValue();
315: }
316:
317: /**
318: * Not implemented in GeoTools 2.4. This method is implemented in GeoTools 2.5.
319: */
320: public MathTransform createBaseToDerived(
321: org.opengis.referencing.crs.CoordinateReferenceSystem baseCRS,
322: org.opengis.parameter.ParameterValueGroup parameters,
323: org.opengis.referencing.cs.CoordinateSystem derivedCS)
324: throws FactoryException {
325: throw new FactoryException("Not implemented.");
326: }
327:
328: /**
329: * Creates a transform from a group of parameters. The method name is inferred from
330: * the {@linkplain ParameterDescriptorGroup#getName parameter group name}. Example:
331: *
332: * <blockquote><pre>
333: * ParameterValueGroup p = factory.getDefaultParameters("Transverse_Mercator");
334: * p.parameter("semi_major").setValue(6378137.000);
335: * p.parameter("semi_minor").setValue(6356752.314);
336: * MathTransform mt = factory.createParameterizedTransform(p);
337: * </pre></blockquote>
338: *
339: * @param parameters The parameter values.
340: * @return The parameterized transform.
341: * @throws NoSuchIdentifierException if there is no transform registered for the method.
342: * @throws FactoryException if the object creation failed. This exception is thrown
343: * if some required parameter has not been supplied, or has illegal value.
344: *
345: * @see #getDefaultParameters
346: * @see #getAvailableMethods
347: * @see #getLastUsedMethod
348: */
349: public MathTransform createParameterizedTransform(
350: ParameterValueGroup parameters)
351: throws NoSuchIdentifierException, FactoryException {
352: // lastMethod.remove(); // TODO: uncomment when we will be allowed to target J2SE 1.5.
353: final String classification = parameters.getDescriptor()
354: .getName().getCode();
355: final MathTransformProvider provider = getProvider(classification);
356: OperationMethod method = provider;
357: MathTransform transform;
358: try {
359: parameters = provider.ensureValidValues(parameters);
360: transform = provider.createMathTransform(parameters);
361: } catch (IllegalArgumentException exception) {
362: /*
363: * Catch only exceptions which may be the result of improper parameter
364: * usage (e.g. a value out of range). Do not catch exception caused by
365: * programming errors (e.g. null pointer exception).
366: */
367: throw new FactoryException(exception);
368: }
369: if (transform instanceof MathTransformProvider.Delegate) {
370: final MathTransformProvider.Delegate delegate = (MathTransformProvider.Delegate) transform;
371: method = delegate.method;
372: transform = delegate.transform;
373: }
374: transform = (MathTransform) pool.unique(transform);
375: lastMethod.set(method);
376: return transform;
377: }
378:
379: /**
380: * Creates a transform from a group of parameters and add the method used to a list.
381: * This variant of {@code createParameterizedTransform(...)} provides a way for
382: * the client to keep trace of any {@linkplain OperationMethod operation method}
383: * used by this factory.
384: *
385: * @param parameters The parameter values.
386: * @param methods A collection where to add the operation method that apply to the transform,
387: * or {@code null} if none.
388: * @return The parameterized transform.
389: * @throws NoSuchIdentifierException if there is no transform registered for the method.
390: * @throws FactoryException if the object creation failed. This exception is thrown
391: * if some required parameter has not been supplied, or has illegal value.
392: *
393: * @deprecated Replaced by {@link #createParameterizedTransform(ParameterValueGroup)}
394: * followed by a call to {@link #getLastUsedMethod}.
395: */
396: public MathTransform createParameterizedTransform(
397: ParameterValueGroup parameters, Collection methods)
398: throws NoSuchIdentifierException, FactoryException {
399: MathTransform transform = createParameterizedTransform(parameters);
400: if (methods != null) {
401: methods.add(lastMethod.get());
402: }
403: return transform;
404: }
405:
406: /**
407: * Creates an affine transform from a matrix.
408: * If the transform's input dimension is {@code M}, and output dimension
409: * is {@code N}, then the matrix will have size {@code [N+1][M+1]}.
410: * The +1 in the matrix dimensions allows the matrix to do a shift, as well as
411: * a rotation. The {@code [M][j]} element of the matrix will be the j'th
412: * ordinate of the moved origin. The {@code [i][N]} element of the matrix
413: * will be 0 for <var>i</var> less than {@code M}, and 1 for <var>i</var>
414: * equals {@code M}.
415: *
416: * @param matrix The matrix used to define the affine transform.
417: * @return The affine transform.
418: * @throws FactoryException if the object creation failed.
419: */
420: public MathTransform createAffineTransform(final Matrix matrix)
421: throws FactoryException {
422: // lastMethod.remove(); // TODO: uncomment when we will be allowed to target J2SE 1.5.
423: return (MathTransform) pool.unique(ProjectiveTransform
424: .create(matrix));
425: }
426:
427: /**
428: * Creates a transform by concatenating two existing transforms.
429: * A concatenated transform acts in the same way as applying two
430: * transforms, one after the other.
431: *
432: * The dimension of the output space of the first transform must match
433: * the dimension of the input space in the second transform.
434: * If you wish to concatenate more than two transforms, then you can
435: * repeatedly use this method.
436: *
437: * @param transform1 The first transform to apply to points.
438: * @param transform2 The second transform to apply to points.
439: * @return The concatenated transform.
440: * @throws FactoryException if the object creation failed.
441: */
442: public MathTransform createConcatenatedTransform(
443: final MathTransform transform1,
444: final MathTransform transform2) throws FactoryException {
445: // lastMethod.remove(); // TODO: uncomment when we will be allowed to target J2SE 1.5.
446: MathTransform tr;
447: try {
448: tr = ConcatenatedTransform.create(transform1, transform2);
449: } catch (IllegalArgumentException exception) {
450: throw new FactoryException(exception);
451: }
452: tr = (MathTransform) pool.unique(tr);
453: return tr;
454: }
455:
456: /**
457: * Creates a transform which passes through a subset of ordinates to another transform.
458: * This allows transforms to operate on a subset of ordinates. For example, if you have
459: * (<var>Lat</var>,<var>Lon</var>,<var>Height</var>) coordinates, then you may wish to
460: * convert the height values from meters to feet without affecting the
461: * (<var>Lat</var>,<var>Lon</var>) values.
462: *
463: * @param firstAffectedOrdinate The lowest index of the affected ordinates.
464: * @param subTransform Transform to use for affected ordinates.
465: * @param numTrailingOrdinates Number of trailing ordinates to pass through.
466: * Affected ordinates will range from {@code firstAffectedOrdinate}
467: * inclusive to {@code dimTarget-numTrailingOrdinates} exclusive.
468: * @return A pass through transform with the following dimensions:<br>
469: * <pre>
470: * Source: firstAffectedOrdinate + subTransform.getSourceDimensions() + numTrailingOrdinates
471: * Target: firstAffectedOrdinate + subTransform.getTargetDimensions() + numTrailingOrdinates</pre>
472: * @throws FactoryException if the object creation failed.
473: */
474: public MathTransform createPassThroughTransform(
475: final int firstAffectedOrdinate,
476: final MathTransform subTransform,
477: final int numTrailingOrdinates) throws FactoryException {
478: // lastMethod.remove(); // TODO: uncomment when we will be allowed to target J2SE 1.5.
479: MathTransform tr;
480: try {
481: tr = PassThroughTransform.create(firstAffectedOrdinate,
482: subTransform, numTrailingOrdinates);
483: } catch (IllegalArgumentException exception) {
484: throw new FactoryException(exception);
485: }
486: tr = (MathTransform) pool.unique(tr);
487: return tr;
488: }
489:
490: /**
491: * Creates a math transform object from a XML string. The default implementation
492: * always throws an exception, since this method is not yet implemented.
493: *
494: * @param xml Math transform encoded in XML format.
495: * @throws FactoryException if the object creation failed.
496: */
497: public MathTransform createFromXML(String xml)
498: throws FactoryException {
499: throw new FactoryException("Not yet implemented.");
500: }
501:
502: /**
503: * Creates a math transform object from a
504: * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
505: * Known Text</cite> (WKT)</A>.
506: *
507: * @param text Math transform encoded in Well-Known Text format.
508: * @return The math transform (never {@code null}).
509: * @throws FactoryException if the Well-Known Text can't be parsed,
510: * or if the math transform creation failed from some other reason.
511: */
512: public synchronized MathTransform createFromWKT(final String text)
513: throws FactoryException {
514: // Note: while this factory is thread safe, the WKT parser is not.
515: // Since we share a single instance of this parser, we must
516: // synchronize.
517: if (parser == null) {
518: parser = new MathTransformParser(Symbols.DEFAULT, this );
519: }
520: try {
521: return parser.parseMathTransform(text);
522: } catch (ParseException exception) {
523: final Throwable cause = exception.getCause();
524: if (cause instanceof FactoryException) {
525: throw (FactoryException) cause;
526: }
527: throw new FactoryException(exception);
528: }
529: }
530:
531: /**
532: * Scans for factory plug-ins on the application class path. This method is
533: * needed because the application class path can theoretically change, or
534: * additional plug-ins may become available. Rather than re-scanning the
535: * classpath on every invocation of the API, the class path is scanned
536: * automatically only on the first invocation. Clients can call this
537: * method to prompt a re-scan. Thus this method need only be invoked by
538: * sophisticated applications which dynamically make new plug-ins
539: * available at runtime.
540: */
541: public void scanForPlugins() {
542: registry.scanForPlugins();
543: }
544:
545: /**
546: * Dump to the standard output stream a list of available operation methods.
547: * This method can be invoked from the command line. It provides a mean to
548: * verify which transforms were found in the classpath. The syntax is:
549: * <BR>
550: * <BLOCKQUOTE><CODE>
551: * java org.geotools.referencing.operation.DefaultMathTransformFactory
552: * <VAR><options></VAR> <VAR><method></VAR>
553: * </CODE></BLOCKQUOTE>
554: *
555: * <P>where options are:</P>
556: *
557: * <TABLE CELLPADDING='0' CELLSPACING='0'>
558: * <TR><TD NOWRAP><CODE>-projections</CODE></TD>
559: * <TD NOWRAP> List only projections</TD></TR>
560: * <TR><TD NOWRAP><CODE>-conversions</CODE></TD>
561: * <TD NOWRAP> List only conversions</TD></TR>
562: * <TR><TD NOWRAP><CODE>-all</CODE></TD>
563: * <TD NOWRAP> List the parameters for all transforms</TD></TR>
564: * <TR><TD NOWRAP><CODE>-encoding</CODE> <VAR><code></VAR></TD>
565: * <TD NOWRAP> Set the character encoding</TD></TR>
566: * <TR><TD NOWRAP><CODE>-locale</CODE> <VAR><language></VAR></TD>
567: * <TD NOWRAP> Set the language for the output (e.g. "fr" for French)</TD></TR>
568: * </TABLE>
569: *
570: * <P>and <VAR><method></VAR> is the optional name of an operation method
571: * (e.g. <CODE>"Affine"</CODE>, <CODE>"EPSG:9624"</CODE> or just
572: * <CODE>"9624"</CODE> for the affine transform method).</P>
573: *
574: * <P><strong>Note for Windows users:</strong> If the output contains strange
575: * symbols, try to supply an "{@code -encoding}" argument. Example:</P>
576: *
577: * <blockquote><code>
578: * java org.geotools.referencing.operation.DefaultMathTransformFactory -encoding Cp850
579: * </code></blockquote>
580: *
581: * <P>The codepage number (850 in the previous example) can be obtained from the DOS
582: * commande line using the "{@code chcp}" command with no arguments.
583: * This {@code -encoding} argument need to be supplied only once.</P>
584: *
585: * @param args Command line arguments.
586: */
587: public static void main(String[] args) {
588: /*
589: * Parse the command-line arguments and print the summary.
590: */
591: final Arguments arguments = new Arguments(args);
592: final boolean printAll = arguments.getFlag("-all");
593: Class type = null;
594: if (arguments.getFlag("-projections"))
595: type = Projection.class;
596: if (arguments.getFlag("-conversions"))
597: type = Conversion.class;
598: args = arguments.getRemainingArguments(1);
599: try {
600: final DefaultMathTransformFactory factory = new DefaultMathTransformFactory();
601: final ParameterWriter writer = new ParameterWriter(
602: arguments.out);
603: writer.setLocale(arguments.locale);
604: Set transforms = Collections.EMPTY_SET;
605: if (printAll || args.length == 0) {
606: final Set scopes = new HashSet();
607: // scopes.add("OGC"); // Omitted because usually the same than 'identifier'.
608: scopes.add("EPSG");
609: scopes.add("Geotools"); // Limit the number of columns to output.
610: transforms = new TreeSet(
611: AbstractIdentifiedObject.NAME_COMPARATOR);
612: transforms.addAll(factory.getAvailableMethods(type));
613: writer.summary(transforms, scopes);
614: }
615: if (!printAll) {
616: if (args.length == 0) {
617: transforms = Collections.EMPTY_SET;
618: } else {
619: transforms = Collections.singleton(factory
620: .getProvider(args[0]));
621: }
622: }
623: /*
624: * Iterates through all math transform to print. It may be a singleton
625: * if the user ask for a specific math transform.
626: */
627: final Iterator it = transforms.iterator();
628: final String lineSeparator = System.getProperty(
629: "line.separator", "\n");
630: while (it.hasNext()) {
631: arguments.out.write(lineSeparator);
632: writer.format((OperationMethod) it.next());
633: }
634: } catch (NoSuchIdentifierException exception) {
635: arguments.err.println(exception.getLocalizedMessage());
636: return;
637: } catch (Exception exception) {
638: exception.printStackTrace(arguments.err);
639: return;
640: }
641: arguments.out.flush();
642: }
643: }
|