use of org.opengis.parameter.ParameterDescriptor in project sis by apache.
the class CC_OperationParameterGroup method merge.
/**
* Invoked by {@link DefaultParameterDescriptorGroup#setDescriptors(GeneralParameterDescriptor[])}
* for merging into a single set the descriptors which are repeated twice in a GML document.
*
* <p>The {@code descriptors} argument gives the descriptors listed explicitely inside a
* {@code <gml:OperationParameterGroup>} or {@code <gml:OperationMethod>} element. Those
* descriptors are said "incomplete" (from SIS point of view) because they are missing the
* {@link ParameterDescriptor#getValueClass()} property, which does not exist in GML but
* is mandatory for us. However an exception to this "incompleteness" happen when SIS has
* been able to match the {@code <gml:OperationMethod>} parent to one of the pre-defined
* operations in the {@link org.apache.sis.internal.referencing.provider} package.</p>
*
* <p>The {@code fromValues} argument gives the descriptors declared in each {@code <gml:ParameterValue>}
* instances of a {@code <gml:ParameterValueGroup>} or {@code <gml:AbstractSingleOperation>} element.
* Contrarily to the {@code descriptors} argument, the {@code fromValues} instances should have non-null
* {@link ParameterDescriptor#getValueClass()} property inferred by SIS from the parameter value.</p>
*
* <p>So the preferred descriptors from more complete to less complete are:</p>
* <ol>
* <li>{@code descriptors} if and only if they contain pre-defined parameters inferred by SIS from the {@code <gml:OperationMethod>} name.</li>
* <li>{@code fromValues}, which contain the descriptors declared in the {@code <gml:ParameterValue>} instances.</li>
* <li>{@code descriptors}, which contain the descriptor listed in {@code <gml:OperationParameterGroup>} or {@code <gml:OperationMethod>}.</li>
* </ol>
*
* <div class="note"><b>Note:</b>
* this code is defined in this {@code CC_OperationParameterGroup} class instead than in the
* {@link DefaultParameterDescriptorGroup} class in the hope to reduce the amount of code
* processed by the JVM in the common case where JAXB (un)marshalling is not needed.</div>
*
* @param descriptors the descriptors declared in the {@code ParameterDescriptorGroup}.
* @param fromValues the descriptors declared in the {@code ParameterValue} instances.
* They are said "valid" because they contain the mandatory {@code valueClass} property.
* @param replacements an {@code IdentityHashMap} where to store the replacements that the caller needs to
* apply in the {@code GeneralParameterValue} instances.
* @return a sequence containing the merged set of parameter descriptors.
*
* @see <a href="http://issues.apache.org/jira/browse/SIS-290">SIS-290</a>
*/
public static GeneralParameterDescriptor[] merge(final List<GeneralParameterDescriptor> descriptors, final GeneralParameterDescriptor[] fromValues, final Map<GeneralParameterDescriptor, GeneralParameterDescriptor> replacements) {
if (descriptors.isEmpty()) {
return fromValues;
}
final Map<String, GeneralParameterDescriptor> union = new LinkedHashMap<>(Containers.hashMapCapacity(descriptors.size()));
/*
* Collect the descriptors declared explicitely in the ParameterDescriptorGroup. We should never have
* two descriptors of the same name since the DefaultParameterDescriptorGroup constructor checked for
* name ambiguity. If a name collision is nevertheless detected, this would mean that a descriptor's
* name mutated.
*/
for (final GeneralParameterDescriptor p : descriptors) {
final String name = p.getName().getCode();
if (union.put(name, p) != null) {
throw new CorruptedObjectException(name);
}
}
/*
* Verify if any descriptors found in the ParameterValue instances could replace the descriptors in the group.
* We give precedence to the descriptors having a non-null 'valueClass' property, which normally appear in the
* 'fromValues' array.
*/
for (final GeneralParameterDescriptor valueDescriptor : fromValues) {
final String name = valueDescriptor.getName().getCode();
GeneralParameterDescriptor complete = valueDescriptor;
GeneralParameterDescriptor previous = union.put(name, complete);
if (previous != null) {
if (previous instanceof ParameterDescriptor<?>) {
verifyEquivalence(name, complete instanceof ParameterDescriptor<?>);
final Class<?> valueClass = ((ParameterDescriptor<?>) previous).getValueClass();
if (valueClass != null) {
/*
* This may happen if the 'descriptors' argument contain the parameters of a pre-defined
* method from the 'org.apache.sis.internal.referencing.provider' package instead than a
* descriptor from the GML file. In such case, presume that 'previous' is actually more
* complete than 'complete'.
*
* Note that 'r' should never be null unless JAXB unmarshalled the elements in reverse
* order (e.g. <gml:ParameterValue> before <gml:OperationMethod>). Since this behavior
* may depend on JAXB implementation, we are better to check for such case.
*/
final Class<?> r = ((ParameterDescriptor<?>) complete).getValueClass();
if (r != null) {
verifyEquivalence(name, valueClass == r);
}
// Restore the previous value in the map and swap 'previous' with 'replacement'.
previous = union.put(name, complete = previous);
}
} else if (previous instanceof ParameterDescriptorGroup) {
verifyEquivalence(name, complete instanceof ParameterDescriptorGroup);
}
/*
* Verify that the replacement contains at least all the information provided by the previous
* descriptor. The replacement is allowed to contain more information however.
*/
final GeneralParameterDescriptor replacement = CC_GeneralOperationParameter.merge(previous, complete);
if (replacement != valueDescriptor) {
union.put(name, replacement);
if (replacements.put(valueDescriptor, replacement) != null) {
// Should never happen, unless the parameter name changed during execution of this loop.
throw new CorruptedObjectException(name);
}
}
}
}
return union.values().toArray(new GeneralParameterDescriptor[union.size()]);
}
use of org.opengis.parameter.ParameterDescriptor in project sis by apache.
the class EPSGDataAccess method createOperationMethod.
/**
* Creates description of the algorithm and parameters used to perform a coordinate operation.
* An {@code OperationMethod} is a kind of metadata: it does not perform any coordinate operation
* (e.g. map projection) by itself, but tells us what is needed in order to perform such operation.
*
* <div class="note"><b>Example:</b>
* some EPSG codes for operation methods are:
*
* <table class="sis" summary="EPSG codes examples">
* <tr><th>Code</th> <th>Description</th></tr>
* <tr><td>9804</td> <td>Mercator (variant A)</td></tr>
* <tr><td>9802</td> <td>Lambert Conic Conformal (2SP)</td></tr>
* <tr><td>9810</td> <td>Polar Stereographic (variant A)</td></tr>
* <tr><td>9624</td> <td>Affine parametric transformation</td></tr>
* </table></div>
*
* @param code value allocated by EPSG.
* @return the operation method for the given code.
* @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
* @throws FactoryException if the object creation failed for some other reason.
*/
@Override
public synchronized OperationMethod createOperationMethod(final String code) throws NoSuchAuthorityCodeException, FactoryException {
ArgumentChecks.ensureNonNull("code", code);
OperationMethod returnValue = null;
try (ResultSet result = executeQuery("Coordinate_Operation Method", "COORD_OP_METHOD_CODE", "COORD_OP_METHOD_NAME", "SELECT COORD_OP_METHOD_CODE," + " COORD_OP_METHOD_NAME," + " REMARKS," + " DEPRECATED" + " FROM [Coordinate_Operation Method]" + " WHERE COORD_OP_METHOD_CODE = ?", code)) {
while (result.next()) {
final Integer epsg = getInteger(code, result, 1);
final String name = getString(code, result, 2);
final String remarks = getOptionalString(result, 3);
final boolean deprecated = getOptionalBoolean(result, 4);
final Integer[] dim = getDimensionsForMethod(epsg);
final ParameterDescriptor<?>[] descriptors = createParameterDescriptors(epsg);
Map<String, Object> properties = createProperties("Coordinate_Operation Method", name, epsg, remarks, deprecated);
// We do not store the formula at this time, because the text is very verbose and rarely used.
final OperationMethod method = new DefaultOperationMethod(properties, dim[0], dim[1], new DefaultParameterDescriptorGroup(properties, 1, 1, descriptors));
returnValue = ensureSingleton(method, returnValue, code);
}
} catch (SQLException exception) {
throw databaseFailure(OperationMethod.class, code, exception);
}
if (returnValue == null) {
throw noSuchAuthorityCode(OperationMethod.class, code);
}
return returnValue;
}
use of org.opengis.parameter.ParameterDescriptor in project sis by apache.
the class CC_OperationParameterGroupTest method create.
/**
* Creates the parameter descriptors equivalent to the result of {@link #unmarshal()}
* but with value class, units and default values.
*
* @param remarks Remarks to associate to the latitude parameter, or {@code null} if none.
*/
private static ParameterDescriptor<?>[] create(final String remarks) {
final ParameterBuilder builder = new ParameterBuilder();
builder.setCodeSpace(EPSG, "EPSG").setRequired(true);
return new ParameterDescriptor<?>[] { builder.addIdentifier("8801").addName("Latitude of natural origin").setRemarks(remarks).create(0, Units.DEGREE), builder.addIdentifier("8802").addName("Longitude of natural origin").create(0, Units.DEGREE) };
}
use of org.opengis.parameter.ParameterDescriptor in project sis by apache.
the class ParameterBuilderTest method testMercatorProjection.
/**
* Tests the <cite>"Mercator (variant A)"</cite> example given in Javadoc.
*/
@Test
@DependsOnMethod("testCreate")
@SuppressWarnings("UnnecessaryBoxing")
public void testMercatorProjection() {
final ParameterBuilder builder = new ParameterBuilder();
builder.setCodeSpace(Citations.EPSG, "EPSG").setRequired(true);
final ParameterDescriptor<?>[] parameters = { builder.addName("Longitude of natural origin").addName(Citations.OGC, "central_meridian").addName(Citations.GEOTIFF, "NatOriginLong").setRemarks("Some remarks.").createBounded(-180, +180, 0, Units.DEGREE), builder.addName("Latitude of natural origin").createBounded(-80, +84, 0, Units.DEGREE), builder.addName("Scale factor at natural origin").createStrictlyPositive(1, Units.UNITY), builder.addName("False easting").create(0, Units.METRE), builder.addName("False northing").create(0, Units.METRE) };
// Tests random properties.
assertEquals("EPSG", parameters[1].getName().getCodeSpace());
assertEquals("False easting", parameters[3].getName().getCode());
assertEquals("Some remarks.", parameters[0].getRemarks().toString());
assertEquals(Double.valueOf(84), parameters[1].getMaximumValue());
assertEquals(Units.METRE, parameters[4].getUnit());
assertTrue(parameters[1].getAlias().isEmpty());
final GenericName alias = parameters[0].getAlias().iterator().next();
assertEquals("central_meridian", alias.tip().toString());
assertEquals("OGC", alias.head().toString());
assertEquals("OGC:central_meridian", alias.toString());
}
use of org.opengis.parameter.ParameterDescriptor in project sis by apache.
the class SingleOperationMarshallingTest method createMercatorMethod.
/**
* Creates the test operation method.
*/
private static DefaultOperationMethod createMercatorMethod() {
final ParameterBuilder builder = new ParameterBuilder();
builder.setCodeSpace(EPSG, "EPSG").setRequired(true);
ParameterDescriptor<?>[] parameters = { builder.addIdentifier("8801").addName("Latitude of natural origin").create(0, Units.DEGREE), builder.addIdentifier("8802").addName("Longitude of natural origin").create(0, Units.DEGREE) // There is more parameters for a Mercator projection, but 2 is enough for this test.
};
builder.addName(null, "Mercator (1SP)");
final ParameterDescriptorGroup descriptor = builder.createGroup(parameters);
final Map<String, Object> properties = new HashMap<>(4);
properties.put(DefaultOperationMethod.NAME_KEY, descriptor.getName());
properties.put(DefaultOperationMethod.FORMULA_KEY, new DefaultFormula("See EPSG guide."));
return new DefaultOperationMethod(properties, 2, 2, descriptor);
}
Aggregations