Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package au.org.aodn.ogcapi.server.core.model;

import au.org.aodn.ogcapi.features.model.*;
import au.org.aodn.ogcapi.features.model.FeatureCollectionGeoJSON;
import au.org.aodn.ogcapi.features.model.FeatureGeoJSON;
import au.org.aodn.ogcapi.features.model.PointGeoJSON;
import au.org.aodn.ogcapi.server.core.model.enumeration.FeatureProperty;
import lombok.Getter;
import au.org.aodn.ogcapi.server.core.util.DatasetSummarizer;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Getter
public class DatasetSearchResult {

private final FeatureCollectionGeoJSON dataset;
Expand All @@ -24,6 +25,12 @@ private void initDataset() {
dataset.setFeatures(new ArrayList<>());
}

public FeatureCollectionGeoJSON getSummarizedDataset() {
var summarizer = new DatasetSummarizer(dataset);
summarizer.summarizeDataset();
return summarizer.getSummarizedDataset();
}

public void addDatum(DatumModel datum) {

if (datum == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ public enum FeatureProperty {
TIME("time"),
DEPTH("depth"),
COUNT("count"),
UUID("uuid")
UUID("uuid"),
START_TIME("startTime"),
END_TIME("endTime"),
COORDINATE_ACCURACY("coordinateAccuracy"),
;

private final String value;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package au.org.aodn.ogcapi.server.core.util;

import au.org.aodn.ogcapi.features.model.FeatureCollectionGeoJSON;
import au.org.aodn.ogcapi.features.model.FeatureGeoJSON;
import au.org.aodn.ogcapi.features.model.PointGeoJSON;
import au.org.aodn.ogcapi.server.core.model.enumeration.FeatureProperty;
import lombok.Getter;

import java.time.YearMonth;
import java.util.HashMap;
import java.util.Map;

public class DatasetSummarizer {

private final FeatureCollectionGeoJSON dataset;

@Getter
private final FeatureCollectionGeoJSON summarizedDataset;

public DatasetSummarizer(FeatureCollectionGeoJSON dataset) {
this.dataset = dataset;
this.summarizedDataset = new FeatureCollectionGeoJSON();
this.summarizedDataset.setType(FeatureCollectionGeoJSON.TypeEnum.FEATURECOLLECTION);
summarizeDataset();
}


public void summarizeDataset() {
for (var feature : dataset.getFeatures()) {
var sameLocationFeature = getSameLocationFeature(feature);
if (sameLocationFeature == null) {
summarizedDataset
.getFeatures()
.add(generateNewSummarizedFeature(feature));
continue;
}
var newFeature = aggregateFeature(sameLocationFeature, feature);
summarizedDataset.getFeatures().remove(sameLocationFeature);
summarizedDataset.getFeatures().add(newFeature);
}
}

@SuppressWarnings("unchecked")
private FeatureGeoJSON aggregateFeature(FeatureGeoJSON existingFeature, FeatureGeoJSON featureToAdd) {
var aggregatedFeature = new FeatureGeoJSON();
aggregatedFeature.setType(FeatureGeoJSON.TypeEnum.FEATURE);
aggregatedFeature.setGeometry(existingFeature.getGeometry());

try{
var existingProperties = (Map<String, Object>) existingFeature.getProperties();

var newTimeStr = getTime(featureToAdd);
var timeUpdatedProperties = updateTimeRange(existingProperties, newTimeStr);

var newCount = getCount(featureToAdd);
var timeAndCountUpdatedProperties = updateCount(timeUpdatedProperties, newCount);

aggregatedFeature.setProperties(timeAndCountUpdatedProperties);
} catch (ClassCastException e) {
throw new RuntimeException("Feature properties is not a map", e);
}
return aggregatedFeature;
}

private Map<String, Object> updateCount(Map<String, Object> existingProperties, Long newCount) {
var existingCount = (Long) existingProperties.get(FeatureProperty.COUNT.getValue());
var updatedProperties = new HashMap<>(existingProperties);
updatedProperties.put(FeatureProperty.COUNT.getValue(), existingCount + newCount);
return updatedProperties;
}

private Map<String, Object> updateTimeRange(Map<String, Object> existingProperties, String newTimeStr) {

var startTimeStr = (String) existingProperties.get(FeatureProperty.START_TIME.getValue());
var endTimeStr = (String) existingProperties.get(FeatureProperty.END_TIME.getValue());

var updatedProperties = new HashMap<>(existingProperties);
updatedProperties.remove(FeatureProperty.TIME.getValue());
if (newTimeStr != null) {
var newTime = YearMonth.parse(newTimeStr);
var startTime = YearMonth.parse(startTimeStr);
var endTime = YearMonth.parse(endTimeStr);
if (newTime.isBefore(startTime)) {
startTimeStr = newTimeStr;
} else if (newTime.isAfter(endTime)) {
endTimeStr = newTimeStr;
}
updatedProperties.put(FeatureProperty.START_TIME.getValue(), startTimeStr);
updatedProperties.put(FeatureProperty.END_TIME.getValue(), endTimeStr);
}
return updatedProperties;
}


private FeatureGeoJSON generateNewSummarizedFeature(FeatureGeoJSON feature) {
var summarizedFeature = new FeatureGeoJSON();
summarizedFeature.setType(FeatureGeoJSON.TypeEnum.FEATURE);
summarizedFeature.setGeometry(feature.getGeometry());
summarizedFeature.setProperties(feature.getProperties());
var time = getTime(feature);
setPropertyToFeature(feature, FeatureProperty.START_TIME , time);
setPropertyToFeature(feature, FeatureProperty.END_TIME , time);

return summarizedFeature;
}

@SuppressWarnings("unchecked")
private void setPropertyToFeature(
FeatureGeoJSON feature, FeatureProperty propertyType, String value
) {
try{
var properties = (Map<String, Object>) feature.getProperties();
properties.put(propertyType.getValue(), value);
} catch (ClassCastException e) {
throw new RuntimeException("Feature properties is not a map", e);
}
}

@SuppressWarnings("unchecked")
private Object getPropertyFromFeature(FeatureGeoJSON feature, FeatureProperty propertyType) {
try{
var properties = (Map<String, Object>) feature.getProperties();
return properties.get(propertyType.getValue());
} catch (ClassCastException e) {
throw new RuntimeException("Feature properties is not a map", e);
}
}

private Long getCount(FeatureGeoJSON feature) {
try {
return (Long) getPropertyFromFeature(feature, FeatureProperty.COUNT);
} catch (Exception e) {
throw new RuntimeException("failed to get count from feature", e);
}
}

private String getTime(FeatureGeoJSON feature) {
try {
return (String) getPropertyFromFeature(feature, FeatureProperty.TIME);
} catch (Exception e) {
throw new RuntimeException("failed to get time from feature", e);
}
}


private FeatureGeoJSON getSameLocationFeature(FeatureGeoJSON feature) {
for (var f : summarizedDataset.getFeatures()) {
try {
var existingCoordinates = ((PointGeoJSON) f.getGeometry()).getCoordinates();
var newCoordinates = ((PointGeoJSON) feature.getGeometry()).getCoordinates();
if (existingCoordinates.get(0).equals(newCoordinates.get(0)) && existingCoordinates.get(1).equals(newCoordinates.get(1))) {
return f;
}
} catch (ClassCastException e) {
throw new RuntimeException("Feature geometry is not a point", e);
}
}
return null;
}


}

// following are values from experience. can change
//1 decimal place: ~11.1 kilometers
//2 decimal places: ~1.1 kilometers
//3 decimal places: ~110 meters
//4 decimal places: ~11 meters
//5 decimal places: ~1.1 meters

// zoom level less than 7.3, 1 decimal place
// zoom level less than 4, integer
// zoom level less than 1.2, 10
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ public ResponseEntity<FeatureCollectionGeoJSON> getFeatures(

@PathVariable("collectionId") String collectionId,
@RequestParam(value = "start_datetime", required = false) String startDate,
@RequestParam(value = "end_datetime", required = false) String endDate
@RequestParam(value = "end_datetime", required = false) String endDate,
// keep these two parameters for future usage
@RequestParam(value= "zoom", required = false) Double zoomLevel,
@RequestParam(value="bbox", required = false) List<BigDecimal> bbox
) {
return featuresService.getDataset(collectionId, startDate, endDate);
return featuresService.getSummarizedDataset(collectionId, startDate, endDate);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ public ResponseEntity<Collection> getCollection(String id, String sortBy) throws
}
}

public ResponseEntity<FeatureCollectionGeoJSON> getDataset(
public ResponseEntity<FeatureCollectionGeoJSON> getSummarizedDataset(
String collectionId,
String startDate,
String endDate
) {
try {
var result = search.searchDataset(collectionId, startDate, endDate);
return ResponseEntity.ok()
.body(result.getDataset());
.body(result.getSummarizedDataset());
} catch (Exception e) {
log.error("Error while getting dataset", e);
return ResponseEntity.internalServerError().build();
Expand Down