Skip to content

Commit

Permalink
Get items in the temporal context from static catalog
Browse files Browse the repository at this point in the history
  • Loading branch information
inigo-cobian committed Jan 7, 2025
1 parent 9af651f commit c174980
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import java.io.IOException;
import java.io.OutputStream;
import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -11,6 +13,7 @@
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.data.FeatureSource;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.hortonmachine.gears.io.stac.HMStacAsset;
import org.hortonmachine.gears.io.stac.HMStacCollection;
import org.hortonmachine.gears.io.stac.HMStacItem;
import org.hortonmachine.gears.io.stac.HMStacManager;
Expand Down Expand Up @@ -43,7 +46,9 @@
import org.integratedmodelling.klab.exceptions.KlabIllegalStateException;
import org.integratedmodelling.klab.exceptions.KlabInternalErrorException;
import org.integratedmodelling.klab.exceptions.KlabResourceAccessException;
import org.integratedmodelling.klab.exceptions.KlabResourceNotFoundException;
import org.integratedmodelling.klab.exceptions.KlabUnimplementedException;
import org.integratedmodelling.klab.exceptions.KlabValidationException;
import org.integratedmodelling.klab.ogc.STACAdapter;
import org.integratedmodelling.klab.ogc.vector.files.VectorEncoder;
import org.integratedmodelling.klab.raster.files.RasterEncoder;
Expand All @@ -52,6 +57,7 @@
import org.integratedmodelling.klab.stac.extensions.STACIIASAExtension;
import org.integratedmodelling.klab.utils.s3.S3URLUtils;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Polygon;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
Expand Down Expand Up @@ -180,6 +186,12 @@ private AmazonS3 buildS3Client(String bucketRegion) throws IOException {
return s3Client;
}

private boolean isDateInsideRange(Time rangeTime, Date date) {
long rangeStart = rangeTime.getStart().getMilliseconds();
long rangeEnd = rangeTime.getEnd().getMilliseconds();
return (rangeStart <= date.getTime() && rangeEnd <= date.getTime());
}

