use of org.opengis.metadata.Identifier in project sis by apache.
the class ProvidersTest method ensureParameterUniqueness.
/**
* Ensures that every parameter instance is unique. Actually this test is not strong requirement.
* This is only for sharing existing resources by avoiding unnecessary objects duplication.
*
* @throws ReflectiveOperationException if the instantiation of a service provider failed.
*/
@Test
public void ensureParameterUniqueness() throws ReflectiveOperationException {
final Map<GeneralParameterDescriptor, String> groupNames = new IdentityHashMap<>();
final Map<GeneralParameterDescriptor, GeneralParameterDescriptor> parameters = new HashMap<>();
final Map<Object, Object> namesAndIdentifiers = new HashMap<>();
for (final Class<?> c : methods()) {
final OperationMethod method = (OperationMethod) c.newInstance();
final ParameterDescriptorGroup group = method.getParameters();
final String operationName = group.getName().getCode();
for (final GeneralParameterDescriptor param : group.descriptors()) {
assertFalse("Parameter declared twice in the same group.", operationName.equals(groupNames.put(param, operationName)));
/*
* Ensure uniqueness of the parameter descriptor as a whole.
*/
final Identifier name = param.getName();
Object existing = parameters.put(param, param);
if (existing != null && existing != param) {
fail("Parameter “" + name.getCode() + "” defined in “" + operationName + '”' + " was already defined in “" + groupNames.get(existing) + "”." + " The same instance could be shared.");
}
/*
* Ensure uniqueness of each name and identifier.
*/
existing = namesAndIdentifiers.put(name, name);
if (existing != null && existing != name) {
fail("The name of parameter “" + name.getCode() + "” defined in “" + operationName + '”' + " was already defined elsewhere. The same instance could be shared.");
}
for (final GenericName alias : param.getAlias()) {
existing = namesAndIdentifiers.put(alias, alias);
if (existing != null && existing != alias) {
fail("Alias “" + alias + "” of parameter “" + name.getCode() + "” defined in “" + operationName + '”' + " was already defined elsewhere. The same instance could be shared.");
}
}
for (final Identifier id : param.getIdentifiers()) {
existing = namesAndIdentifiers.put(id, id);
if (existing != null && existing != id) {
fail("Identifier “" + id + "” of parameter “" + name.getCode() + "” defined in “" + operationName + '”' + " was already defined elsewhere. The same instance could be shared.");
}
}
}
}
}
use of org.opengis.metadata.Identifier in project sis by apache.
the class DefaultAggregateInformation method setAggregateDataSetIdentifier.
/**
* Sets the identification information about aggregate dataset.
*
* @param newValue the new identifier.
*
* @deprecated As of ISO 19115:2014, replaced by an identifier of {@link #getAggregateDataSetName()}.
*/
@Deprecated
public void setAggregateDataSetIdentifier(final Identifier newValue) {
checkWritePermission();
Citation name = getAggregateDataSetName();
if (newValue != null) {
if (!(name instanceof DefaultCitation)) {
name = new DefaultCitation(name);
setAggregateDataSetName(name);
}
/*
* If there is more than one value, replace only the first one and keep all other ones unchanged.
* The intent is to be consistent with the getter method, which returns the first element.
*/
final ArrayList<Identifier> identifiers = new ArrayList<>(name.getIdentifiers());
if (identifiers.isEmpty()) {
identifiers.add(newValue);
} else {
identifiers.set(0, newValue);
}
((DefaultCitation) name).setIdentifiers(identifiers);
} else if (name != null) {
final Iterator<? extends Identifier> it = name.getIdentifiers().iterator();
if (it.hasNext()) {
it.next();
it.remove();
}
}
}
use of org.opengis.metadata.Identifier in project sis by apache.
the class Proj4 method definition.
/**
* Infers a {@literal Proj.4} definition from the given projected, geographic or geocentric coordinate reference system.
* This method does not need the Proj.4 native library; it can be used in a pure Java application.
* However the returned definition string may differ depending on whether the Proj.4 library is available or not.
*
* @param crs the coordinate reference system for which to create a Proj.4 definition.
* @return the definition of the given CRS in a Proj.4 format.
* @throws FactoryException if the Proj.4 definition string can not be created from the given CRS.
*/
public static String definition(final CoordinateReferenceSystem crs) throws FactoryException {
ArgumentChecks.ensureNonNull("crs", crs);
/*
* If the given CRS object is associated to a Proj.4 structure, let Proj.4 formats itself
* the definition string. Note that this operation may fail if there is no Proj.4 library
* in the current system, or no JNI bindings to that library.
*/
try {
for (final Identifier id : crs.getIdentifiers()) {
if (id instanceof PJ) {
return ((PJ) id).getCode();
}
}
} catch (UnsatisfiedLinkError e) {
// Thrown the first time that we try to use the library.
Logging.unexpectedException(Logging.getLogger(Modules.GDAL), Proj4.class, "definition", e);
} catch (NoClassDefFoundError e) {
// Thrown on all attempts after the first one.
Logging.recoverableException(Logging.getLogger(Modules.GDAL), Proj4.class, "definition", e);
}
/*
* If we found no Proj.4 structure, formats the definition string ourself. The string may differ from
* what Proj.4 would have given. In particular, we do not provide "+init=" or "+datum=" parameter.
* But the definition should still be semantically equivalent.
*/
final String method;
final GeodeticDatum datum;
final ParameterValueGroup parameters;
final CoordinateSystem cs = crs.getCoordinateSystem();
if (crs instanceof GeodeticCRS) {
if (cs instanceof EllipsoidalCS) {
method = "latlon";
} else if (cs instanceof CartesianCS) {
method = "geocent";
} else {
throw new FactoryException(Errors.format(Errors.Keys.UnsupportedCoordinateSystem_1, cs.getClass()));
}
datum = ((GeodeticCRS) crs).getDatum();
parameters = null;
} else if (crs instanceof ProjectedCRS) {
Projection c = ((ProjectedCRS) crs).getConversionFromBase();
datum = ((ProjectedCRS) crs).getDatum();
method = name(c.getMethod());
parameters = c.getParameterValues();
} else {
throw new FactoryException(Errors.format(Errors.Keys.UnsupportedType_1, crs.getClass()));
}
/*
* Append the map projection parameters. Those parameters may include axis lengths (a and b),
* but not necessarily. If axis lengths are specified, then we will ignore the Ellipsoid instance
* associated to the CRS.
*/
final StringBuilder definition = new StringBuilder(100);
definition.append(Proj4Factory.PROJ_PARAM).append(method);
boolean hasSemiMajor = false;
boolean hasSemiMinor = false;
if (parameters != null) {
definition.append(Proj4Factory.STANDARD_OPTIONS);
for (final GeneralParameterValue parameter : parameters.values()) {
if (parameter instanceof ParameterValue<?>) {
final ParameterValue<?> pv = (ParameterValue<?>) parameter;
final Object value;
Unit<?> unit = pv.getUnit();
if (unit != null) {
unit = Units.isAngular(unit) ? Units.DEGREE : unit.getSystemUnit();
// Always in metres or degrees.
value = pv.doubleValue(unit);
} else {
value = pv.getValue();
if (value == null) {
continue;
}
}
final String pn = name(parameter.getDescriptor());
hasSemiMajor |= pn.equals("a");
hasSemiMinor |= pn.equals("b");
definition.append(" +").append(pn).append('=').append(value);
}
}
}
/*
* Append datum information: axis lengths if they were not part of the parameters, then prime meridian.
*/
final Ellipsoid ellipsoid = datum.getEllipsoid();
if (!hasSemiMajor)
definition.append(" +a=").append(ellipsoid.getSemiMajorAxis());
if (!hasSemiMinor)
definition.append(" +b=").append(ellipsoid.getSemiMinorAxis());
final PrimeMeridian pm = datum.getPrimeMeridian();
if (pm != null) {
double lon = pm.getGreenwichLongitude();
final Unit<Angle> unit = pm.getAngularUnit();
if (unit != null) {
lon = unit.getConverterTo(Units.DEGREE).convert(lon);
}
definition.append(" +pm=").append(lon);
}
/*
* Appends axis directions. This method always format a vertical direction (up or down)
* even if the coordinate system is two-dimensional, because Proj.4 seems to require it.
* Also extract axis units in the process.
*/
// Horizontal at index 0, vertical at index 1.
final Unit<?>[] units = new Unit<?>[2];
boolean validCS = true;
definition.append(' ').append(Proj4Factory.AXIS_ORDER_PARAM);
final int dimension = Math.min(cs.getDimension(), 3);
boolean hasVertical = false;
for (int i = 0; i < dimension; i++) {
final CoordinateSystemAxis axis = cs.getAxis(i);
final AxisDirection dir = axis.getDirection();
int unitIndex = 0;
if (!AxisDirections.isCardinal(dir)) {
if (!AxisDirections.isVertical(dir)) {
throw new FactoryException(Errors.format(Errors.Keys.UnsupportedAxisDirection_1, dir));
}
hasVertical = true;
unitIndex = 1;
}
final Unit<?> old = units[unitIndex];
units[unitIndex] = axis.getUnit();
validCS &= (old == null || old.equals(units[unitIndex]));
definition.appendCodePoint(Character.toLowerCase(dir.name().codePointAt(0)));
}
if (!hasVertical && dimension < 3) {
// Add a UP direction if not already present.
definition.append('u');
}
/*
* Append units of measurement, then verify the coordinate system validity.
*/
for (int i = 0; i < units.length; i++) {
final Unit<?> unit = units[i];
if (unit != null && !unit.equals(Units.DEGREE) && !unit.equals(Units.METRE)) {
validCS &= Units.isLinear(unit);
definition.append(" +");
// "+vto_meter" parameter.
if (i == 1)
definition.append('v');
definition.append("to_meter=").append(Units.toStandardUnit(unit));
}
}
/*
* Append the "+towgs84" element if any. This is the last piece of information.
* Note that the use of a "+towgs84" parameter is an "early binding" approach,
* which is usually not recommended. But Proj4 works that way.
*/
if (validCS) {
if (datum instanceof DefaultGeodeticDatum) {
for (final BursaWolfParameters bwp : ((DefaultGeodeticDatum) datum).getBursaWolfParameters()) {
if (Utilities.equalsIgnoreMetadata(CommonCRS.WGS84.datum(), bwp.getTargetDatum())) {
definition.append(" +towgs84=").append(bwp.tX).append(',').append(bwp.tY).append(',').append(bwp.tZ);
if (!bwp.isTranslation()) {
definition.append(',').append(bwp.rX).append(',').append(bwp.rY).append(',').append(bwp.rZ).append(',').append(bwp.dS);
}
break;
}
}
}
return definition.toString();
}
/*
* If we reach this point, we detected a coordinate system that we can not format as a
* Proj.4 definition string. Format an error message with axis directions and units.
*/
definition.setLength(0);
definition.append('(');
for (int i = 0; i < units.length; i++) {
final CoordinateSystemAxis axis = cs.getAxis(i);
if (i != 0)
definition.append(", ");
definition.append(axis.getUnit()).append(' ').append(Types.getCodeName(axis.getDirection()));
}
throw new FactoryException(Errors.format(Errors.Keys.IllegalCoordinateSystem_1, definition.append(')')));
}
use of org.opengis.metadata.Identifier in project sis by apache.
the class Proj4Factory method createOperation.
/**
* Creates an operation for conversion or transformation between two coordinate reference systems.
* The given CRSs should be instances {@linkplain #createCoordinateReferenceSystem created by this factory}.
* If not, then there is a choice:
*
* <ul>
* <li>If {@code force} is {@code false}, then this method returns {@code null}.</li>
* <li>Otherwise this method always uses Proj.4 for performing the coordinate operations,
* regardless if the given CRS were created from Proj.4 definition strings or not.
* This method fails if it can not map the given CRS to Proj.4 data structures.</li>
* </ul>
*
* @param sourceCRS the source coordinate reference system.
* @param targetCRS the target coordinate reference system.
* @param force whether to force the creation of a Proj.4 transform
* even if the given CRS are not wrappers around Proj.4 data structures.
* @return a coordinate operation for transforming coordinates from the given source CRS to the given target CRS, or
* {@code null} if the given CRS are not wrappers around Proj.4 data structures and {@code force} is false.
* @throws FactoryException if {@code force} is {@code true} and this method can not create Proj.4 transform
* for the given pair of coordinate reference systems.
*
* @see Proj4#createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem, boolean)
* @see DefaultCoordinateOperationFactory#createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem)
*/
public CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS, final boolean force) throws FactoryException {
final PJ source, target;
try {
if ((source = unwrapOrCreate(sourceCRS, force)) == null || (target = unwrapOrCreate(targetCRS, force)) == null) {
// At least one CRS is not a Proj.4 wrapper and 'force' is false.
return null;
}
} catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
throw new UnavailableFactoryException(Proj4.unavailable(e), e);
}
/*
* Before to create a transform, verify if the target CRS already contains a suitable transform.
* In such case, returning the existing operation is preferable since it usually contains better
* parameter description than what this method build.
*/
if (targetCRS instanceof GeneralDerivedCRS) {
final CoordinateOperation op = ((GeneralDerivedCRS) targetCRS).getConversionFromBase();
final MathTransform tr = op.getMathTransform();
if (tr instanceof Transform && ((Transform) tr).isFor(sourceCRS, source, targetCRS, target)) {
return op;
}
}
/*
* The 'Transform' construction implies parameter validation, so we do it first before to
* construct other objects.
*/
final Transform tr = new Transform(source, is3D("sourceCRS", sourceCRS), target, is3D("targetCRS", targetCRS));
Identifier id;
String src = null, tgt = null, name = UNNAMED;
if ((id = sourceCRS.getName()) != null)
src = id.getCode();
if ((id = targetCRS.getName()) != null)
tgt = id.getCode();
if (src != null || tgt != null) {
final StringBuilder buffer = new StringBuilder();
if (src != null)
buffer.append("From ").append(src);
if (tgt != null)
buffer.append(buffer.length() == 0 ? "To " : " to ").append(tgt);
name = buffer.toString();
}
return opFactory().createSingleOperation(identifier(name), sourceCRS, targetCRS, null, Transform.METHOD, tr);
}
use of org.opengis.metadata.Identifier in project sis by apache.
the class Proj4Factory method identifier.
/**
* Returns the identifier for the given code in {@literal Proj.4} namespace.
*/
private Map<String, Object> identifier(final String code) {
Identifier id = identifiers.computeIfAbsent(code, (k) -> {
short i18n = 0;
if (k.equalsIgnoreCase(UNNAMED))
i18n = Vocabulary.Keys.Unnamed;
if (k.equalsIgnoreCase("Unknown"))
i18n = Vocabulary.Keys.Unknown;
return new ImmutableIdentifier(Citations.PROJ4, Constants.PROJ4, k, null, (i18n != 0) ? Vocabulary.formatInternational(i18n) : null);
});
final Map<String, Object> properties = new HashMap<>(defaultProperties);
properties.put(IdentifiedObject.NAME_KEY, id);
return properties;
}
Aggregations