/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-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.referencing.wkt; import java.text.ParseException; import java.text.ParsePosition; import org.opengis.parameter.ParameterValue; import org.opengis.parameter.ParameterValueGroup; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchIdentifierException; import org.opengis.referencing.operation.Operation; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.MathTransformFactory; import org.opengis.referencing.operation.NoninvertibleTransformException; import org.opengis.referencing.operation.OperationMethod; import org.geotools.referencing.ReferencingFactoryFinder; import org.geotools.referencing.AbstractIdentifiedObject; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Errors; /** * Parser for {@linkplain MathTransform math transform} * Well * Known Text (WKT) of math transform. * * @since 2.0 * * @source $URL$ * @version $Id$ * @author Remi Eve * @author Martin Desruisseaux (IRD) * @author Rueben Schulz */ public class MathTransformParser extends AbstractParser { /** * The factory to use for creating math transforms. */ protected final MathTransformFactory mtFactory; /** * The classification of the last math transform or projection parsed, * or {@code null} if none. */ private String classification; /** * The method for the last math transform passed, or {@code null} if none. * * @see #getOperationMethod */ private OperationMethod lastMethod; /** * Constructs a parser using the default set of symbols. */ public MathTransformParser() { this(Symbols.DEFAULT); } /** * Constructs a parser using the specified set of symbols * and the default factories. * * @param symbols The symbols for parsing and formatting numbers. * * @todo Pass hints in argument. */ public MathTransformParser(final Symbols symbols) { this(symbols, ReferencingFactoryFinder.getMathTransformFactory(null)); } /** * Constructs a parser for the specified set of symbols and factory. * * @param symbols The symbols for parsing and formatting numbers. * @param mtFactory The factory to use to create {@link MathTransform} objects. */ public MathTransformParser(final Symbols symbols, final MathTransformFactory mtFactory) { super(symbols); this.mtFactory = mtFactory; } /** * Parses a math transform element. * * @param text The text to be parsed. * @return The math transform. * @throws ParseException if the string can't be parsed. */ public MathTransform parseMathTransform(final String text) throws ParseException { final Element element = getTree(text, new ParsePosition(0)); final MathTransform mt = parseMathTransform(element, true); element.close(); return mt; } /** * Parses the next element in the specified Well Know Text (WKT) tree. * * @param element The element to be parsed. * @return The object. * @throws ParseException if the element can't be parsed. */ protected Object parse(final Element element) throws ParseException { return parseMathTransform(element, true); } /** * Parses the next element (a {@link MathTransform}) in the specified * Well Know Text (WKT) tree. * * @param element The parent element. * @param required True if parameter is required and false in other case. * @return The next element as a {@link MathTransform} object. * @throws ParseException if the next element can't be parsed. */ final MathTransform parseMathTransform(final Element element, final boolean required) throws ParseException { lastMethod = null; classification = null; final Object key = element.peek(); if (key instanceof Element) { final String keyword = ((Element) key).keyword.trim().toUpperCase(symbols.locale); if ("PARAM_MT" .equals(keyword)) return parseParamMT (element); if ("CONCAT_MT" .equals(keyword)) return parseConcatMT (element); if ("INVERSE_MT" .equals(keyword)) return parseInverseMT (element); if ("PASSTHROUGH_MT".equals(keyword)) return parsePassThroughMT(element); } if (required) { throw element.parseFailed(null, Errors.format(ErrorKeys.UNKNOW_TYPE_$1, key)); } return null; } /** * Parses a "PARAM_MT" element. This element has the following pattern: * *
* PARAM_MT["" {,}* ]
*
*
* @param parent The parent element.
* @return The "PARAM_MT" element as an {@link MathTransform} object.
* @throws ParseException if the "PARAM_MT" element can't be parsed.
*/
private MathTransform parseParamMT(final Element parent) throws ParseException {
final Element element = parent.pullElement("PARAM_MT");
classification = element.pullString("classification");
final ParameterValueGroup parameters;
try {
parameters = mtFactory.getDefaultParameters(classification);
} catch (NoSuchIdentifierException exception) {
throw element.parseFailed(exception, null);
}
/*
* Scan over all PARAMETER["name", value] elements and
* set the corresponding parameter in the parameter group.
*/
Element param;
while ((param=element.pullOptionalElement("PARAMETER")) != null) {
final String name = param.pullString("name");
final ParameterValue parameter = parameters.parameter(name);
final Class type = parameter.getDescriptor().getValueClass();
if (Integer.class.equals(type)) {
parameter.setValue(param.pullInteger("value"));
} else if (Double.class.equals(type)) {
parameter.setValue(param.pullDouble("value"));
} else {
parameter.setValue(param.pullString("value"));
}
param.close();
}
element.close();
/*
* We now have all informations for constructing the math transform. If the factory is
* a Geotools implementation, we will use a special method that returns the operation
* method used. Otherwise, we will use the ordinary method and will performs a slower
* search for the operation method later if the user ask for it.
*/
final MathTransform transform;
try {
transform = mtFactory.createParameterizedTransform(parameters);
} catch (FactoryException exception) {
throw element.parseFailed(exception, null);
}
lastMethod = mtFactory.getLastMethodUsed();
return transform;
}
/**
* Parses a "INVERSE_MT" element. This element has the following pattern:
*
*
* INVERSE_MT[
*
* @param parent The parent element.
* @return The "INVERSE_MT" element as an {@link MathTransform} object.
* @throws ParseException if the "INVERSE_MT" element can't be parsed.
*/
private MathTransform parseInverseMT(final Element parent) throws ParseException {
final Element element = parent.pullElement("INVERSE_MT");
try {
final MathTransform transform;
transform = parseMathTransform(element, true).inverse();
element.close();
return transform;
}
catch (NoninvertibleTransformException exception) {
throw element.parseFailed(exception, null);
}
}
/**
* Parses a "PASSTHROUGH_MT" element. This element has the following pattern:
*
*
* PASSTHROUGH_MT[,
*
* @param parent The parent element.
* @return The "PASSTHROUGH_MT" element as an {@link MathTransform} object.
* @throws ParseException if the "PASSTHROUGH_MT" element can't be parsed.
*/
private MathTransform parsePassThroughMT(final Element parent) throws ParseException {
final Element element = parent.pullElement("PASSTHROUGH_MT");
final int firstAffectedOrdinate = parent.pullInteger("firstAffectedOrdinate");
final MathTransform transform = parseMathTransform(element, true);
element.close();
try {
return mtFactory.createPassThroughTransform(firstAffectedOrdinate, transform, 0);
} catch (FactoryException exception) {
throw element.parseFailed(exception, null);
}
}
/**
* Parses a "CONCAT_MT" element. This element has the following pattern:
*
*
* CONCAT_MT[
*
* @param parent The parent element.
* @return The "CONCAT_MT" element as an {@link MathTransform} object.
* @throws ParseException if the "CONCAT_MT" element can't be parsed.
*/
private MathTransform parseConcatMT(final Element parent) throws ParseException {
final Element element = parent.pullElement("CONCAT_MT");
MathTransform transform = parseMathTransform(element, true);
MathTransform optionalTransform;
while ((optionalTransform = parseMathTransform(element, false)) != null) {
try {
transform = mtFactory.createConcatenatedTransform(transform, optionalTransform);
} catch (FactoryException exception) {
throw element.parseFailed(exception, null);
}
}
element.close();
return transform;
}
/**
* Returns the operation method for the last math transform parsed. This is used by
* {@link Parser} in order to built {@link org.opengis.referencing.crs.DerivedCRS}.
*/
final OperationMethod getOperationMethod() {
if (lastMethod == null) {
/*
* Safety in case come MathTransformFactory implementation do not support
* getLastMethod(). Performs a slower and less robust check as a fallback.
*/
if (classification != null) {
for (final OperationMethod method : mtFactory.getAvailableMethods(Operation.class)) {
if (AbstractIdentifiedObject.nameMatches(method, classification)) {
lastMethod = method;
break;
}
}
}
}
return lastMethod;
}
}