use of org.opengis.parameter.GeneralParameterDescriptor in project sis by apache.
the class Formatter method appendComplement.
/**
* Appends the optional complementary attributes common to many {@link IdentifiedObject} subtypes.
* Those attributes are {@code ANCHOR}, {@code SCOPE}, {@code AREA}, {@code BBOX}, {@code VERTICALEXTENT},
* {@code TIMEEXTENT}, {@code ID} (previously known as {@code AUTHORITY}) and {@code REMARKS},
* and have a special treatment: they are written by {@link #append(FormattableObject)}
* after the {@code formatTo(Formatter)} method returned.
*
* <p>The {@code ID[<name>,<code>,…]} element is normally written only for the root element
* (unless the convention is {@code INTERNAL}), but there is various exceptions to this rule.
* If formatted, the {@code ID} element will be by default on the same line than the enclosing
* element (e.g. {@code SPHEROID["Clarke 1866", …, ID["EPSG", 7008]]}). Other example:</p>
*
* {@preformat text
* PROJCS["NAD27 / Idaho Central",
* GEOGCS[...etc...],
* ...etc...
* ID["EPSG", 26769]]
* }
*
* For non-internal conventions, all elements other than {@code ID[…]} are formatted
* only for {@link CoordinateOperation} and root {@link ReferenceSystem} instances,
* with an exception for remarks of {@code ReferenceSystem} embedded inside {@code CoordinateOperation}.
* Those restrictions are our interpretation of the following ISO 19162 requirement:
*
* <blockquote>(…snip…) {@code <scope extent identifier remark>} is a collection of four optional attributes
* which may be applied to a coordinate reference system, a coordinate operation or a boundCRS. (…snip…)
* Identifier (…snip…) may also be utilised for components of these objects although this is not recommended
* except for coordinate operation methods (including map projections) and parameters. (…snip…)
* A {@code <remark>} can be included within the descriptions of source and target CRS embedded within
* a coordinate transformation as well as within the coordinate transformation itself.</blockquote>
*/
@SuppressWarnings("null")
private void appendComplement(final IdentifiedObject object, final FormattableObject parent, final FormattableObject gp) {
isComplement = true;
// Whether to format ID[…] elements.
final boolean showIDs;
// Whether we shall limit to a single ID[…] element.
final boolean filterID;
// Whether to format any element other than ID[…] and Remarks[…].
final boolean showOthers;
// Whether to format Remarks[…].
final boolean showRemarks;
if (convention == Convention.INTERNAL) {
showIDs = true;
filterID = false;
showOthers = true;
showRemarks = true;
} else {
/*
* Except for the special cases of OperationMethod and Parameters, ISO 19162 recommends to format the
* ID only for the root element. But Apache SIS adds an other exception to this rule by handling the
* components of CompoundCRS as if they were root elements. The reason is that users often create their
* own CompoundCRS from standard components, for example by adding a time axis to some standard CRS like
* "WGS84". The resulting CompoundCRS usually have no identifier. Then the users often need to extract a
* particular component of a CompoundCRS, most often the horizontal part, and will need its identifier
* for example in a Web Map Service (WMS). Those ID are lost if we do not format them here.
*/
if (parent == null || parent instanceof CompoundCRS) {
showIDs = true;
} else if (gp instanceof CoordinateOperation && !(parent instanceof IdentifiedObject)) {
// "SourceCRS[…]" and "TargetCRS[…]" sub-elements in CoordinateOperation.
showIDs = true;
} else if (convention == Convention.WKT2_SIMPLIFIED) {
showIDs = false;
} else {
showIDs = (object instanceof OperationMethod) || (object instanceof GeneralParameterDescriptor);
}
if (convention.majorVersion() == 1) {
filterID = true;
showOthers = false;
showRemarks = false;
} else {
filterID = (parent != null);
if (object instanceof CoordinateOperation) {
showOthers = !(parent instanceof ConcatenatedOperation);
showRemarks = showOthers;
} else if (object instanceof ReferenceSystem) {
showOthers = (parent == null);
showRemarks = (parent == null) || (gp instanceof CoordinateOperation);
} else {
// Mandated by ISO 19162.
showOthers = false;
showRemarks = false;
}
}
}
if (showOthers) {
appendForSubtypes(object);
}
if (showIDs) {
Collection<ReferenceIdentifier> identifiers = object.getIdentifiers();
if (identifiers != null) {
// Paranoiac check
if (filterID) {
for (final ReferenceIdentifier id : identifiers) {
if (Citations.identifierMatches(authority, id.getAuthority())) {
identifiers = Collections.singleton(id);
break;
}
}
}
for (ReferenceIdentifier id : identifiers) {
if (!(id instanceof FormattableObject)) {
id = ImmutableIdentifier.castOrCopy(id);
}
append((FormattableObject) id);
if (filterID)
break;
}
}
}
if (showRemarks) {
appendOnNewLine(WKTKeywords.Remark, object.getRemarks(), ElementKind.REMARKS);
}
isComplement = false;
}
use of org.opengis.parameter.GeneralParameterDescriptor in project sis by apache.
the class InverseOperationMethod method create.
/**
* Returns or create the inverse of the given operation method. If the same operation method can be used
* for the inverse operation either with the exact same parameter values or with the sign of some values
* reversed, then the given method is returned as-is. Otherwise a synthetic method is created.
*/
static OperationMethod create(final OperationMethod method) {
if (method instanceof InverseOperationMethod) {
return ((InverseOperationMethod) method).inverse;
}
if (!isInvertible(method)) {
boolean useSameParameters = false;
for (final GeneralParameterDescriptor descriptor : method.getParameters().descriptors()) {
useSameParameters = (descriptor.getRemarks() instanceof SignReversalComment);
if (!useSameParameters)
break;
}
if (!useSameParameters) {
Identifier name = method.getName();
name = new ImmutableIdentifier(null, null, "Inverse of " + name.getCode());
final Map<String, Object> properties = new HashMap<>(6);
properties.put(NAME_KEY, name);
properties.put(FORMULA_KEY, method.getFormula());
properties.put(REMARKS_KEY, method.getRemarks());
if (method instanceof Deprecable) {
properties.put(DEPRECATED_KEY, ((Deprecable) method).isDeprecated());
}
return new InverseOperationMethod(properties, method);
}
}
return method;
}
use of org.opengis.parameter.GeneralParameterDescriptor in project sis by apache.
the class CC_GeneralOperationParameter method merge.
/**
* Returns a descriptor with the given properties, completed with information not found in GML.
* Those extra information are given by the {@code complete} descriptor.
*
* @param caller the public source class to report if a log message need to be emitted.
* @param properties properties as declared in the GML document, to be used if {@code complete} is incompatible.
* @param merged more complete properties, to be used if {@code complete} is compatible.
* @param minimumOccurs value to assign to {@link DefaultParameterDescriptorGroup#getMinimumOccurs()}.
* @param maximumOccurs value to assign to {@link DefaultParameterDescriptorGroup#getMaximumOccurs()}.
* @param provided parameter descriptors declared in the GML document. This array will be overwritten.
* @param complete more complete parameter descriptors.
* @param canSubstitute {@code true} if this method is allowed to return {@code complete}.
* @return the parameter descriptor group to use (may be the {@code complete} instance).
*
* @see <a href="http://issues.apache.org/jira/browse/SIS-290">SIS-290</a>
*/
static ParameterDescriptorGroup merge(final Class<?> caller, final Map<String, ?> properties, final Map<String, ?> merged, final int minimumOccurs, final int maximumOccurs, final GeneralParameterDescriptor[] provided, final ParameterDescriptorGroup complete, boolean canSubstitute) {
boolean isCompatible = true;
final Set<GeneralParameterDescriptor> included = new HashSet<>(Containers.hashMapCapacity(provided.length));
for (int i = 0; i < provided.length; i++) {
final GeneralParameterDescriptor p = provided[i];
try {
/*
* Replace the descriptors provided in the GML document by descriptors from the 'complete' instance,
* if possible. Keep trace of the complete descriptors that we found in this process.
*/
GeneralParameterDescriptor predefined = complete.descriptor(p.getName().getCode());
if (predefined != null) {
// Safety in case 'complete' is a user's implementation.
canSubstitute &= (provided[i] = merge(p, predefined)) == predefined;
if (!included.add(predefined)) {
// Broken hashCode/equals, or object mutated.
throw new CorruptedObjectException(predefined);
}
continue;
}
} catch (ParameterNotFoundException e) {
/*
* Log at Level.WARNING for the first parameter (canSubstitute == true) and at Level.FINE
* for all other (canSubstitute == false). We do not use CC_GeneralOperationParameter as
* the source class because this is an internal class. We rather use the first public class
* in the caller hierarchy, which is either DefaultParameterValueGroup or DefaultOperationMethod.
*/
Context.warningOccured(Context.current(), caller, (caller == DefaultParameterValueGroup.class) ? "setValues" : "setDescriptors", e, canSubstitute);
}
/*
* If a parameter was not found in the 'complete' descriptor, we will not be able to use that descriptor.
* But we may still be able to use its properties (name, alias, identifier) provided that the parameter
* not found was optional.
*/
isCompatible &= p.getMinimumOccurs() == 0;
canSubstitute = false;
}
if (isCompatible) {
/*
* At this point, we determined that all mandatory parameters in the GML document exist in the 'complete'
* descriptor. However the converse is not necessarily true. Verify that all parameters missing in the GML
* document were optional.
*/
for (final GeneralParameterDescriptor descriptor : complete.descriptors()) {
if (!included.contains(descriptor) && descriptor.getMinimumOccurs() != 0 && !CC_OperationMethod.isImplicitParameter(descriptor)) {
canSubstitute = false;
isCompatible = false;
break;
}
}
}
if (canSubstitute) {
return complete;
} else {
return new DefaultParameterDescriptorGroup(isCompatible ? merged : properties, minimumOccurs, maximumOccurs, provided);
}
}
use of org.opengis.parameter.GeneralParameterDescriptor in project sis by apache.
the class ParameterValueList method ensureDescriptorExists.
/**
* Verifies the given descriptor exists in the {@link DefaultParameterDescriptorGroup#descriptors()} list.
*/
final void ensureDescriptorExists(final GeneralParameterDescriptor desc) {
final List<GeneralParameterDescriptor> descriptors = descriptor.descriptors();
if (!descriptors.contains(desc)) {
/*
* For a more accurate error message, check if the operation failed because the
* parameter name was not found, or the parameter descriptor does not matches.
*/
final Identifier name = desc.getName();
final String code = name.getCode();
for (final GeneralParameterDescriptor descriptor : descriptors) {
if (IdentifiedObjects.isHeuristicMatchForName(descriptor, code)) {
throw new IllegalArgumentException(Resources.format(Resources.Keys.MismatchedParameterDescriptor_1, name));
}
}
throw new InvalidParameterNameException(Resources.format(Resources.Keys.ParameterNotFound_2, Verifier.getDisplayName(descriptor), name), code);
}
}
use of org.opengis.parameter.GeneralParameterDescriptor in project sis by apache.
the class DefaultParameterValueGroup method groups.
/**
* Returns all subgroups with the specified name.
*
* <p>This method do not create new groups: if the requested group is optional (i.e.
* <code>{@linkplain DefaultParameterDescriptor#getMinimumOccurs() minimumOccurs} == 0</code>)
* and no value were defined previously, then this method returns an empty set.</p>
*
* @param name the name of the parameter to search for.
* @return the set of all parameter group for the given name.
* @throws ParameterNotFoundException if no descriptor was found for the given name.
*/
@Override
public List<ParameterValueGroup> groups(final String name) throws ParameterNotFoundException {
ArgumentChecks.ensureNonNull("name", name);
// Protect against accidental changes.
final ParameterValueList values = this.values;
final List<ParameterValueGroup> groups = new ArrayList<>(4);
final int size = values.size();
for (int i = 0; i < size; i++) {
final GeneralParameterDescriptor descriptor = values.descriptor(i);
if (descriptor instanceof ParameterDescriptorGroup) {
if (IdentifiedObjects.isHeuristicMatchForName(descriptor, name)) {
groups.add((ParameterValueGroup) values.get(i));
}
}
}
/*
* No groups were found. Check if the group actually exists (i.e. is declared in the
* descriptor). If it doesn't exists, then an exception is thrown. If it exists (i.e.
* it is simply an optional group not yet defined), then returns an empty list.
*/
if (groups.isEmpty()) {
final ParameterDescriptorGroup descriptor = values.descriptor;
if (!(descriptor.descriptor(name) instanceof ParameterDescriptorGroup)) {
throw new ParameterNotFoundException(Resources.format(Resources.Keys.ParameterNotFound_2, Verifier.getDisplayName(descriptor), name), name);
}
}
return groups;
}
Aggregations