@Override
public void getEncodedData(IResource resource, Map<String, String> urnParameters, IGeometry geometry, Builder builder,
IContextualizationScope scope) {
Expand All @@ -188,19 +200,20 @@ public void getEncodedData(IResource resource, Map<String, String> urnParameters
String collectionId = collectionData.getString("id");
String catalogUrl = STACUtils.getCatalogUrl(collectionUrl, collectionId, collectionData);
JSONObject catalogData = STACUtils.requestMetadata(catalogUrl, "catalog");
String assetId = resource.getParameters().get("asset", String.class);

boolean hasSearchOption = STACUtils.containsLinkTo(catalogData, "search");
// This is part of a WIP that will be removed in the future
boolean isIIASA = catalogUrl.contains("iiasa.blob");
if (!hasSearchOption && !isIIASA) {
// TODO implement how to read static collections
throw new KlabUnimplementedException("Cannot read a static collection.");
}

Space space = (Space) geometry.getDimensions().stream().filter(d -> d instanceof Space)
.findFirst().orElseThrow();
IEnvelope envelope = space.getEnvelope();
List<Double> bbox = List.of(envelope.getMinX(), envelope.getMaxX(), envelope.getMinY(), envelope.getMaxY());
Time time = (Time) geometry.getDimensions().stream().filter(d -> d instanceof Time)
.findFirst().orElseThrow();
Time resourceTime = (Time) Scale.create(resource.getGeometry()).getDimension(Type.TIME);

if (isIIASA) {
FeatureSource<SimpleFeatureType, SimpleFeature> source;
try {
Expand All @@ -213,6 +226,32 @@ public void getEncodedData(IResource resource, Map<String, String> urnParameters
return;
}

if (!hasSearchOption) {
List<SimpleFeature> features = getFeaturesFromStaticCollection(collectionUrl, collectionData, collectionId);
Time time2 = time; //TODO make the time and query time different
features = features.stream().filter(f -> {
Geometry fGeometry = (Geometry) f.getDefaultGeometry();
return fGeometry.intersects(space.getShape().getJTSGeometry());
}).toList();
features = features.stream().filter(f -> isFeatureInTimeRange(time2, f)).toList();
if (features.isEmpty()) {
throw new KlabResourceNotFoundException("There are no items in this context for the collection " + collectionId);
}
List<HMStacAsset> assets = features.stream().map(f -> {
try {
return HMStacItem.fromSimpleFeature(f).getAssetForBand(assetId);
} catch (Exception e) {
throw new KlabIOException("Cannot get item from feature. Reason " + e.getMessage());
}
}).toList();
HMStacAsset asset = assets.stream().filter(as -> as.getId().equals(assetId)).findFirst().get();
HMRaster.fromGridCoverage(null);
encoder = new RasterEncoder();
GridCoverage2D coverage = null;
// TODO get coverage from the raster
((RasterEncoder)encoder).encodeFromCoverage(resource, urnParameters, coverage, geometry, builder, scope);
}

LogProgressMonitor lpm = new LogProgressMonitor();
HMStacManager manager = new HMStacManager(catalogUrl, lpm);
HMStacCollection collection = null;
Expand All @@ -236,10 +275,6 @@ public void getEncodedData(IResource resource, Map<String, String> urnParameters
Polygon poly = GeometryUtilities.createPolygonFromEnvelope(env);
collection.setGeometryFilter(poly);

Time time = (Time) geometry.getDimensions().stream().filter(d -> d instanceof Time)
.findFirst().orElseThrow();
Time resourceTime = (Time) Scale.create(resource.getGeometry()).getDimension(Type.TIME);

if (resourceTime.getStart() != null && resourceTime.getEnd() != null && resourceTime.getCoveredExtent() > 0) {
time = validateTemporalDimension(time, resourceTime);
}
Expand Down Expand Up @@ -286,7 +321,6 @@ public void getEncodedData(IResource resource, Map<String, String> urnParameters
// Allow transform ensures the process to finish, but I would not bet on the resulting
// data.
final boolean allowTransform = true;
String assetId = resource.getParameters().get("asset", String.class);
HMRaster outRaster = collection.readRasterBandOnRegion(regionTransformed, assetId, items, allowTransform, mergeMode, lpm);
coverage = outRaster.buildCoverage();
manager.close();
Expand All @@ -297,6 +331,40 @@ public void getEncodedData(IResource resource, Map<String, String> urnParameters
((RasterEncoder)encoder).encodeFromCoverage(resource, urnParameters, coverage, geometry, builder, scope);
}

private boolean isFeatureInTimeRange(Time time2, SimpleFeature f) {
Date datetime = (Date) f.getAttribute("datetime");
if (datetime != null) {
if (isDateInsideRange(time2, datetime)) {
return true;
}
}

Date itemStart = (Date) f.getAttribute("start_datetime");
if (itemStart == null) {
return false;
}
Date itemEnd = (Date) f.getAttribute("end_datetime");
if (itemEnd == null) {
return itemStart.toInstant().getEpochSecond() <= time2.getStart().getMilliseconds();
}
if (isDateInsideRange(time2, itemStart) || isDateInsideRange(time2, itemEnd)) {
return false;
}
return true;
}

private List<SimpleFeature> getFeaturesFromStaticCollection(String collectionUrl, JSONObject collectionData, String collectionId) {
List<JSONObject> links = collectionData.getJSONArray("links").toList().stream().filter(link -> ((JSONObject)link).getString("rel").equalsIgnoreCase("item")).toList();
List<String> urlOfLinks = links.stream().map(link -> STACUtils.getUrlOfItem(collectionUrl, collectionId, link.getString("href"))).toList();
return urlOfLinks.stream().map(i -> {
try {
return STACUtils.getItemAsFeature(i);
} catch (Exception e) {
throw new KlabValidationException("Item at " + i + " cannot be parsed.");
}
}).toList();
}

@Override
public void listDetail(IResource resource, OutputStream stream, boolean verbose, IMonitor monitor) {
// TODO Auto-generated method stub
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package org.integratedmodelling.klab.stac;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.geotools.data.geojson.GeoJSONReader;
import org.integratedmodelling.klab.api.provenance.IArtifact.Type;
import org.integratedmodelling.klab.exceptions.KlabResourceAccessException;
import org.integratedmodelling.klab.utils.DOIReader;
import org.opengis.feature.simple.SimpleFeature;

import com.fasterxml.jackson.core.JsonParseException;

import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
Expand Down Expand Up @@ -125,9 +130,21 @@ public static String getCatalogUrl(String collectionUrl, String collectionId, JS
throw new KlabResourceAccessException("STAC collection is missing a relationship to the root catalog");
}
String href = rootLink.get().getString("href");
return getUrlOfItem(collectionUrl, collectionId, href);
}

public static String getUrlOfItem(String collectionUrl, String collectionId, String href) {
if (href.startsWith("..")) {
return collectionUrl.replace("/collection.json", "").replace(collectionId, "") + href.replace("../", "");
}
if (href.startsWith(".")) {
return collectionUrl.replace("collection.json", "") + href.replace("./", "");
}
return href;
}

public static SimpleFeature getItemAsFeature(String itemUrl) throws JsonParseException, IOException {
HttpResponse<JsonNode> response = Unirest.get(itemUrl).asJson();
return GeoJSONReader.parseFeature(response.getBody().toString());
}
}

0 comments on commit c174980

Please sign in to comment.