Search in sources :

Example 1 with GeneralParameterDescriptor

use of org.opengis.parameter.GeneralParameterDescriptor in project sis by apache.

the class SingleOperationMarshallingTest method verifyMethod.

/**
 * Verifies the unmarshalled parameter descriptors.
 */
private static void verifyMethod(final OperationMethod method) {
    assertIdentifierEquals("name", null, null, null, "Mercator (1SP)", method.getName());
    assertEquals("formula", "See EPSG guide.", method.getFormula().getFormula().toString());
    assertEquals("sourceDimensions", Integer.valueOf(2), method.getSourceDimensions());
    assertEquals("targetDimensions", Integer.valueOf(2), method.getTargetDimensions());
    final ParameterDescriptorGroup parameters = method.getParameters();
    assertEquals("parameters.name", "Mercator (1SP)", parameters.getName().getCode());
    final Iterator<GeneralParameterDescriptor> it = parameters.descriptors().iterator();
    CC_OperationParameterGroupTest.verifyMethodParameter(Mercator1SP.LATITUDE_OF_ORIGIN, (ParameterDescriptor<?>) it.next());
    CC_OperationParameterGroupTest.verifyMethodParameter(Mercator1SP.LONGITUDE_OF_ORIGIN, (ParameterDescriptor<?>) it.next());
    assertFalse("Unexpected parameter.", it.hasNext());
}
Also used : ParameterDescriptorGroup(org.opengis.parameter.ParameterDescriptorGroup) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor)

Example 2 with GeneralParameterDescriptor

use of org.opengis.parameter.GeneralParameterDescriptor 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()]);
}
Also used : GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) ParameterDescriptor(org.opengis.parameter.ParameterDescriptor) DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) ParameterDescriptorGroup(org.opengis.parameter.ParameterDescriptorGroup) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) CorruptedObjectException(org.apache.sis.util.CorruptedObjectException) LinkedHashMap(java.util.LinkedHashMap)

Example 3 with GeneralParameterDescriptor

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;
}
Also used : ReferenceIdentifier(org.opengis.referencing.ReferenceIdentifier) CompoundCRS(org.opengis.referencing.crs.CompoundCRS) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) CoordinateOperation(org.opengis.referencing.operation.CoordinateOperation) ConcatenatedOperation(org.opengis.referencing.operation.ConcatenatedOperation) IdentifiedObject(org.opengis.referencing.IdentifiedObject) ReferenceSystem(org.opengis.referencing.ReferenceSystem) OperationMethod(org.opengis.referencing.operation.OperationMethod)

Example 4 with GeneralParameterDescriptor

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;
}
Also used : ImmutableIdentifier(org.apache.sis.metadata.iso.ImmutableIdentifier) Identifier(org.opengis.metadata.Identifier) HashMap(java.util.HashMap) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) SignReversalComment(org.apache.sis.internal.referencing.SignReversalComment) InternationalString(org.opengis.util.InternationalString) ImmutableIdentifier(org.apache.sis.metadata.iso.ImmutableIdentifier) Deprecable(org.apache.sis.util.Deprecable)

Example 5 with GeneralParameterDescriptor

use of org.opengis.parameter.GeneralParameterDescriptor in project sis by apache.

the class CC_GeneralOperationParameterTest method testGroupMergeBecauseDifferentProperties.

/**
 * Tests case where the unmarshalled parameter group needs to be merged with the complete parameter group.
 * The reason for the group merge in this test is because the unmarshalled parameters have different remarks
 * or different obligation.
 *
 * @throws JAXBException if this method failed to create test data.
 */
@Test
@DependsOnMethod({ "testGroupSubstitution", "testParameterMerge" })
public void testGroupMergeBecauseDifferentProperties() throws JAXBException {
    final Map<String, String> properties = new HashMap<>(4);
    assertNull(properties.put(DefaultParameterDescriptor.NAME_KEY, "Group"));
    final ParameterDescriptorGroup provided = new DefaultParameterDescriptorGroup(properties, 1, 2, unmarshal("Parameter A", "Remarks A."), unmarshal("Parameter B", "Remarks B."), unmarshal("Parameter C", "Remarks C."));
    assertNull(properties.put(DefaultParameterDescriptor.REMARKS_KEY, "More details here."));
    final ParameterDescriptorGroup complete = new DefaultParameterDescriptorGroup(properties, 1, 2, create("Parameter A", "Remarks A.", true, 3), create("Parameter B", "Remarks B.", false, 4), create("Parameter C", "Different.", false, 5), create("Parameter D", "Remarks D.", false, 6));
    final ParameterDescriptorGroup merged = (ParameterDescriptorGroup) CC_GeneralOperationParameter.merge(provided, complete);
    assertNotSame(complete, provided);
    assertSame("name", complete.getName(), merged.getName());
    assertSame("remarks", complete.getRemarks(), merged.getRemarks());
    assertEquals("minimumOccurs", 1, merged.getMinimumOccurs());
    assertEquals("maximumOccurs", 2, merged.getMaximumOccurs());
    final Iterator<GeneralParameterDescriptor> itc = complete.descriptors().iterator();
    final Iterator<GeneralParameterDescriptor> itm = merged.descriptors().iterator();
    // Not same because different obligation.
    verifyParameter(itc.next(), itm.next(), false, "Remarks A.");
    // Same ParameterDescriptor instance.
    verifyParameter(itc.next(), itm.next(), true, "Remarks B.");
    // Not same because different remarks.
    verifyParameter(itc.next(), itm.next(), false, "Remarks C.");
    assertTrue("Missing descriptor.", itc.hasNext());
    assertFalse("Unexpected descriptor.", itm.hasNext());
}
Also used : DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) HashMap(java.util.HashMap) DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) ParameterDescriptorGroup(org.opengis.parameter.ParameterDescriptorGroup) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) Test(org.junit.Test) DependsOnMethod(org.apache.sis.test.DependsOnMethod)

Aggregations

GeneralParameterDescriptor (org.opengis.parameter.GeneralParameterDescriptor)30 ParameterDescriptorGroup (org.opengis.parameter.ParameterDescriptorGroup)12 Test (org.junit.Test)10 DefaultParameterDescriptorGroup (org.apache.sis.parameter.DefaultParameterDescriptorGroup)8 DependsOnMethod (org.apache.sis.test.DependsOnMethod)8 ParameterNotFoundException (org.opengis.parameter.ParameterNotFoundException)6 ParameterValueGroup (org.opengis.parameter.ParameterValueGroup)6 HashMap (java.util.HashMap)5 Identifier (org.opengis.metadata.Identifier)5 GeneralParameterValue (org.opengis.parameter.GeneralParameterValue)5 ParameterDescriptor (org.opengis.parameter.ParameterDescriptor)4 IdentityHashMap (java.util.IdentityHashMap)3 OperationMethod (org.opengis.referencing.operation.OperationMethod)3 ArrayList (java.util.ArrayList)2 DefaultParameterValueGroup (org.apache.sis.parameter.DefaultParameterValueGroup)2 CorruptedObjectException (org.apache.sis.util.CorruptedObjectException)2 InvalidParameterNameException (org.opengis.parameter.InvalidParameterNameException)2 ParameterValue (org.opengis.parameter.ParameterValue)2 Collection (java.util.Collection)1 HashSet (java.util.HashSet)1