use of eu.esdihumboldt.hale.common.instance.geometry.GeometryFinder in project hale by halestudio.
the class StreamGmlWriter method partitionByExtent.
private void partitionByExtent(ProgressIndicator progress, IOReporter reporter) throws IOException {
int maxNodes = getParameter(PARAM_PARTITION_BY_EXTENT_MAX_NODES).as(Integer.class, 1000);
String mode = getParameter(PARAM_PARTITION_BY_EXTENT_MODE).as(String.class, PARTITION_BY_EXTENT_MODE_DATASET);
final SubtaskProgressIndicator qtProgress = new SubtaskProgressIndicator(progress) {
@Override
protected String getCombinedTaskName(String taskName, String subtaskName) {
return taskName + " (" + subtaskName + ")";
}
};
// Map for instances that either contain no or multiple geometries
Map<String, InstanceReference> unhandledInstances = new HashMap<>();
QuadtreeBuilder<Point, InstanceReference> builder = new QuadtreeBuilder<>();
try (ResourceIterator<Instance> it = getInstances().iterator()) {
qtProgress.begin("Collecting geometries", getInstances().size());
final XMLInspector gadget = new XMLInspector();
int i = 0;
while (it.hasNext()) {
Instance inst = it.next();
InstanceReference instRef = getInstances().getReference(inst);
InstanceTraverser traverser = new DepthFirstInstanceTraverser();
GeometryFinder finder = new GeometryFinder(getTargetCRS());
traverser.traverse(inst, finder);
List<GeometryProperty<?>> geoms = finder.getGeometries();
if (geoms.isEmpty() || geoms.size() > 1) {
unhandledInstances.put(gadget.getIdentity(inst), instRef);
} else {
GeometryProperty<?> geomProperty = geoms.get(0);
Geometry geom = geomProperty.getGeometry();
Point centroid;
switch(mode) {
case PARTITION_BY_EXTENT_MODE_WORLD:
CoordinateReferenceSystem sourceCrs = geomProperty.getCRSDefinition().getCRS();
CodeDefinition wgs84 = new CodeDefinition("EPSG:4326");
try {
MathTransform toWgs84 = CRS.findMathTransform(sourceCrs, wgs84.getCRS());
Geometry geomWgs84 = JTS.transform(geom, toWgs84);
centroid = geomWgs84.getCentroid();
} catch (FactoryException | MismatchedDimensionException | TransformException e) {
log.error("Unable to transform geometry to WGS 84", e);
throw new IllegalStateException(e.getMessage(), e);
}
break;
case PARTITION_BY_EXTENT_MODE_DATASET:
// fall through to default
default:
centroid = geom.getCentroid();
}
builder.add(centroid, new IdentifiableInstanceReference(instRef, gadget.getIdentity(inst)));
}
qtProgress.advance(1);
if (++i % 100 == 0) {
qtProgress.setCurrentTask(MessageFormat.format("{0} instances processed", i));
}
}
qtProgress.setCurrentTask("Building quadtree");
FixedBoundaryQuadtree<InstanceReference> qt;
switch(mode) {
case PARTITION_BY_EXTENT_MODE_DATASET:
qt = builder.build(maxNodes);
break;
case PARTITION_BY_EXTENT_MODE_WORLD:
Envelope world = new Envelope(-180, 180, -90, 90);
qt = builder.build(maxNodes, world);
break;
default:
log.error(MessageFormat.format("Unrecognized extent partitioning mode \"{0}\", using dataset boundaries", mode));
qt = builder.build(maxNodes);
}
qtProgress.setCurrentTask("Performing spatial partitioning");
final Map<String, String> idToKeyMapping = new HashMap<>();
final Map<String, Collection<InstanceReference>> keyToRefsMapping = new HashMap<>();
// Instances without geometry or with multiple geometries
keyToRefsMapping.put(ExtentPartsHandler.KEY_NO_GEOMETRY, unhandledInstances.values());
unhandledInstances.keySet().stream().forEach(id -> idToKeyMapping.put(id, ExtentPartsHandler.KEY_NO_GEOMETRY));
buildMappings(qt, idToKeyMapping, keyToRefsMapping);
// Partition source instances based on quadtree tiles
Iterator<InstanceCollection> collIt = new Iterator<InstanceCollection>() {
private final Queue<String> keySet = new LinkedList<>(keyToRefsMapping.keySet());
@Override
public boolean hasNext() {
return !keySet.isEmpty();
}
@Override
public InstanceCollection next() {
String key = keySet.poll();
Collection<InstanceReference> refs = keyToRefsMapping.get(key);
InstanceCollection instColl = new DefaultInstanceCollection(refs.stream().map(ref -> getInstances().getInstance(IdentifiableInstanceReference.getRootReference(ref))).collect(Collectors.toList()));
return new ExtentPartsHandler.TreeKeyDecorator(instColl, key);
}
};
final Map<String, URI> keyToTargetMapping = new HashMap<>();
keyToRefsMapping.keySet().stream().forEach(k -> keyToTargetMapping.put(k, new File(ExtentPartsHandler.getTargetFilename(k, getTarget().getLocation())).toURI()));
final ExtentPartsHandler handler = new ExtentPartsHandler(keyToTargetMapping, idToKeyMapping);
qtProgress.end();
try {
writeParts(collIt, handler, progress, reporter);
} catch (XMLStreamException e) {
throw new IOException(e.getMessage(), e);
}
}
}
use of eu.esdihumboldt.hale.common.instance.geometry.GeometryFinder in project hale by halestudio.
the class JacksonMapper method streamWriteGeoJSONInstance.
/**
* Writes a single instance as GeoJSON.
*
* @param instance the instance to write
* @param config the default geometry config
* @param reporter the reporter
* @throws IOException if writing the instance fails
*/
private void streamWriteGeoJSONInstance(Instance instance, GeoJSONConfig config, IOReporter reporter) throws IOException {
jsonGen.writeStartObject();
jsonGen.writeStringField("type", "Feature");
PropertyEntityDefinition geomProperty = config.getDefaultGeometry(instance.getDefinition());
GeometryFinder geomFinder = new GeometryFinder(null);
// check whether a geometry property is set
if (geomProperty != null) {
// find all occurrences of the property
Collection<Object> values = AlignmentUtil.getValues(instance, geomProperty, false);
// find all geometries below any value (the values themselves might
// be geometries)
InstanceTraverser traverser = new DepthFirstInstanceTraverser(true);
for (Object value : values) traverser.traverse(value, geomFinder);
}
Collection<GeometryProperty<?>> geometries = geomFinder.getGeometries();
if (!geometries.isEmpty()) {
// XXX It would be better to put CRS to each geometry.
// This is currently not possible because geotools doesn't support
// this.
GeometryProperty<?> geomProp = geometries.iterator().next();
if (geomProp.getCRSDefinition() != null) {
jsonGen.writeFieldName("crs");
jsonGen.writeRawValue(new FeatureJSON().toString(geomProp.getCRSDefinition().getCRS()));
}
}
jsonGen.writeFieldName("geometry");
if (geometries.isEmpty())
jsonGen.writeNull();
else if (geometries.size() == 1)
streamWriteGeometryValue(geometries.iterator().next().getGeometry());
else {
jsonGen.writeStartObject();
jsonGen.writeStringField("type", "GeometryCollection");
jsonGen.writeArrayFieldStart("geometries");
for (GeometryProperty<?> geom : geometries) streamWriteGeometryValue(geom.getGeometry());
jsonGen.writeEndArray();
jsonGen.writeEndObject();
}
jsonGen.writeFieldName("properties");
jsonGen.writeStartObject();
jsonGen.writeStringField("_type", instance.getDefinition().getName().getLocalPart());
streamWriteProperties(instance, reporter);
jsonGen.writeEndObject();
jsonGen.writeEndObject();
}
use of eu.esdihumboldt.hale.common.instance.geometry.GeometryFinder in project hale by halestudio.
the class AbstractHandlerTest method checkSingleGeometry.
/**
* Check a single geometry contained in an instance (at an arbitrary path).
*
* @param instance the geometry instance
* @param checker the checker (should throw an exception when the check
* fails)
* @return the collection of encountered geometries
*/
protected Collection<GeometryProperty<?>> checkSingleGeometry(Instance instance, @Nullable Consumer<Geometry> checker) {
GeometryFinder finder = new GeometryFinder(null);
BreadthFirstInstanceTraverser traverser = new BreadthFirstInstanceTraverser();
traverser.traverse(instance, finder);
List<GeometryProperty<?>> geoms = finder.getGeometries();
assertFalse("No geometry found in instances", geoms.isEmpty());
assertEquals("More than one geometry found in instance", 1, geoms.size());
Geometry geom = geoms.get(0).getGeometry();
if (checker != null) {
checker.accept(geom);
}
return geoms;
}
use of eu.esdihumboldt.hale.common.instance.geometry.GeometryFinder in project hale by halestudio.
the class SpatialIndexInstanceProcessor method process.
/**
* @see eu.esdihumboldt.hale.common.instance.processing.InstanceProcessor#process(eu.esdihumboldt.hale.common.instance.model.Instance,
* eu.esdihumboldt.hale.common.instance.model.InstanceReference)
*/
@Override
public void process(Instance instance, InstanceReference reference) {
SpatialIndexService<Localizable, Localizable> index = getSpatialIndexService();
final GeometryFinder finder = new GeometryFinder(null);
InstanceTraverser traverser = new DepthFirstInstanceTraverser(true);
traverser.traverse(instance, finder);
final List<Geometry> geometries = new ArrayList<>();
for (GeometryProperty<?> property : finder.getGeometries()) {
Geometry g = property.getGeometry();
for (int i = 0; i < g.getNumGeometries(); i++) {
geometries.add(g.getGeometryN(i));
}
}
final BoundingBox boundingBox = new BoundingBox();
for (Geometry geometry : geometries) {
boundingBox.add(BoundingBox.compute(geometry));
}
if (boundingBox.checkIntegrity()) {
TypedInstanceReference typedRef = new TypedInstanceReference(reference, instance.getDefinition());
index.insert(new LocalizableInstanceReference(typedRef, boundingBox));
}
}
use of eu.esdihumboldt.hale.common.instance.geometry.GeometryFinder in project hale by halestudio.
the class CalculateLength method evaluate.
/**
* @see eu.esdihumboldt.hale.common.align.transformation.function.impl.AbstractSingleTargetPropertyTransformation#evaluate(java.lang.String,
* eu.esdihumboldt.hale.common.align.transformation.engine.TransformationEngine,
* com.google.common.collect.ListMultimap, java.lang.String,
* eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition,
* 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, NoResultException {
// get input geometry
PropertyValue input = variables.get(null).get(0);
Object inputValue = input.getValue();
// depth first traverser that on cancel continues traversal but w/o the
// children of the current object
InstanceTraverser traverser = new DepthFirstInstanceTraverser(true);
GeometryFinder geoFind = new GeometryFinder(null);
traverser.traverse(inputValue, geoFind);
List<GeometryProperty<?>> geoms = geoFind.getGeometries();
Geometry geom = null;
if (geoms.size() > 1) {
int length = 0;
for (GeometryProperty<?> geoProp : geoms) {
length += geoProp.getGeometry().getLength();
}
return length;
} else {
geom = geoms.get(0).getGeometry();
}
if (geom != null) {
return geom.getLength();
} else {
throw new TransformationException("Geometry for calculate length could not be retrieved.");
}
}
Aggregations