diff --git a/src/main/java/org/gcube/dataanalysis/geo/retrieval/GeoIntersector.java b/src/main/java/org/gcube/dataanalysis/geo/retrieval/GeoIntersector.java index 243b829..582e72b 100644 --- a/src/main/java/org/gcube/dataanalysis/geo/retrieval/GeoIntersector.java +++ b/src/main/java/org/gcube/dataanalysis/geo/retrieval/GeoIntersector.java @@ -1,8 +1,7 @@ package org.gcube.dataanalysis.geo.retrieval; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; @@ -12,10 +11,17 @@ import org.gcube.dataanalysis.ecoengine.signals.SignalProcessing; import org.gcube.dataanalysis.ecoengine.utils.Tuple; import org.gcube.dataanalysis.geo.meta.features.FeaturesManager; import org.gcube.dataanalysis.geo.utils.EnvDataExplorer; +import org.gcube.dataanalysis.geo.utils.FeaturedPolygon; import org.gcube.dataanalysis.geo.utils.ThreddsDataExplorer; import org.opengis.metadata.Metadata; import org.opengis.metadata.identification.Identification; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.PrecisionModel; +import com.vividsolutions.jts.geom.impl.CoordinateArraySequence; + public class GeoIntersector { private FeaturesManager featurer; @@ -88,18 +94,30 @@ public class GeoIntersector { } */ } else { - //TODO: adjust WFS take AnalysisLogger.getLogger().debug("found a Geo Layer with title " + layerTitle + " and layer name " + layer); - /* - for (Tuple triplet : triplets) { - double x = triplet.getElements().get(0); - double y = triplet.getElements().get(1); - AnalysisLogger.getLogger().debug("Taking point: (" + x + "," + y + ")"); - LinkedHashMap features = new LinkedHashMap(); - features = getFeaturesFromWFS(featurer.getWFSLink(meta), layer, x, y); - featuresSets.add(features); - } - */ +// AnalysisLogger.getLogger().debug("Taking point: (" + x + "," + y + ")"); + List featuresInTime = new ArrayList(); + AnalysisLogger.getLogger().debug("taking WFS features"); + featuresInTime = getFeaturesFromWFS(featurer.getGeoserverLink(meta), layer, xL,yL, xR, yR); + AnalysisLogger.getLogger().debug("Intersecting "+triplets.size()+" vs "+featuresInTime.size() +" elements"); + for (Tuple triplet:triplets){ + GeometryFactory factory = new GeometryFactory(new PrecisionModel(), 4326); + CoordinateArraySequence pcoords = new CoordinateArraySequence(new Coordinate[] { new Coordinate(triplet.getElements().get(0),triplet.getElements().get(1)),}); + Point po = new Point(pcoords, factory); + boolean found = false; + for (FeaturedPolygon poly:featuresInTime){ + + if (poly.p.covers(po)){ +// System.out.println(po+" intersected by "+poly.p); + features.add(poly.value); + found = true; + break; + } + + } + if (!found) + features.add(Double.NaN); + } } } return features; @@ -119,14 +137,21 @@ public class GeoIntersector { return ThreddsDataExplorer.retrieveDataFromNetCDF(opendapURL, layer, x, y, z); } - private LinkedHashMap getFeaturesFromWFS(String wfsUrl, String layer, double x, double y) { - if (wfsUrl == null) + private LinkedHashMap getFeaturesFromWFS(String geoserverUrl, String layer, double x, double y) { + if (geoserverUrl == null) return null; - return EnvDataExplorer.getFeatures(wfsUrl, layer, x, y); + return EnvDataExplorer.getFeatures(geoserverUrl, layer, x, y); } - public double[][] takeLastTimeChunk(String layerTitle, double x1, double x2, double y1, double y2, double z, double xResolution, double yResolution) throws Exception { + private List getFeaturesFromWFS(String geoserverUrl, String layer, double xL,double yL,double xR, double yR) { + if (geoserverUrl == null) + return null; + + return EnvDataExplorer.getFeatures(geoserverUrl, layer, xL,yL,xR, yR); + } + + public double[][] takeTimeSlice(String layerTitle, int timeInstant, double x1, double x2, double y1, double y2, double z, double xResolution, double yResolution) throws Exception { AnalysisLogger.getLogger().debug("Bounding box: (" + x1 + "," + x2 + ";" + y1 + "," + y2 + ")"); if ((x2 < x1) || (y2 < y1)) { AnalysisLogger.getLogger().debug("ERROR: BAD BOUNDING BOX!!!"); @@ -152,17 +177,17 @@ public class GeoIntersector { } AnalysisLogger.getLogger().debug("Taking " + ysteps + " values per "+xsteps+"="+(ysteps*xsteps)+ "..."); - List time = getFeaturesInTimeInstant(layerTitle, 0, tuples, x1, x2, y1,y2); - AnalysisLogger.getLogger().debug("Taken " + time.size() + " values"); + List timeValues = getFeaturesInTimeInstant(layerTitle, timeInstant, tuples, x1, x2, y1,y2); + AnalysisLogger.getLogger().debug("Taken " + timeValues.size() + " values"); // build back the values matrix int k = 0; int g = 0; - int ntriplets = time.size(); + int ntriplets = timeValues.size(); //cycle on all the triplets to recontruct the matrix for (int t = 0; t < ntriplets; t++) { //take the corresponding (time,value) pair - Double value = time.get(t); + Double value = timeValues.get(t); //if there is value, then set it, otherwise set NaN //the layer is undefined in that point and a value must be generated //assign a value to the matrix diff --git a/src/main/java/org/gcube/dataanalysis/geo/test/TestChunkization.java b/src/main/java/org/gcube/dataanalysis/geo/test/TestChunkization.java index 8ef2f14..e8b4373 100644 --- a/src/main/java/org/gcube/dataanalysis/geo/test/TestChunkization.java +++ b/src/main/java/org/gcube/dataanalysis/geo/test/TestChunkization.java @@ -14,9 +14,9 @@ public class TestChunkization { long t0 = System.currentTimeMillis(); AnalysisLogger.setLogger(cfg+AlgorithmConfiguration.defaultLoggerFile); GeoIntersector intersector = new GeoIntersector(null, cfg); -// intersector.takeLastTimeChunk(layertitle, -180, 180, -10, 10, 0, 1, 1); - intersector.takeLastTimeChunk(layertitle, -10, 10, -10, 10, 0,1, 1); -// intersector.takeLastTimeChunk(layertitle, -180, 180, -90, 90, 0, 1, 1); +// intersector.takeTimeSlice(layertitle, 0, -180, 180, -10, 10, 0, 1, 1); +// intersector.takeTimeSlice(layertitle, 0, -10, 10, -10, 10, 0,1, 1); + intersector.takeTimeSlice(layertitle, 0, -180, 180, -90, 90, 0, 0.5, 0.5); System.out.println("ELAPSED TIME: "+(System.currentTimeMillis()-t0)); } } diff --git a/src/main/java/org/gcube/dataanalysis/geo/test/TestChunkizationLayer.java b/src/main/java/org/gcube/dataanalysis/geo/test/TestChunkizationLayer.java new file mode 100644 index 0000000..0ebd093 --- /dev/null +++ b/src/main/java/org/gcube/dataanalysis/geo/test/TestChunkizationLayer.java @@ -0,0 +1,21 @@ +package org.gcube.dataanalysis.geo.test; + +import org.gcube.contentmanagement.lexicalmatcher.utils.AnalysisLogger; +import org.gcube.dataanalysis.ecoengine.configuration.AlgorithmConfiguration; +import org.gcube.dataanalysis.geo.retrieval.GeoIntersector; + +public class TestChunkizationLayer { + + static String cfg = "./cfg/"; + public static void main(String[] args) throws Exception{ + String layertitle = "MyDistributionMap"; +// String layertitle = "Mass Concentration of Chlorophyll in Sea Water in [03-30-13 01:00] (3D) {Mercator Ocean BIOMER1V1R1: Data extracted from dataset http://atoll-mercator.vlandata.cls.fr:44080/thredds/dodsC/global-analysis-bio-001-008-a}"; +// String layertitle = "Objectively Analyzed Climatology in [07-01-01 01:00] (3D) {World Ocean Atlas 09: Sea Water Temperature - annual: dods://thredds.research-infrastructures.eu/thredds/dodsC/public/netcdf/temperature_annual_1deg_ENVIRONMENT_OCEANS_.nc}"; + long t0 = System.currentTimeMillis(); + AnalysisLogger.setLogger(cfg+AlgorithmConfiguration.defaultLoggerFile); + GeoIntersector intersector = new GeoIntersector(null, cfg); +// intersector.takeTimeSlice(layertitle, 0, -10, 10, -10, 10, 0,1, 1); + intersector.takeTimeSlice(layertitle, 0, -180, 180, -90, 90, 0, 0.5, 0.5); + System.out.println("ELAPSED TIME: "+(System.currentTimeMillis()-t0)); + } +} diff --git a/src/main/java/org/gcube/dataanalysis/geo/utils/EnvDataExplorer.java b/src/main/java/org/gcube/dataanalysis/geo/utils/EnvDataExplorer.java index 84ab299..5285edf 100644 --- a/src/main/java/org/gcube/dataanalysis/geo/utils/EnvDataExplorer.java +++ b/src/main/java/org/gcube/dataanalysis/geo/utils/EnvDataExplorer.java @@ -1,18 +1,48 @@ package org.gcube.dataanalysis.geo.utils; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import org.gcube.contentmanagement.graphtools.utils.HttpRequest; import org.gcube.contentmanagement.lexicalmatcher.utils.AnalysisLogger; import org.gcube.dataanalysis.geo.meta.OGCFormatter; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.PrecisionModel; +import com.vividsolutions.jts.geom.impl.CoordinateArraySequence; + public class EnvDataExplorer { private static String callWFS(String geoServer, String layer, double x, double y) { float tolerance = 0.25f; - String wfsURL = OGCFormatter.getWfsUrl(geoServer, layer, OGCFormatter.pointToBoundingBox(x, y, tolerance), 1, "json"); + String wfsURL = OGCFormatter.getWfsUrl(geoServer, layer, OGCFormatter.pointToBoundingBox(x, y, tolerance), 1, "json"); + AnalysisLogger.getLogger().debug("EnvDataExplorer-> Requesting URL: " + wfsURL); + String returned = null; + try { + returned = HttpRequest.sendGetRequest(wfsURL, null); + } catch (Exception e) { + AnalysisLogger.getLogger().debug("EnvDataExplorer-> ERROR " + e.getLocalizedMessage()); + } + if (returned != null) + AnalysisLogger.getLogger().debug("EnvDataExplorer-> Found Intersection: " + returned); + else + AnalysisLogger.getLogger().debug("EnvDataExplorer-> Found Nothing!"); + + return returned; + } + + private static String callWFS(String geoServer, String layer, double xL, double yL, double xR, double yR) { + + // String wfsURL = OGCFormatter.getWfsUrl(geoServer, layer, OGCFormatter.buildBoundingBox(xL, yL, xR, yR), 0, "json"); + // there is a bug in WFS in the retrieval according to a bounding box: y must be in the range -180;180. then I preferred to take all the features + String wfsURL = OGCFormatter.getWfsUrl(geoServer, layer, null, 0, "json"); AnalysisLogger.getLogger().debug("EnvDataExplorer-> Requesting URL: " + wfsURL); String returned = null; try { @@ -30,11 +60,12 @@ public class EnvDataExplorer { public static LinkedHashMap getFeatures(String geoserver, String layer, double x, double y) { try { + AnalysisLogger.getLogger().debug("Calling WFS towards Geoserver:" + geoserver + " and layer:" + layer); String jsonString = callWFS(geoserver, layer, x, y); LinkedHashMap map = JsonMapper.parse(jsonString); LinkedHashMap mapout = (LinkedHashMap) ((HashMap) map.get("features")).get("properties"); - LinkedHashMap values = new LinkedHashMap(); - for (String key:mapout.keySet()){ + LinkedHashMap values = new LinkedHashMap(); + for (String key : mapout.keySet()) { values.put(key, Double.parseDouble(mapout.get(key))); } return values; @@ -43,4 +74,144 @@ public class EnvDataExplorer { return null; } } + + public static List getFeatures(String geoserver, String layer, double xL, double yL, double xR, double yR) { + try { + AnalysisLogger.getLogger().debug("Calling WFS towards Geoserver:" + geoserver + " and layer:" + layer); + String jsonString = callWFS(geoserver, layer, xL, yL, xR, yR); + // System.out.println("JSON:"+jsonString); + LinkedHashMap map = JsonMapper.parse(jsonString); + List fpolygons = new ArrayList(); + FeaturedPolygon poly = null; + for (String key : map.keySet()) { + if (key.contains("features")) { + HashMap propertiesMap = (HashMap) map.get(key); + + //cycle on all the properties + for (String properties : propertiesMap.keySet()) { + if (properties.contains("properties")) { + if (poly==null) + poly=new FeaturedPolygon(); + + LinkedHashMap props = (LinkedHashMap) propertiesMap.get(properties); + //fill the properties of the fpolygon + for (String keyprop : props.keySet()) { + try { + //fulfill the FeaturedPolygon + String value = props.get(keyprop); + try{ + String lowcaseprop = keyprop.toLowerCase(); + if ((poly.value==null) && + !lowcaseprop.startsWith("id")&& + !lowcaseprop.endsWith("id")) + poly.setValue(Double.parseDouble(value)); + else + poly.addFeature(keyprop, value); + }catch (Exception e2){ + poly.addFeature(keyprop, value); + } + } catch (Exception e) { + } + } + } + else + if (properties.contains("geometry") && !properties.contains("geometry_")) { + + if (poly==null) + poly=new FeaturedPolygon(); + else if (poly.p!=null){ + if (poly.value==null) + poly.value=Double.NaN; + fpolygons.add(poly); + poly=new FeaturedPolygon(); + } + + LinkedHashMap props = (LinkedHashMap) propertiesMap.get(properties); + List coords = WFS2Coordinates(props.toString()); + GeometryFactory factory = new GeometryFactory(new PrecisionModel(), 4326); + Polygon p = null; + if (coords != null) { + Coordinate[] coordarray = new Coordinate[coords.size()]; + int i=0; + for (double[] pair:coords){ + coordarray[i] = new Coordinate(pair[0],pair[1]); + i++; + } + CoordinateArraySequence coordseq = new CoordinateArraySequence(coordarray); + LinearRing ring = new LinearRing(coordseq, factory); + p = new Polygon(ring, new LinearRing[] {}, factory); + } + poly.setPolygon(p); + } + + + } + } + }// end for on all the wfs + + if (poly!=null){ + if (poly.value==null) + poly.value=Double.NaN; + fpolygons.add(poly); + } + return fpolygons; + } catch (Exception e) { + AnalysisLogger.getLogger().debug("EnvDataExplorer-> Error in getting properties"); + return null; + } + } + + public static List WFS2Coordinates(String wfsgeometry) { + + // geometry935133b1-ba3c-493d-8e18-6fb496ced995={type=MultiPolygon, coordinates={966a275c-23aa-4a43-a943-7e1c7eaf5d65=[[[1.5,125.00000000000011],[1.5,124.5],[2.000000000000057,124.5],[2.000000000000057,125.00000000000011],[1.5,125.00000000000011]]]}}, + String[] coordinatePairs = null; + List dpairs = new ArrayList(); + if (wfsgeometry.toLowerCase().contains("multipolygon")) { + String coordString = "coordinates="; + String coordinates = wfsgeometry.substring(wfsgeometry.indexOf(coordString) + coordString.length()); + coordinates = coordinates.substring(coordinates.indexOf("=")+1); + coordinatePairs = coordinates.split("\\],\\["); + for (String coord : coordinatePairs) { + coord = coord.replaceAll("(\\[|\\]|\\}|\\{|)", ""); + String[] coordpair = coord.split(","); + double[] dd = new double[2]; + //invert the coordinates as the final must be are long,lat + dd[1] = Double.parseDouble(coordpair[0]); + dd[0] = Double.parseDouble(coordpair[1]); + dpairs.add(dd); + } + } + return dpairs; + } + + public static void main(String[] args) { + + String geom = "{type=MultiPolygon, coordinates={cce4daf3-966e-4b5f-adea-f88ea2b93d03=[[[-16,-146.49999999999997],[-16,-146.99999999999994],[-15.5,-146.99999999999994],[-15.5,-146.49999999999997],[-16,-146.49999999999997]]]}}"; + List coords = WFS2Coordinates(geom); + + GeometryFactory factory = new GeometryFactory(new PrecisionModel(), 4326); + // GeometryFactory factory = new GeometryFactory(new PrecisionModel(), 0); + /* + * CoordinateArraySequence coords = new CoordinateArraySequence(new Coordinate[] { new Coordinate(12.0, 34.23), new Coordinate(12.000, 54.555), new Coordinate(7, 8), new Coordinate(12.0, 34.23) }); LinearRing ring = new LinearRing(coords, factory); Polygon p = new Polygon(ring, null, factory); CoordinateArraySequence pcoords = new CoordinateArraySequence(new Coordinate[] { new Coordinate(12.0, 34.23),}); + */ + // CoordinateArraySequence coords = new CoordinateArraySequence(new Coordinate[] { new Coordinate(1.5, 125.00000000000011), new Coordinate(1.5, 124.5), new Coordinate(2.000000000000057, 124.5), new Coordinate(2.000000000000057, 125.00000000000011), new Coordinate(1.5, 125.00000000000011) }); + + if (coords != null) { + Coordinate[] coordarray = new Coordinate[coords.size()]; + int i=0; + for (double[] pair:coords){ + coordarray[i] = new Coordinate(pair[0],pair[1]); + i++; + } + CoordinateArraySequence coordseq = new CoordinateArraySequence(coordarray); + LinearRing ring = new LinearRing(coordseq, factory); + Polygon p = new Polygon(ring, new LinearRing[] {}, factory); +// CoordinateArraySequence pcoords = new CoordinateArraySequence(new Coordinate[] { new Coordinate(-16,-146.49999999999997), }); + CoordinateArraySequence pcoords = new CoordinateArraySequence(new Coordinate[] { new Coordinate(-150,-16), }); + Point po = new Point(pcoords, factory); +// po = p.getCentroid(); + System.out.println("contains: " + p.contains(po)+" boundary: "+p.covers(po)); + } + } + } diff --git a/src/main/java/org/gcube/dataanalysis/geo/utils/FeaturedPolygon.java b/src/main/java/org/gcube/dataanalysis/geo/utils/FeaturedPolygon.java new file mode 100644 index 0000000..991b453 --- /dev/null +++ b/src/main/java/org/gcube/dataanalysis/geo/utils/FeaturedPolygon.java @@ -0,0 +1,28 @@ +package org.gcube.dataanalysis.geo.utils; + +import java.util.LinkedHashMap; + +import com.vividsolutions.jts.geom.Polygon; + +public class FeaturedPolygon { + public Polygon p; + public LinkedHashMap features; + public Double value; + public FeaturedPolygon(){ + + } + + public void setPolygon(Polygon p){ + this.p=p; + } + + public void setValue(Double v){ + this.value=v; + } + + public void addFeature(String key,String value){ + if (features==null) + features = new LinkedHashMap(); + features.put(key,value); + } +} diff --git a/src/main/java/org/gcube/dataanalysis/geo/utils/JsonMapper.java b/src/main/java/org/gcube/dataanalysis/geo/utils/JsonMapper.java index 3ae590c..81a5a7b 100644 --- a/src/main/java/org/gcube/dataanalysis/geo/utils/JsonMapper.java +++ b/src/main/java/org/gcube/dataanalysis/geo/utils/JsonMapper.java @@ -4,6 +4,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import java.util.UUID; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -32,6 +33,9 @@ public class JsonMapper { parseMap(map, (JsonObject) element); } } + else{ + map.put(UUID.randomUUID().toString(), element.toString()); + } } } @@ -47,6 +51,10 @@ public class JsonMapper { Map.Entry entry = iterator.next(); String key = entry.getKey(); JsonElement value = entry.getValue(); + if (map.get(key)!=null){ + key+=UUID.randomUUID(); + } + if (!value.isJsonPrimitive()) { map.put(key, parse(value.toString())); } else {