*/
public synchronized CoordinateOperation generateCoordinateOperation(final String code)
throws FactoryException
{
ensureNonNull("code", code);
CoordinateOperation returnValue = null;
try {
final String primaryKey = toPrimaryKey(CoordinateOperation.class, code,
"[Coordinate_Operation]", "COORD_OP_CODE", "COORD_OP_NAME");
final PreparedStatement stmt;
stmt = prepareStatement("CoordinateOperation", "SELECT COORD_OP_CODE,"
+ " COORD_OP_NAME,"
+ " COORD_OP_TYPE,"
+ " SOURCE_CRS_CODE,"
+ " TARGET_CRS_CODE,"
+ " COORD_OP_METHOD_CODE,"
+ " COORD_TFM_VERSION,"
+ " COORD_OP_ACCURACY,"
+ " AREA_OF_USE_CODE,"
+ " COORD_OP_SCOPE,"
+ " REMARKS"
+ " FROM [Coordinate_Operation]"
+ " WHERE COORD_OP_CODE = ?");
stmt.setString(1, primaryKey);
ResultSet result = stmt.executeQuery();
while (result.next()) {
final String epsg = getString(result, 1, code);
final String name = getString(result, 2, code);
final String type = getString(result, 3, code).trim().toLowerCase();
final boolean isTransformation = type.equals("transformation");
final boolean isConversion = type.equals("conversion");
final boolean isConcatenated = type.equals("concatenated operation");
final String sourceCode, targetCode, methodCode;
if (isConversion) {
// Optional for conversions, mandatory for all others.
sourceCode = result.getString(4);
targetCode = result.getString(5);
} else {
sourceCode = getString(result, 4, code);
targetCode = getString(result, 5, code);
}
if (isConcatenated) {
// Not applicable to concatenated operation, mandatory for all others.
methodCode = result.getString(6);
} else {
methodCode = getString(result, 6, code);
}
String version = result.getString( 7);
double accuracy = result.getDouble( 8); if (result.wasNull()) accuracy=Double.NaN;
String area = result.getString( 9);
String scope = result.getString(10);
String remarks = result.getString(11);
/*
* Gets the source and target CRS. They are mandatory for transformations (it
* was checked above in this method) and optional for conversions. Conversions
* are usually "defining conversions" and don't define source and target CRS.
* In EPSG database 6.7, all defining conversions are projections and their
* dimensions are always 2. However, this is not generalizable to other kind
* of operation methods. For example the "Geocentric translation" operation
* method has 3-dimensional source and target.
*/
final int sourceDimensions, targetDimensions;
final CoordinateReferenceSystem sourceCRS, targetCRS;
if (sourceCode != null) {
sourceCRS = createCoordinateReferenceSystem(sourceCode);
sourceDimensions = sourceCRS.getCoordinateSystem().getDimension();
} else {
sourceCRS = null;
sourceDimensions = 2; // Acceptable default for projections only.
}
if (targetCode != null) {
targetCRS = createCoordinateReferenceSystem(targetCode);
targetDimensions = targetCRS.getCoordinateSystem().getDimension();
} else {
targetCRS = null;
targetDimensions = 2; // Acceptable default for projections only.
}
/*
* Gets the operation method. This is mandatory for conversions and transformations
* (it was checked above in this method) but optional for concatenated operations.
* Fetching parameter values is part of this block.
*/
final boolean isBursaWolf;
OperationMethod method;
final ParameterValueGroup parameters;
if (methodCode == null) {
isBursaWolf = false;
method = null;
parameters = null;
} else {
final int num;
try {
num = Integer.parseInt(methodCode);
} catch (NumberFormatException exception) {
result.close();
throw new FactoryException(exception);
}
isBursaWolf = (num>=BURSA_WOLF_MIN_CODE && num<=BURSA_WOLF_MAX_CODE);
// Reminder: The source and target dimensions MUST be computed when
// the information is available. Dimension is not always 2!!
method = generateOperationMethod(methodCode);
if (method.getSourceDimensions() != sourceDimensions ||
method.getTargetDimensions() != targetDimensions)
{
method = new DefaultOperationMethod(method, sourceDimensions, targetDimensions);
}
/*
* Note that some parameters required for MathTransform creation are implicit in
* the EPSG database (e.g. semi-major and semi-minor axis length in the case of
* map projections). We ask the parameter value group straight from the math
* transform factory instead of from the operation method in order to get all
* required parameter descriptors, including implicit ones.
*/
final String classe = method.getName().getCode();
parameters = factories.getMathTransformFactory().getDefaultParameters(classe);
fillParameterValues(methodCode, epsg, parameters);
}
/*
* Creates common properties. The 'version' and 'accuracy' are usually defined
* for transformations only. However, we check them for all kind of operations
* (including conversions) and copy the information inconditionnaly if present.
*
* NOTE: This block must be executed last before object creations below, because
* methods like createCoordinateReferenceSystem and createOperationMethod
* overwrite the properties map.
*/
final Map<String,Object> properties = generateProperties(name, epsg, area, scope, remarks);
if (version!=null && (version=version.trim()).length()!=0) {
properties.put(CoordinateOperation.OPERATION_VERSION_KEY, version);
}
if (!Double.isNaN(accuracy)) {
final QuantitativeResultImpl accuracyResult;
final AbsoluteExternalPositionalAccuracyImpl accuracyElement;
accuracyResult = new QuantitativeResultImpl(new double[]{accuracy});
// TODO: Need to invoke something equivalent to:
// accuracyResult.setValueType(Float.class);
// This is the type declared in the MS-Access database.
accuracyResult.setValueUnit(SI.METER); // In meters by definition in the EPSG database.
accuracyElement = new AbsoluteExternalPositionalAccuracyImpl(accuracyResult);
accuracyElement.setMeasureDescription(TRANSFORMATION_ACCURACY);
accuracyElement.setEvaluationMethodType(EvaluationMethodType.DIRECT_EXTERNAL);
properties.put(CoordinateOperation.COORDINATE_OPERATION_ACCURACY_KEY,
new PositionalAccuracy[] {
(PositionalAccuracy)accuracyElement.unmodifiable()
});
}
/*
* Creates the operation. Conversions should be the only operations allowed to
* have null source and target CRS. In such case, the operation is a defining
* conversion (usually to be used later as part of a ProjectedCRS creation),
* and always a projection in the specific case of the EPSG database (which
* allowed us to assume 2-dimensional operation method in the code above for
* this specific case - not to be generalized to the whole EPSG database).
*/
final CoordinateOperation operation;
if (isConversion && (sourceCRS==null || targetCRS==null)) {
// Note: we usually can't resolve sourceCRS and targetCRS because there
// is many of them for the same coordinate operation (projection) code.
operation = new DefiningConversion(properties, method, parameters);
} else if (isConcatenated) {