use of eu.esdihumboldt.hale.common.schema.geometry.CRSDefinition in project hale by halestudio.
the class StreamGmlHelper method parseInstance.
/**
* Parses an instance with the given type from the given XML stream reader.
*
* @param reader the XML stream reader, the current event must be the start
* element of the instance
* @param type the definition of the instance type
* @param indexInStream the index of the instance in the stream or
* <code>null</code>
* @param strict if associating elements with properties should be done
* strictly according to the schema, otherwise a fall-back is
* used trying to populate values also on invalid property paths
* @param srsDimension the dimension of the instance or <code>null</code>
* @param crsProvider CRS provider in case no CRS is specified, may be
* <code>null</code>
* @param parentType the type of the topmost instance
* @param propertyPath the property path down from the topmost instance, may
* be <code>null</code>
* @param allowNull if a <code>null</code> result is allowed
* @param ignoreNamespaces if parsing of the XML instances should allow
* types and properties with namespaces that differ from those
* defined in the schema
* @param ioProvider the I/O Provider to get value
* @param crs The <code>CRSDefinition</code> to use for geometries
* @return the parsed instance, may be <code>null</code> if allowNull is
* <code>true</code>
* @throws XMLStreamException if parsing the instance failed
*/
public static Instance parseInstance(XMLStreamReader reader, TypeDefinition type, Integer indexInStream, boolean strict, Integer srsDimension, CRSProvider crsProvider, TypeDefinition parentType, List<QName> propertyPath, boolean allowNull, boolean ignoreNamespaces, IOProvider ioProvider, CRSDefinition crs) throws XMLStreamException {
checkState(reader.getEventType() == XMLStreamConstants.START_ELEMENT);
if (propertyPath == null) {
propertyPath = Collections.emptyList();
}
if (srsDimension == null) {
String dim = reader.getAttributeValue(null, "srsDimension");
if (dim != null)
srsDimension = Integer.parseInt(dim);
}
// extract additional settings from I/O provider
boolean suppressParsingGeometry = ioProvider.getParameter(StreamGmlReader.PARAM_SUPPRESS_PARSE_GEOMETRY).as(Boolean.class, false);
MutableInstance instance;
if (indexInStream == null) {
// not necessary to associate data set
instance = new DefaultInstance(type, null);
} else {
instance = new StreamGmlInstance(type, indexInStream);
}
// If the current instance has an srsName attribute, try to resolve the
// corresponding CRS and pass it down the hierarchy and use it for
// nested geometries that don't have their own srsName.
CRSDefinition lastCrs = crs;
String srsName = reader.getAttributeValue(null, "srsName");
if (srsName != null) {
lastCrs = CodeDefinition.tryResolve(srsName);
if (lastCrs == null && crsProvider != null) {
// In case the srsName value could not be resolved to a CRS, try
// to resolve the CRS via the crsProvider.
CRSDefinition unresolvedCrs = new CodeDefinition(srsName);
CRSDefinition resolvedCrs = crsProvider.getCRS(parentType, propertyPath, unresolvedCrs);
// unresolvedCrs unchanged
if (resolvedCrs != null && !resolvedCrs.equals(unresolvedCrs)) {
lastCrs = resolvedCrs;
}
}
// If the provided CRS could not be resolved, it will be ignored
// here silently, so that use cases that don't need the CRS will not
// fail.
}
boolean mixed = type.getConstraint(XmlMixedFlag.class).isEnabled();
if (!mixed) {
// mixed types are treated special (see else)
// check if xsi:nil attribute is there and set to true
String nilString = reader.getAttributeValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil");
boolean isNil = nilString != null && "true".equalsIgnoreCase(nilString);
// instance properties
parseProperties(reader, instance, strict, srsDimension, crsProvider, lastCrs, parentType, propertyPath, false, ignoreNamespaces, ioProvider);
// nil instance w/o properties
if (allowNull && isNil && Iterables.isEmpty(instance.getPropertyNames())) {
// no value should be created
/*
* XXX returning null here then results in problems during
* adding other properties to the parent group, as mandatory
* elements are expected to appear, and it will warn about
* possible invalid data loaded
*/
// return null;
}
// instance value
if (!hasElements(type)) {
/*
* Value can only be determined if there are no documents,
* because otherwise elements have already been processed in
* parseProperties and we are already past END_ELEMENT.
*/
if (type.getConstraint(HasValueFlag.class).isEnabled()) {
// try to get text value
String value = reader.getElementText();
if (!isNil && value != null) {
instance.setValue(convertSimple(type, value));
}
}
}
} else {
/*
* XXX For a mixed type currently ignore elements and parse only
* attributes and text.
*/
// instance properties (attributes only)
parseProperties(reader, instance, strict, srsDimension, crsProvider, lastCrs, parentType, propertyPath, true, ignoreNamespaces, ioProvider);
// combined text
String value = readText(reader);
if (value != null) {
instance.setValue(convertSimple(type, value));
}
}
// augmented value XXX should this be an else if?
if (!suppressParsingGeometry && type.getConstraint(AugmentedValueFlag.class).isEnabled()) {
// add geometry as a GeometryProperty value where applicable
GeometryFactory geomFactory = type.getConstraint(GeometryFactory.class);
Object geomValue = null;
// the default value for the srsDimension
int defaultValue = 2;
try {
if (srsDimension != null) {
geomValue = geomFactory.createGeometry(instance, srsDimension, ioProvider);
} else {
// srsDimension is not set
geomValue = geomFactory.createGeometry(instance, defaultValue, ioProvider);
}
} catch (Exception e) {
/*
* Catch IllegalArgumentException that e.g. occurs if a linear
* ring has to few points. NullPointerExceptions may occur
* because an internal geometry could not be created.
*
* XXX a problem is that these messages will not appear in the
* report
*/
log.error("Error creating geometry", e);
}
if (geomValue != null && crsProvider != null && propertyPath != null) {
// check if CRS are set, and if not, try determining them using
// the CRS provider
Collection<?> values;
if (geomValue instanceof Collection) {
values = (Collection<?>) geomValue;
} else {
values = Collections.singleton(geomValue);
}
List<Object> resultVals = new ArrayList<Object>();
for (Object value : values) {
if (value instanceof Geometry || (value instanceof GeometryProperty<?> && ((GeometryProperty<?>) value).getCRSDefinition() == null)) {
// try to resolve value of srsName attribute
CRSDefinition geometryCrs = crsProvider.getCRS(parentType, propertyPath, lastCrs);
if (geometryCrs != null) {
Geometry geom = (value instanceof Geometry) ? ((Geometry) value) : (((GeometryProperty<?>) value).getGeometry());
resultVals.add(new DefaultGeometryProperty<Geometry>(geometryCrs, geom));
continue;
}
}
resultVals.add(value);
}
if (resultVals.size() == 1) {
geomValue = resultVals.get(0);
} else {
geomValue = resultVals;
}
}
if (geomValue != null) {
instance.setValue(geomValue);
}
}
return instance;
}
use of eu.esdihumboldt.hale.common.schema.geometry.CRSDefinition in project hale by halestudio.
the class StreamGmlWriter method writeElement.
/**
* Write a property element.
*
* @param value the element value
* @param propDef the property definition
* @param report the reporter
* @throws XMLStreamException if writing the element fails
*/
private void writeElement(Object value, PropertyDefinition propDef, IOReporter report) throws XMLStreamException {
Group group = null;
if (value instanceof Group) {
group = (Group) value;
if (value instanceof Instance) {
// extract value from instance
value = ((Instance) value).getValue();
}
}
if (group == null) {
if (value == null) {
// null value
if (propDef.getConstraint(Cardinality.class).getMinOccurs() > 0) {
// write empty element
GmlWriterUtil.writeEmptyElement(writer, propDef.getName());
// mark as nil
writeElementValue(null, propDef);
}
// otherwise just skip it
} else {
GmlWriterUtil.writeStartElement(writer, propDef.getName());
Pair<Geometry, CRSDefinition> pair = extractGeometry(value, true, report);
if (pair != null) {
String srsName = extractCode(pair.getSecond());
// write geometry
writeGeometry(pair.getFirst(), propDef, srsName, report);
} else {
// simple element with value
// write value as content
writeElementValue(value, propDef);
}
writer.writeEndElement();
}
} else {
// children and maybe a value
GmlWriterUtil.writeStartElement(writer, propDef.getName());
boolean hasValue = propDef.getPropertyType().getConstraint(HasValueFlag.class).isEnabled();
Pair<Geometry, CRSDefinition> pair = extractGeometry(value, true, report);
// handle about annotated geometries
if (!hasValue && pair != null) {
String srsName = extractCode(pair.getSecond());
// write geometry
writeGeometry(pair.getFirst(), propDef, srsName, report);
} else {
boolean hasOnlyNilReason = hasOnlyNilReason(group);
// write no elements if there is a value or only a nil reason
boolean writeElements = !hasValue && !hasOnlyNilReason;
boolean isNil = !writeElements && (!hasValue || value == null);
// write all children
writeProperties(group, group.getDefinition(), writeElements, isNil, report);
// write value
if (hasValue) {
writeElementValue(value, propDef);
} else if (hasOnlyNilReason) {
// complex element with a nil value -> write xsi:nil if
// possible
/*
* XXX open question: should xsi:nil be there also if there
* are other attributes than nilReason?
*/
writeElementValue(null, propDef);
}
}
writer.writeEndElement();
}
}
use of eu.esdihumboldt.hale.common.schema.geometry.CRSDefinition in project hale by halestudio.
the class OrdinatesToPoint method evaluate.
/**
* @see eu.esdihumboldt.hale.common.align.transformation.function.impl.AbstractPropertyTransformation#evaluate(java.lang.String,
* eu.esdihumboldt.hale.common.align.transformation.engine.TransformationEngine,
* com.google.common.collect.ListMultimap,
* com.google.common.collect.ListMultimap, java.util.Map,
* eu.esdihumboldt.hale.common.align.transformation.report.TransformationLog)
*/
@Override
protected Object evaluate(String transformationIdentifier, TransformationEngine engine, ListMultimap<String, PropertyValue> variables, String resultName, PropertyEntityDefinition resultProperty, Map<String, String> executionParameters, TransformationLog log) throws TransformationException {
// get x, y and z properties
PropertyValue x = variables.get("x").get(0);
PropertyValue y = variables.get("y").get(0);
PropertyValue z = null;
if (!variables.get("z").isEmpty())
z = variables.get("z").get(0);
// get crs definition if srs is specified
CRSDefinition crsDef = null;
String srs = getOptionalParameter(PARAMETER_REFERENCE_SYSTEM, null).as(String.class);
if (srs != null)
crsDef = new CodeDefinition(srs, null);
// convert values to double and create a point
double xValue = x.getValueAs(Double.class);
double yValue = y.getValueAs(Double.class);
Point resultPoint;
GeometryFactory geomFactory = new GeometryFactory();
if (z == null)
resultPoint = geomFactory.createPoint(new Coordinate(xValue, yValue));
else
resultPoint = geomFactory.createPoint(new Coordinate(xValue, yValue, z.getValueAs(Double.class)));
// pack result into geometry property and return it
GeometryProperty<Point> result = new DefaultGeometryProperty<Point>(crsDef, resultPoint);
return result;
}
use of eu.esdihumboldt.hale.common.schema.geometry.CRSDefinition in project hale by halestudio.
the class ReprojectGeometry method evaluate.
@Override
protected Object evaluate(String transformationIdentifier, TransformationEngine engine, ListMultimap<String, PropertyValue> variables, String resultName, PropertyEntityDefinition resultProperty, Map<String, String> executionParameters, TransformationLog log) throws TransformationException, NoResultException {
// Get input geometry
PropertyValue input = variables.get("source").get(0);
Object inputValue = input.getValue();
InstanceTraverser traverser = new DepthFirstInstanceTraverser(true);
GeometryFinder geoFind = new GeometryFinder(null);
traverser.traverse(inputValue, geoFind);
List<GeometryProperty<?>> geoms = geoFind.getGeometries();
Geometry sourceGeometry = geoms.get(0).getGeometry();
CRSDefinition crsDef = geoms.get(0).getCRSDefinition();
if (crsDef == null) {
throw new TransformationException("Geometry does not have an associated Coordinate Reference System");
}
CoordinateReferenceSystem sourceCRS = crsDef.getCRS();
Geometry resultGeometry = sourceGeometry;
CoordinateReferenceSystem targetCRS = sourceCRS;
// Get input parameter
String srs = getParameterChecked(PARAMETER_REFERENCE_SYSTEM).as(String.class);
if (srs != null) {
try {
targetCRS = parseReferenceSystemParamter(srs);
} catch (Exception e) {
throw new TransformationException("Error determining destination Cordinate Reference System.", e);
}
// Retrieve transformation from cell context, or create a new
// instance
Map<Object, Object> cellContext = getExecutionContext().getCellContext();
MathTransform transform = getOrCreateMathTransform(sourceCRS, targetCRS, cellContext);
// Apply transformation
try {
resultGeometry = JTS.transform(sourceGeometry, transform);
} catch (MismatchedDimensionException | TransformException e) {
throw new TransformationException("Problem on execute transformation from: " + sourceCRS + " to " + targetCRS, e);
}
}
return new DefaultGeometryProperty<Geometry>(new CodeDefinition(CRS.toSRS(targetCRS), targetCRS), resultGeometry);
}
use of eu.esdihumboldt.hale.common.schema.geometry.CRSDefinition in project hale by halestudio.
the class AggregateTransformation method aggregateGeometries.
/**
* Aggregates geometries contained in the provided objects.
*
* @param geometries the geometries or instances containing geometries
* @param cell the currently process cell or <code>null</code>
* @param log the transformation log or <code>null</code>
* @return the aggregated geometry
* @throws TransformationException if source geometries don't have a common
* CRS
* @throws NoResultException if the result extent would be <code>null</code>
*/
public static GeometryProperty<?> aggregateGeometries(Iterable<?> geometries, @Nullable TransformationLog log, @Nullable Cell cell) throws NoResultException, TransformationException {
InstanceTraverser traverser = new DepthFirstInstanceTraverser(true);
GeometryFinder geoFind = new GeometryFinder(null);
CRSDefinition commonCrs = null;
Class<? extends Geometry> commonGeometryType = null;
List<Geometry> collectedGeometries = new ArrayList<>();
for (Object value : geometries) {
// find contained geometries
traverser.traverse(value, geoFind);
for (GeometryProperty<?> geom : geoFind.getGeometries()) {
// no CRS or one common CRS is OK
if (commonCrs == null) {
commonCrs = geom.getCRSDefinition();
} else {
if (geom.getCRSDefinition() != null && !geom.getCRSDefinition().equals(commonCrs)) {
// CRS doesn't match
throw new TransformationException("Source geometries don't have a common CRS.");
}
}
Geometry g = geom.getGeometry();
// determine common geometry type: point / line / polygon
if (commonGeometryType == null) {
commonGeometryType = getContainedGeometryType(g.getClass());
} else {
Class<? extends Geometry> currentType = getContainedGeometryType(g.getClass());
if (!commonGeometryType.isAssignableFrom(currentType)) {
if (currentType.isAssignableFrom(commonGeometryType)) {
commonGeometryType = currentType;
} else {
commonGeometryType = Geometry.class;
}
}
}
// collect geometry
for (int i = 0; i < g.getNumGeometries(); i++) {
collectedGeometries.add(g.getGeometryN(i));
}
}
geoFind.reset();
}
if (commonGeometryType != null && commonGeometryType.equals(Geometry.class)) {
if (log != null && cell != null) {
log.warn(new TransformationMessageImpl(cell, "Could not find common geometry type for aggregation", null));
}
}
if (commonGeometryType != null) {
Geometry combined = combineGeometries(collectedGeometries, commonGeometryType);
return new DefaultGeometryProperty<Geometry>(commonCrs, combined);
}
throw new NoResultException();
}
Aggregations