From 9d549a7f34745ad905d73ce32e67a86df02fe835 Mon Sep 17 00:00:00 2001 From: alexrodriguez <alejandro.rodriguez@tecnalia.com> Date: Mon, 28 Nov 2022 16:04:11 +0100 Subject: [PATCH] Added method to generate GPS Routes from vehicle points datamodel, and anonymice then deleting the first and last 50 meters of the route AND hidding the name with a hash code. --- .../anonymize/AnonymizeApplication.java | 2 +- .../anonymize/rest/AnonymizerAPI.java | 20 +- .../anonymize/service/AnonymizerService.java | 102 +++++ .../anonymize/service/DataService.java | 20 +- .../anonymize/utils/Configuration.java | 2 +- .../urbanite/anonymize/utils/DataUtils.java | 247 ++++++++++ src/main/java/sml/geoUtils/Calculations.java | 170 +++++++ .../GreatCircleDistanceCalculator.java | 21 + .../sml/geoUtils/IDistanceCalculator.java | 8 + src/main/java/sml/geoUtils/Topology.java | 132 ++++++ src/main/java/sml/geoUtils/Vector3.java | 49 ++ src/main/java/sml/geoUtils/geometry/BBox.java | 80 ++++ .../java/sml/geoUtils/geometry/IPointGeo.java | 11 + .../java/sml/geoUtils/geometry/IPolyline.java | 12 + .../java/sml/geoUtils/geometry/PointGeo.java | 34 ++ .../java/sml/geoUtils/geometry/Polyline.java | 66 +++ .../java/sml/geoUtils/geometry/Segment.java | 39 ++ src/main/java/sml/gps/datamodel/GPSPoint.java | 222 +++++++++ .../java/sml/gps/datamodel/GPSPoints.java | 99 ++++ src/main/java/sml/gps/datamodel/GPSRoute.java | 191 ++++++++ .../java/sml/gps/datamodel/GPSSegment.java | 21 + src/main/java/sml/gps/datamodel/GPSTrack.java | 20 + .../sml/gps/datamodel/GPSTrackSegment.java | 17 + .../java/sml/stops/datamodel/StopData.java | 427 ++++++++++++++++++ src/main/java/sml/utils/Calculations.java | 71 +++ src/main/java/sml/utils/GeoDistance.java | 30 ++ src/main/java/sml/utils/PolyLineEncoder.java | 89 ++++ src/main/java/sml/utils/RawData.java | 54 +++ .../sml/visualizer/datamodel/Register.java | 29 ++ .../gui/functions/DivideInTraysCover.java | 70 +++ .../visualizer/gui/functions/FindStops.java | 364 +++++++++++++++ 31 files changed, 2713 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/tecnalia/urbanite/anonymize/utils/DataUtils.java create mode 100644 src/main/java/sml/geoUtils/Calculations.java create mode 100644 src/main/java/sml/geoUtils/GreatCircleDistanceCalculator.java create mode 100644 src/main/java/sml/geoUtils/IDistanceCalculator.java create mode 100644 src/main/java/sml/geoUtils/Topology.java create mode 100644 src/main/java/sml/geoUtils/Vector3.java create mode 100644 src/main/java/sml/geoUtils/geometry/BBox.java create mode 100644 src/main/java/sml/geoUtils/geometry/IPointGeo.java create mode 100644 src/main/java/sml/geoUtils/geometry/IPolyline.java create mode 100644 src/main/java/sml/geoUtils/geometry/PointGeo.java create mode 100644 src/main/java/sml/geoUtils/geometry/Polyline.java create mode 100644 src/main/java/sml/geoUtils/geometry/Segment.java create mode 100644 src/main/java/sml/gps/datamodel/GPSPoint.java create mode 100644 src/main/java/sml/gps/datamodel/GPSPoints.java create mode 100644 src/main/java/sml/gps/datamodel/GPSRoute.java create mode 100644 src/main/java/sml/gps/datamodel/GPSSegment.java create mode 100644 src/main/java/sml/gps/datamodel/GPSTrack.java create mode 100644 src/main/java/sml/gps/datamodel/GPSTrackSegment.java create mode 100644 src/main/java/sml/stops/datamodel/StopData.java create mode 100644 src/main/java/sml/utils/Calculations.java create mode 100644 src/main/java/sml/utils/GeoDistance.java create mode 100644 src/main/java/sml/utils/PolyLineEncoder.java create mode 100644 src/main/java/sml/utils/RawData.java create mode 100644 src/main/java/sml/visualizer/datamodel/Register.java create mode 100644 src/main/java/sml/visualizer/gui/functions/DivideInTraysCover.java create mode 100644 src/main/java/sml/visualizer/gui/functions/FindStops.java diff --git a/src/main/java/com/tecnalia/urbanite/anonymize/AnonymizeApplication.java b/src/main/java/com/tecnalia/urbanite/anonymize/AnonymizeApplication.java index 4f4a2bd..da04d10 100644 --- a/src/main/java/com/tecnalia/urbanite/anonymize/AnonymizeApplication.java +++ b/src/main/java/com/tecnalia/urbanite/anonymize/AnonymizeApplication.java @@ -39,7 +39,7 @@ public class AnonymizeApplication { @Bean public OpenAPI customOpenAPI(@Value("${application-description}") String appDesciption, @Value("${application-version}") String appVersion) { return new OpenAPI() - .addServersItem(new Server().url("/data/")) + .addServersItem(new Server().url("/anonymize/")) .info(new Info() .title("Anonymize API") .version(appVersion) diff --git a/src/main/java/com/tecnalia/urbanite/anonymize/rest/AnonymizerAPI.java b/src/main/java/com/tecnalia/urbanite/anonymize/rest/AnonymizerAPI.java index 7b5c7f3..a7ecca3 100644 --- a/src/main/java/com/tecnalia/urbanite/anonymize/rest/AnonymizerAPI.java +++ b/src/main/java/com/tecnalia/urbanite/anonymize/rest/AnonymizerAPI.java @@ -15,7 +15,6 @@ */ package com.tecnalia.urbanite.anonymize.rest; -import org.codehaus.jettison.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -40,7 +39,7 @@ public class AnonymizerAPI { @Autowired AnonymizerService anonymizerService; - @RequestMapping(method = RequestMethod.POST, value = "/anonymize/{city}/{model}/{property}/{value}") + /* @RequestMapping(method = RequestMethod.POST, value = "/anonymize/{city}/{model}/{property}/{value}") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successful operation."), @ApiResponse(responseCode = "400", description = "Bad request. (User unknow)")}) @@ -53,7 +52,7 @@ public class AnonymizerAPI { return anonymizerService.anonymizeProperty(city,model,property,value); - } + } */ @RequestMapping(method = RequestMethod.POST, value = "/removePointsOutOfArea/{city}/{model}/{property}/{value}") @ApiResponses(value = { @@ -78,4 +77,19 @@ public class AnonymizerAPI { return anonymizerService.removePointsOutOfArea(location,city,model,property,value); } + + + @RequestMapping(method = RequestMethod.POST, value = "/generateAnonymousVehicleTripFromVehiclePointsString/{city}/{model}/{property}") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Successful operation."), + @ApiResponse(responseCode = "400", description = "Bad request. ")}) + public ResponseEntity<String> generateAnonymousVehicleTripFromVehiclePointsString( + + @Parameter(description = "City where is the model to be anonymized", example = "messina") @PathVariable String city, + @Parameter(description = "Model that is going to be anonymized.", example = "vehicle") @PathVariable String model, + @Parameter(description = "Property of the model that is going to be anonymized.", example = "name") @PathVariable String property) throws Exception { + + return anonymizerService.generateAnonymousVehicleTripFromVehiclePointsString(city,model,property, 50); + + } } diff --git a/src/main/java/com/tecnalia/urbanite/anonymize/service/AnonymizerService.java b/src/main/java/com/tecnalia/urbanite/anonymize/service/AnonymizerService.java index 3f05c8b..2860577 100644 --- a/src/main/java/com/tecnalia/urbanite/anonymize/service/AnonymizerService.java +++ b/src/main/java/com/tecnalia/urbanite/anonymize/service/AnonymizerService.java @@ -4,6 +4,7 @@ import java.awt.geom.Path2D; import java.io.IOException; import java.net.URISyntaxException; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.List; import org.codehaus.jettison.json.JSONArray; @@ -14,9 +15,15 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import com.tecnalia.urbanite.anonymize.utils.Configuration; import com.tecnalia.urbanite.anonymize.utils.Crypto; +import com.tecnalia.urbanite.anonymize.utils.DataUtils; import model.Location; +import sml.gps.datamodel.GPSPoint; +import sml.gps.datamodel.GPSRoute; +import sml.utils.GeoDistance; +import sml.visualizer.gui.functions.DivideInTraysCover; @Service public class AnonymizerService { @@ -70,7 +77,102 @@ public class AnonymizerService { } } + + public ResponseEntity<String> generateAnonymousVehicleTripFromVehiclePointsString (String city,String model, String property, double distanceInMeters) { + try { + JSONObject object = dataService.getDistinctObject(model, city, property);//messina,vehicle,name + JSONArray objects = (JSONArray) object.get("values"); + String respuesta =""; + if (objects.length() > 0) { + for (int i=0;i<objects.length();i++) { + + String vehicleName = objects.getString(i); + //if (!vehicleName.equals("352503093621149")) continue; + //respuesta= respuesta+vehicleName+"-->"; + + JSONArray vehiclePoints = dataService.getObjectsByName(property,vehicleName, model, city); + vehicleName = Crypto.generateHash(vehicleName); + //respuesta= respuesta+vehicleName+"\n"; + GPSRoute route = new GPSRoute(); + ArrayList<GPSPoint> puntos = new ArrayList<GPSPoint>(); + route.setName(vehicleName); + route.setNodes(puntos); + for (int ipoint = 0 ; ipoint< vehiclePoints.length();ipoint++) { + boolean isvalid = DataUtils.isValidVehiclePoint(vehiclePoints.getJSONObject(ipoint)); + if (isvalid) { + puntos.add(DataUtils.getGpsPointFromVehiclePoint(vehiclePoints.getJSONObject(ipoint))); + } + } + DivideInTraysCover ditc = new DivideInTraysCover(route); + ArrayList<GPSRoute> rutasAntesdeAnonimizar = ditc.doFindingTrays(); + int borrados = 0; + //int b=0; + JSONArray arrObs = new JSONArray(); + for (GPSRoute rutaaAnonymizar:rutasAntesdeAnonimizar) { + + ArrayList<GPSPoint> nodos = rutaaAnonymizar.getArrayNodes(); + if (nodos.size() < 3) { + System.out.println("Ruta with few points. removed"); + borrados++; + continue; + } + double distanciaruta = GeoDistance.CalcDistance(nodos.get(0), nodos.get(nodos.size()-1))*1000; + if (distanciaruta < distanceInMeters*2) { + System.out.println("Ruta too short "+distanciaruta+". removed"); + borrados++; + continue; + } + else { + + //DataUtils.printGPSRoute(rutaaAnonymizar); + ArrayList<GPSPoint> puntosAnonymizadosBegin = DataUtils.removeDistanceFromBegin(nodos, distanceInMeters); + ArrayList<GPSPoint> puntosAnonymizados = DataUtils.removeDistanceFromEnd(puntosAnonymizadosBegin, distanceInMeters); + if (puntosAnonymizados.size() < 3) { + System.out.println("Ruta borrada al anonymizar"); + borrados++; + continue; + } + //b++; + GPSRoute rutaAnonymizada = new GPSRoute(); + rutaAnonymizada.setName(vehicleName); + rutaAnonymizada.setNodes(puntosAnonymizados); + arrObs.put(DataUtils.gpsRouteToNGSINode(rutaAnonymizada).toString()); + //DataUtils.printGPSRoute(rutaAnonymizada); + //if (b==2 )break; + } + + } + respuesta =DataUtils.storeDataFlow("gtfsShape",arrObs.toString(),city,Configuration.getExporterUrl()); + + System.out.println("Total rutas bici:"+vehicleName+"="+rutasAntesdeAnonimizar.size()+" Eliminadas:"+borrados); + + } + return new ResponseEntity<>(respuesta, HttpStatus.OK); + } + else { + return new ResponseEntity<>("Error generation anonymous routes fromvehicles !!", HttpStatus.BAD_REQUEST); + } + + + } catch (JSONException e) { + e.printStackTrace(); + return new ResponseEntity<>("Error while generateAnonymousVehicleTripFromVehiclePointsString:" + property + ". Please try again !! " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } catch (URISyntaxException e) { + e.printStackTrace(); + return new ResponseEntity<>("Error while generateAnonymousVehicleTripFromVehiclePointsString:" + property + ". Please try again !! " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } catch (IOException e) { + e.printStackTrace(); + return new ResponseEntity<>("Error while generateAnonymousVehicleTripFromVehiclePointsString:" + property + ". Please try again !! " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } catch (InterruptedException e) { + e.printStackTrace(); + return new ResponseEntity<>("Error while generateAnonymousVehicleTripFromVehiclePointsString:" + property + ". Please try again !! " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return new ResponseEntity<>("Error while generateAnonymousVehicleTripFromVehiclePointsString:" + property + ". Please try again !! " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + } + public ResponseEntity<String> removePointsOutOfArea(Location location, String city,String model, String property,String value) { try { JSONArray objects = dataService.getObjectsByName(property,value, model, city); diff --git a/src/main/java/com/tecnalia/urbanite/anonymize/service/DataService.java b/src/main/java/com/tecnalia/urbanite/anonymize/service/DataService.java index 91ace8a..be63f95 100644 --- a/src/main/java/com/tecnalia/urbanite/anonymize/service/DataService.java +++ b/src/main/java/com/tecnalia/urbanite/anonymize/service/DataService.java @@ -28,7 +28,7 @@ public class DataService { //https://bilbao.urbanite.esilab.org/data/getTData/mapLayer/bilbao?filters=%7B%22alternateName%22%3A%20%22test.geojson%22%7D HttpRequest request = HttpRequest.newBuilder() - .uri(new URI(URL+"/data/getTData/"+model+"/"+city+"?filters="+filter)) + .uri(new URI(URL+"/data/getTData/"+model+"/"+city+"?filters="+filter+"&sort=ASC")) .GET() .build(); @@ -73,6 +73,24 @@ public class DataService { System.out.println(response.body()); return new JSONObject(response.body()); } + public JSONObject getDistinctObject(String model, String city, String field) throws JSONException, URISyntaxException, IOException, InterruptedException { + String URL = Configuration.getExporterUrl(); + + //http://localhost:8080/data/updateTData/vehicle/bilbao/vehicle%3AWasteManagement%3A1 + HttpRequest request = HttpRequest.newBuilder() + .uri(new URI(URL+"/data/getDistinct/"+model+"/"+city+"?field="+field)) + .GET() + .build(); + + HttpResponse<String> response = HttpClient + .newBuilder() + .build() + .send(request, BodyHandlers.ofString()); + System.out.println(response.body()); + return new JSONObject(response.body()); + } + + private String encode(String value) throws UnsupportedEncodingException { return URLEncoder.encode(value, StandardCharsets.UTF_8.toString()); diff --git a/src/main/java/com/tecnalia/urbanite/anonymize/utils/Configuration.java b/src/main/java/com/tecnalia/urbanite/anonymize/utils/Configuration.java index 8b2005e..65bc6c5 100644 --- a/src/main/java/com/tecnalia/urbanite/anonymize/utils/Configuration.java +++ b/src/main/java/com/tecnalia/urbanite/anonymize/utils/Configuration.java @@ -4,7 +4,7 @@ public class Configuration { public static String getExporterUrl() { - return System.getenv("DATA_STORAGE_URL") != null ? System.getenv("OPENTSDB_URL") : "http://localhost:8080"; + return System.getenv("DATA_STORAGE_URL") != null ? System.getenv("DATA_STORAGE_URL") : "http://localhost:8080"; } } diff --git a/src/main/java/com/tecnalia/urbanite/anonymize/utils/DataUtils.java b/src/main/java/com/tecnalia/urbanite/anonymize/utils/DataUtils.java new file mode 100644 index 0000000..635e623 --- /dev/null +++ b/src/main/java/com/tecnalia/urbanite/anonymize/utils/DataUtils.java @@ -0,0 +1,247 @@ +package com.tecnalia.urbanite.anonymize.utils; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.cert.X509Certificate; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collections; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import sml.gps.datamodel.GPSPoint; +import sml.gps.datamodel.GPSRoute; +import sml.utils.GeoDistance; + +public class DataUtils { + public static boolean isValidVehiclePoint(JSONObject vehicle) throws JSONException { + String observationDateTime = vehicle.getString("observationDateTime"); + ZonedDateTime dateTime = getZonedDateTimeFromString(observationDateTime); + + if (dateTime ==null) { + System.out.println ("Descatartado:"+observationDateTime); + return false; + } + if (dateTime.getYear() < 2020 || dateTime.getYear() > 2021){ + System.out.println ("Descatartado:"+dateTime.getYear()); + return false; + } + else if (dateTime.getMonthValue() < 8 && dateTime.getYear() == 2020 ) { + System.out.println ("Descatartado:"+dateTime.getYear()+"-"+dateTime.getMonthValue()); + return false; + + } + else{ + return true; + } + + } + public static GPSPoint getGpsPointFromVehiclePoint(JSONObject vehicle) throws JSONException { + + String observationDateTime = vehicle.getString("observationDateTime"); + ZonedDateTime dateTime = getZonedDateTimeFromString(observationDateTime); + if (dateTime == null) { + System.out.println ("Descatartado:"+observationDateTime); + return null; + } + Long time = dateTime.toEpochSecond() *1000; + double lon = vehicle.getJSONObject("location").getJSONArray("coordinates").getDouble(0); + double lat =vehicle.getJSONObject("location").getJSONArray("coordinates").getDouble(1); + double speed = vehicle.getDouble("speed"); + GPSPoint p =new GPSPoint(time,lat,lon,speed); + p.setTime(dateTime.toEpochSecond()); + return p; + + } + + private static ZonedDateTime getZonedDateTimeFromString (String zonedDateTime) { + ZonedDateTime dateTime = null; + try { + dateTime =OffsetDateTime.parse(zonedDateTime).toZonedDateTime(); + return dateTime; + } + catch (java.time.format.DateTimeParseException e){ + System.out.println ("Descatartado:"+zonedDateTime+ " -- "+e.getMessage()); + return null; + } + + } + public static void printGPSRoute(GPSRoute route) { + String respuesta = ""; + ArrayList<GPSPoint> nodos = route.getArrayNodes(); + double distanciarutaanonimizada = GeoDistance.CalcDistance(nodos.get(0), nodos.get(nodos.size()-1))*1000; + System.out.println("Ruta con distancia: "+distanciarutaanonimizada+" Nuemro de puntos:"+nodos.size()+"."); + + for(int j=0;j<nodos.size();j++) { + GPSPoint nodo = nodos.get(j); + respuesta = respuesta + nodo.getTime()+","+nodo.getLatitude()+","+nodo.getLongitude()+","+nodo.getSpeed()+"\n"; + + } + respuesta = respuesta +"-------\n"; + System.out.println (respuesta); + + + } + public static ArrayList<GPSPoint> removeDistanceFromBegin(ArrayList<GPSPoint> nodos,double distanceInMeters){ + ArrayList<GPSPoint> puntosAnonymizados = new ArrayList<GPSPoint>(); + double distanciaBorrada=0; + for(int j=0;j<nodos.size();j++) { + //if (j==0) continue; + if (distanciaBorrada >= distanceInMeters) { + puntosAnonymizados.add(nodos.get(j)); + } + else if (j != nodos.size()-1) { + double parcial = GeoDistance.CalcDistance(nodos.get(j), nodos.get(j+1))*1000; + System.out.println("distanciaBorrada:"+parcial); + distanciaBorrada = distanciaBorrada + parcial; + } + } + System.out.println("Total distanciaBorrada:"+distanciaBorrada); + return puntosAnonymizados; + } + public static ArrayList<GPSPoint> removeDistanceFromEnd(ArrayList<GPSPoint> nodos,double distanceInMeters){ + ArrayList<GPSPoint> puntosAnonymizados = new ArrayList<GPSPoint>(); + double distanciaBorrada=0; + for(int j=nodos.size()-1 ;j>=0;j--) { + //if (j==0) continue; + if (distanciaBorrada >= distanceInMeters) { + puntosAnonymizados.add(nodos.get(j)); + } + else if (j > 0) { + double parcial = GeoDistance.CalcDistance(nodos.get(j-1), nodos.get(j))*1000; + System.out.println("distanciaBorrada:"+parcial); + distanciaBorrada = distanciaBorrada + parcial; + } + } + Collections.reverse(puntosAnonymizados); + System.out.println("Total distanciaBorrada:"+distanciaBorrada); + return puntosAnonymizados; + } + public static ObjectNode gpsRouteToNGSINode(GPSRoute route) { + ArrayList<GPSPoint> nodos = route.getArrayNodes(); + String id = ""+nodos.get(0).getTime(); + String name = route.getName(); + ObjectNode node = new ObjectMapper().createObjectNode() + .put("id", "urn:ld:GtfsShape:messina:ebiketrajectories:" + name+":"+id) + .put("type", "GtfsShape") + .put("alternateName", "ebiketrajectories") + .put("name", name); + + ArrayNode arrayNodeContext = new ObjectMapper().createArrayNode() + .add("https://smartdatamodels.org/context.jsonld") + .add("https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld"); + + node.set("@context", arrayNodeContext); + ObjectNode location = new ObjectMapper().createObjectNode(); + + ArrayNode coordinates = new ObjectMapper().createArrayNode(); + ArrayNode poligons = new ObjectMapper().createArrayNode(); + ArrayNode trozos = new ObjectMapper().createArrayNode(); + for (GPSPoint nodo:nodos) { + ArrayNode point = new ObjectMapper().createArrayNode(); + point.add(nodo.getLatitude()); + point.add(nodo.getLongitude()); + poligons.add(point); + } + trozos.add(poligons); + coordinates.add(trozos); + location.set("coordinates",coordinates); + location.put("type","MultiPolygon"); + node.set("location",location); + + return node; + + + } + public static String storeDataFlow(String model, String jsonInput, String piloto,String hurl) { + HttpURLConnection conn = null; + try { + // Install the all-trusting trust manager + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + + // Install the all-trusting host verifier + HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); + //http://localhost/data/insertTData/touristTrip/bilbao + //https://helsinki.urbanite.esilab.org/data/insertTData/TransportStation/helsinki + //https://amsterdam.urbanite.esilab.org/data/insertTData/pointOfInterest/amsterdam + URL url = new URL(hurl + "/data/insertTData/"+model+"/"+piloto); + conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/json"); + + OutputStream os = conn.getOutputStream(); + os.write(jsonInput.getBytes()); + os.flush(); + + BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream()))); + + String output; + + while ((output = br.readLine()) != null) { + + if (!output.contains("\"notInserted\":[]")) { + JSONObject res = new JSONObject(output); + System.out.println(res.getJSONArray("notInserted").toString()); + System.out.println("Error in storeDataFlow model= " + model ); + return output; + } + else { + System.out.println("Correct!"); + } + + } + + + return output; + + } catch (Exception e) { + System.err.println("Error in storeTrafficFlow model= " + model+" "+e.getMessage());// + " \njsonInput " + jsonInput); + System.err.println(e.getMessage()); + //System.exit(0); + return "Error in storeTrafficFlow model= " + model+" "+e.getMessage(); + + } + finally { + if (conn!=null)conn.disconnect(); + } + + } + private static TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) { + } + + public void checkServerTrusted(X509Certificate[] certs, String authType) { + } + } + }; + + // Create all-trusting host name verifier + private static HostnameVerifier allHostsValid = new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; +} diff --git a/src/main/java/sml/geoUtils/Calculations.java b/src/main/java/sml/geoUtils/Calculations.java new file mode 100644 index 0000000..d610a7e --- /dev/null +++ b/src/main/java/sml/geoUtils/Calculations.java @@ -0,0 +1,170 @@ + +package sml.geoUtils; + +import sml.geoUtils.geometry.IPointGeo; +import sml.geoUtils.geometry.IPolyline; +import sml.geoUtils.geometry.PointGeo; +import sml.geoUtils.geometry.Segment; +import sml.gps.datamodel.GPSPoint; + +public class Calculations { + public static Double EARTH_RADIOUS = 6371010.0; + public static Double EPS_LENGTH = 0.01; + public static int NUMBEROFPOINTS = 1000; + //static GreatCircleDistanceCalculator distanceCalculator; + static IDistanceCalculator distanceCalculator= new GreatCircleDistanceCalculator(); + public Calculations(){ + distanceCalculator = new GreatCircleDistanceCalculator(); + } + + public static Double getBearing(IPointGeo pt1, IPointGeo pt2){ + Double dLon = Calculations.toRadians(pt1.getLongitude()-pt2.getLongitude()); + Double dLat = Calculations.toRadians(pt1.getLatitude()-pt2.getLatitude()); + + Double y = Math.sin(dLon) * Math.cos(Calculations.toRadians(pt2.getLatitude())); + Double x = Math.cos(Calculations.toRadians(pt1.getLatitude())) * Math.sin(Calculations.toRadians(pt2.getLatitude())) + - Math.sin(Calculations.toRadians(pt1.getLatitude())) * Math.cos(Calculations.toRadians(pt2.getLatitude())) * Math.cos(dLon); + return Calculations.toDegrees(Math.atan2(y, x)); + } + + public static Double getBearing(Segment<IPointGeo> segment){ + return Calculations.getBearing(segment.getStartPoint(), segment.getEndPoint()); + }; + + public static Double getDistance2D(IPointGeo pt1, IPointGeo pt2){ + //System.out.println("pt1=<"+pt1.getLatitude()+","+pt1.getLongitude()+">"); + //System.out.println("pt1=<"+pt2.getLatitude()+","+pt2.getLongitude()+">"); + if( pt1 == null ){ System.err.println("Calculations.getDistance:::pt1=null"); System.exit(1);} + if( pt2 == null ){ System.err.println("Calculations.getDistance:::pt2=null"); System.exit(1);} + return distanceCalculator.calculate2D(pt1,pt2); + } + + public static Double getDistance2D(IPointGeo point, Segment<IPointGeo> segment){ + IPointGeo projectedPoint = Topology.projectPoint(point, segment); + return distanceCalculator.calculate2D(point, projectedPoint); + } + + public static Double getDistance2D(IPointGeo point, IPolyline<IPointGeo> line){ + Double minDistance = Double.POSITIVE_INFINITY; + for(Segment segment : line.getSegments()){ + IPointGeo projectedPoint = Topology.projectPoint(point,segment); + minDistance = Math.min(minDistance, distanceCalculator.calculate2D(point,projectedPoint)); + } + return minDistance; + } + + public static Double getDistance2D(IPointGeo point, IPolyline<IPointGeo> line, int closestSegmentIndex){ + Double minDistance = Double.POSITIVE_INFINITY; + for(int i=0;i<line.getSegments().size();i++){ + IPointGeo projectedPoint = Topology.projectPoint(point,line.getSegments().get(i)); + Double distance = distanceCalculator.calculate2D(point, projectedPoint); + if ( distance < minDistance ){ + minDistance = distance; + closestSegmentIndex = i; + } + } + return minDistance; + } + public static Double getPathLength(IPointGeo from, IPointGeo to, Segment<IPointGeo> path){ + return Calculations.getDistance2D(from, to); + } + + public static Double getPathLength(IPointGeo from, IPointGeo to, IPolyline<IPointGeo> path){ + int pointFound = 0; + int pointFoundLast = 0; + boolean fromFound = false; + boolean toFound = false; + Double distance = 0.0; + for(Segment segment : path.getSegments()){ + pointFoundLast = pointFound; + IPointGeo[] points = new IPointGeo[] {segment.getStartPoint(),segment.getEndPoint()}; + if (!fromFound && (Calculations.getDistance2D(from, segment) < EPS_LENGTH)){ + fromFound = true; + points[pointFound++] = from; + } + if(!toFound && (Calculations.getDistance2D(to, segment) < EPS_LENGTH)){ + toFound = true; + points[pointFound++] = to; + } + if ( pointFound > 0 ){ + if (pointFound == pointFoundLast) distance = distance + segment.getLength(); + else distance = distance + Calculations.getDistance2D(points[0],points[1]); + if (pointFound == 2) return distance; + + } + } + return distance; + } + public static Double getLength(IPolyline<IPointGeo> line){ + Double length = 0.0; + for(Segment segment : line.getSegments()){ + length = length + segment.getLength(); + } + return length; + } + public static PointGeo Averaging(Iterable<IPointGeo> points){ + int count = 0; + Double lat = 0.0; + Double lon = 0.0; + for(IPointGeo point : points){ + lat = lat + point.getLatitude(); + lon = lon + point.getLongitude(); + count = count + 1; + } + return new PointGeo(lat/count, lon/count); + } + public static Double toRadians(Double angle){ + return angle * Math.PI / 180.0; + } + public static double toDegrees(Double angle){ + return angle * 180.0 / Math.PI; + } + + public static GPSPoint greatCirclePoint(GPSPoint pnt1, GPSPoint pnt2, Double f){ + /* + https://math.stackexchange.com/questions/383711/parametric-equation-for-great-circle + d = acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon1 - lon2)) + A = sin((1 - f) * d) / sin(d) + B = sin(f * d) / sin(d) + x = A * cos(lat1) * cos(lon1) + B * cos(lat2) * cos(lon2) + y = A * cos(lat1) * sin(lon1) + B * cos(lat2) * sin(lon2) + z = A * sin(lat1) + B * sin(lat2) + + lat_f = atan2(z, sqrt(x^2 + y^2)) + lon_f = atan2(y,x) + } + */ + + Double lat1 = Math.toRadians(pnt1.getLatitude()); + Double lon1 = Math.toRadians(pnt1.getLongitude()); + Double lat2 = Math.toRadians(pnt2.getLatitude()); + Double lon2 = Math.toRadians(pnt2.getLongitude()); + + Double d = Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1-lon2)); + Double A = Math.sin((1.0-f) * d ) / Math.sin(d); + Double B = Math.sin(f*d) / Math.sin(d); + Double x = A * Math.cos(lat1) * Math.cos(lon1) + B * Math.cos(lat2) * Math.cos(lon2); + Double y = A * Math.cos(lat1) * Math.sin(lon1) + B * Math.cos(lat2) * Math.sin(lon2); + Double z = A * Math.sin(lat1) + B * Math.sin(lat2); + + Double lat_f = Math.toDegrees(Math.atan2(z, Math.sqrt(x*x+y*y))); + Double lon_f = Math.toDegrees(Math.atan2(y,x)); + + GPSPoint pnt = new GPSPoint(lat_f,lon_f); + return pnt; + } + + public static Double distanceToGreatCircle(GPSPoint pnt, GPSPoint pnt1, GPSPoint pnt2){ + Double minDistance = Double.MAX_VALUE; + int numPoints = NUMBEROFPOINTS; + for(int i=0;i<numPoints;i++){ + Double f = (i*1.0) / ((numPoints-1)*1.0); + GPSPoint gcPnt = greatCirclePoint(pnt1, pnt2, f); + Double distance = Calculations.getDistance2D(pnt, gcPnt); + if ( distance < minDistance ){ + minDistance = distance; + } + } + return minDistance; + } +} diff --git a/src/main/java/sml/geoUtils/GreatCircleDistanceCalculator.java b/src/main/java/sml/geoUtils/GreatCircleDistanceCalculator.java new file mode 100644 index 0000000..78d12b9 --- /dev/null +++ b/src/main/java/sml/geoUtils/GreatCircleDistanceCalculator.java @@ -0,0 +1,21 @@ + +package sml.geoUtils; + +import sml.geoUtils.geometry.IPointGeo; + +public class GreatCircleDistanceCalculator implements IDistanceCalculator { + Double EARTH_RADIOUS = 6371010.0; + public Double calculate2D(IPointGeo pt1, IPointGeo pt2) { + //System.out.println("GreateCircleDistanceCalculator.calculate2D:::in routine"); + Double dLat = Calculations.toRadians(pt2.getLatitude()-pt1.getLatitude()); + Double dLon = Calculations.toRadians(pt2.getLongitude()-pt1.getLongitude()); + Double a = Math.sin(dLat/2.0) * Math.sin(dLat/2.0) + + Math.cos(Calculations.toRadians(pt1.getLatitude())) * + Math.cos(Calculations.toRadians(pt2.getLatitude())) * + Math.sin(dLon/2.0) * Math.sin(dLon/2.0); + Double dAngle = 2 * Math.asin(Math.sqrt(a)); + return dAngle * this.EARTH_RADIOUS; + + + } +} diff --git a/src/main/java/sml/geoUtils/IDistanceCalculator.java b/src/main/java/sml/geoUtils/IDistanceCalculator.java new file mode 100644 index 0000000..0ca93e7 --- /dev/null +++ b/src/main/java/sml/geoUtils/IDistanceCalculator.java @@ -0,0 +1,8 @@ + +package sml.geoUtils; + +import sml.geoUtils.geometry.IPointGeo; + +public interface IDistanceCalculator { + Double calculate2D(IPointGeo pt1, IPointGeo pt2); +} diff --git a/src/main/java/sml/geoUtils/Topology.java b/src/main/java/sml/geoUtils/Topology.java new file mode 100644 index 0000000..1fc2e34 --- /dev/null +++ b/src/main/java/sml/geoUtils/Topology.java @@ -0,0 +1,132 @@ +package sml.geoUtils; + +import java.util.ArrayList; +import sml.geoUtils.geometry.BBox; +import sml.geoUtils.geometry.IPointGeo; +import sml.geoUtils.geometry.IPolyline; +import sml.geoUtils.geometry.PointGeo; +import sml.geoUtils.geometry.Segment; + +public class Topology { + + + + public IPointGeo projectPointSphere(IPointGeo toProject, Segment<IPointGeo> projectTo){ + Vector3 a = new Vector3(projectTo.getStartPoint()); + Vector3 b = new Vector3(projectTo.getEndPoint()); + Vector3 c = new Vector3(toProject); + + Vector3 greatCircleN = Vector3.crossProduct(a,b); + Vector3 greatCircleCN = Vector3.crossProduct(c,greatCircleN); + Vector3 projected = Vector3.crossProduct(greatCircleN, greatCircleCN); + projected.normalize(); + + PointGeo result = projected.toSpherical(); + + Double apDistance = Calculations.getDistance2D(projectTo.getStartPoint(), result); + Double bpDistance = Calculations.getDistance2D(projectTo.getEndPoint(), result); + if ( apDistance + bpDistance - Calculations.getLength((IPolyline<IPointGeo>)projectTo) < 0.01 ){ return result; } + else{ + if(Calculations.getDistance2D(projectTo.getStartPoint(),toProject) < Calculations.getDistance2D(projectTo.getEndPoint(),toProject)){ + return projectTo.getStartPoint(); + }else{ + return projectTo.getEndPoint(); + } + } + + } + + public static IPointGeo projectPoint (IPointGeo toProject, Segment<IPointGeo> projectTo){ + Double u = ((projectTo.getEndPoint().getLongitude() - projectTo.getStartPoint().getLongitude()) * + (toProject.getLongitude() - projectTo.getStartPoint().getLongitude()) + + (projectTo.getEndPoint().getLatitude() - projectTo.getStartPoint().getLatitude()) * + (toProject.getLatitude() - projectTo.getStartPoint().getLatitude()) + ) / + ( Math.pow(projectTo.getEndPoint().getLongitude() - projectTo.getStartPoint().getLongitude(), 2) + + Math.pow(projectTo.getEndPoint().getLatitude() - projectTo.getStartPoint().getLatitude(), 2) + ); + + if ( u <= 0.0 ) return projectTo.getStartPoint(); + if ( u >= 1.0 ) return projectTo.getEndPoint(); + Double lon = projectTo.getStartPoint().getLongitude() + u *(projectTo.getEndPoint().getLongitude() - projectTo.getStartPoint().getLongitude()); + Double lat = projectTo.getStartPoint().getLatitude() + u *(projectTo.getEndPoint().getLatitude() - projectTo.getStartPoint().getLatitude()); + return new PointGeo(lat,lon); + } + public static IPointGeo projectPoint (IPointGeo point, IPolyline<IPointGeo> line){ + Double minDistance = Double.POSITIVE_INFINITY; + IPointGeo closestPoint = null; + for(Segment segment : line.getSegments()){ + IPointGeo projected = projectPoint(point,segment); + Double distance = Calculations.getDistance2D(point, projected); + if( distance < minDistance ){ + minDistance = distance; + closestPoint = projected; + } + } + return closestPoint; + } + public static IPointGeo projectPoint (IPointGeo point, IPolyline<IPointGeo> line, Segment<IPointGeo> onSegment){ + Double minDistance = Double.POSITIVE_INFINITY; + IPointGeo closestPoint = null; + onSegment = null; + //System.out.println("Topology.projectPoint:::# nodes="); + for( Segment segment : line.getSegments() ){ + IPointGeo projected = projectPoint(point,segment); + Double distance = Calculations.getDistance2D(point,projected); + if ( distance < minDistance ){ + minDistance = distance; + closestPoint = projected; + onSegment = segment; + } + } + return closestPoint; + } + public static PointGeo projectedPoint(IPointGeo point, Double bearing, Double distance){ + Double lat = Math.asin(Math.sin(Calculations.toRadians(point.getLatitude()))*Math.cos(distance / Calculations.EARTH_RADIOUS) + + Math.cos(Calculations.toRadians(point.getLatitude()))*Math.sin(distance / Calculations.EARTH_RADIOUS) * + Math.cos(Calculations.toRadians(bearing))); + + Double lon = Calculations.toRadians(point.getLongitude()) + + Math.atan2(Math.sin(Calculations.toRadians(bearing))*Math.sin(distance/Calculations.EARTH_RADIOUS)*Math.cos(Calculations.toRadians(point.getLatitude())), + Math.cos(distance / Calculations.EARTH_RADIOUS) - Math.sin(Calculations.toRadians(point.getLatitude()))*Math.sin(lat)); + return new PointGeo(Calculations.toDegrees(lat),Calculations.toDegrees(lon)); + } + public static boolean intersects(BBox bBox1, BBox bBox2){ + return !(bBox2.getWest() > bBox1.getEast() || bBox2.getEast() < bBox1.getWest() || + bBox2.getSouth() > bBox1.getNorth() || bBox2.getNorth() < bBox1.getSouth() + ); + } + public static Iterable<IPointGeo> getNodesBetweenPoints(IPointGeo from, IPointGeo to, IPolyline<IPointGeo> path){ + ArrayList<Segment<IPointGeo>> segments = path.getSegments(); + ArrayList<IPointGeo> result = new ArrayList<IPointGeo>(); + int fromIndex = -1; + int toIndex = -1; + for(int i=0; i< segments.size(); i++){ + if( Calculations.getDistance2D(from, segments.get(i)) < Calculations.EPS_LENGTH){ + if (fromIndex > -1 && toIndex > -1 && toIndex <= fromIndex){} + else fromIndex = i; + } + if( Calculations.getDistance2D(to, segments.get(i)) < Calculations.EPS_LENGTH){ + if (fromIndex > -1 && toIndex > -1 && toIndex <= fromIndex){} + else toIndex = i; + } + } + if ( fromIndex == -1 || toIndex == -1 ) return result; + if ( fromIndex == toIndex -1 ) { + result.add(segments.get(fromIndex).getEndPoint());} + else if ( fromIndex -1 == toIndex ) { + result.add(segments.get(toIndex).getEndPoint()); + } + else if ( fromIndex < toIndex ) { + for(int i=fromIndex;i<toIndex;i++){ + result.add(segments.get(i).getEndPoint()); + } + } + else if ( toIndex < fromIndex ) { + for(int i=fromIndex; i > toIndex;i--){ + result.add(segments.get(i).getStartPoint()); + } + } + return result; + } +} diff --git a/src/main/java/sml/geoUtils/Vector3.java b/src/main/java/sml/geoUtils/Vector3.java new file mode 100644 index 0000000..3177d37 --- /dev/null +++ b/src/main/java/sml/geoUtils/Vector3.java @@ -0,0 +1,49 @@ + +package sml.geoUtils; + +import sml.geoUtils.geometry.IPointGeo; +import sml.geoUtils.geometry.PointGeo; + +public class Vector3 { + Double x; + Double y; + Double z; + public Double getX(){ return x; } + public Double getY(){ return y; } + public Double getZ(){ return z; } + public void setX(Double x){ this.x = x; } + public void setY(Double y){ this.y = y; } + public void setZ(Double z){ this.z = z; } + public Vector3(){} + public Vector3(IPointGeo sphericalPoint){ + Double lat = Math.PI / 2.0 - Calculations.toRadians(sphericalPoint.getLatitude()); + Double lon = Calculations.toRadians(sphericalPoint.getLongitude()); + this.x = Math.sin(lat) * Math.cos(lon); + this.y = Math.sin(lat) * Math.sin(lon); + this.z = Math.cos(lat); + } + public void normalize(){ + Double length = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + this.x = this.x/length; + this.y = this.y/length; + this.z = this.z/length; + } + public void multiply(Double factor){ + this.x = this.x * factor; + this.y = this.y * factor; + this.z = this.z * factor; + } + public PointGeo toSpherical(){ + PointGeo result = new PointGeo(); + result.setLatitude(Calculations.toDegrees(Math.PI/2.0 - Math.acos(this.z))); + result.setLongitude(Calculations.toDegrees(Math.atan2(this.y, this.x))); + return result; + } + public static Vector3 crossProduct(Vector3 A, Vector3 B){ + Vector3 crossProd = new Vector3(); + crossProd.setX(A.getY() * B.getZ() - A.getZ() * B.getY()); + crossProd.setY(A.getZ() * B.getX() - A.getX() * B.getZ()); + crossProd.setZ(A.getX() * B.getY() - A.getY() * B.getX()); + return crossProd; + } +} diff --git a/src/main/java/sml/geoUtils/geometry/BBox.java b/src/main/java/sml/geoUtils/geometry/BBox.java new file mode 100644 index 0000000..da1d959 --- /dev/null +++ b/src/main/java/sml/geoUtils/geometry/BBox.java @@ -0,0 +1,80 @@ + +package sml.geoUtils.geometry; + + +public class BBox { + private Double north; + private Double south; + private Double east; + private Double west; + private Double minElevation; + private Double maxElevation; + private boolean initialized; + public BBox(){ + this.initialized = false; + } + public BBox(Iterable<IPointGeo> pointsToCover){ + for (IPointGeo pointToCover : pointsToCover){ + extendToCover(pointToCover); + } + } + public void setNorth(Double north){this.north = north;} + public void setSouth(Double south){this.south = south;} + public void setWest(Double west) {this.west = west;} + public void setEast(Double east) {this.east = east;} + public Double getNorth(){return this.north;} + public Double getSouth(){return this.south;} + public Double getWest() {return this.west;} + public Double getEast() {return this.east;} + public final void extendToCover(IPointGeo toCover){ + if ( !this.initialized ){ + this.north = toCover.getLatitude(); + this.south = toCover.getLatitude(); + this.east = toCover.getLongitude(); + this.west = toCover.getLongitude(); + + this.minElevation = toCover.getElevation(); + this.maxElevation = toCover.getElevation(); + this.initialized = true; + } + this.north = Math.max(this.north, toCover.getLatitude() ); + this.south = Math.min(this.south, toCover.getLatitude() ); + this.east = Math.max(this.east, toCover.getLongitude()); + this.west = Math.min(this.west, toCover.getLongitude()); + + this.minElevation = Math.min(this.minElevation,toCover.getElevation()); + this.maxElevation = Math.max(this.maxElevation,toCover.getElevation()); + } + public boolean isInside(IPointGeo point){ + boolean result = true; + if ( this.north < point.getLatitude() ){ result = false; } + if ( this.south > point.getLatitude() ){ result = false; } + if ( this.east < point.getLongitude() ){ result = false; } + if ( this.west > point.getLongitude() ){ result = false; } + if ( this.maxElevation < point.getElevation() ) { result = false; } + if ( this.minElevation > point.getElevation() ) { result = false; } + return result; + } + public boolean isInside2D(IPointGeo point){ + boolean result = true; + if( this.north < point.getLatitude() ){ result = false; } + if ( this.south > point.getLatitude() ){ result = false; } + if ( this.east < point.getLongitude() ){ result = false; } + if ( this.west > point.getLongitude() ){ result = false; } + return result; + } + public void inflate(Double dLat, Double dLon){ + this.north = this.north + dLat; + this.south = this.south - dLat; + this.east = this.east + dLon; + this.west = this.west - dLon; + } + public PointGeo[] getCorners(){ + PointGeo[] corners = new PointGeo[4]; + corners[0] = new PointGeo(this.getNorth(), this.getWest()); + corners[1] = new PointGeo(this.getNorth(), this.getEast()); + corners[2] = new PointGeo(this.getSouth(), this.getEast()); + corners[3] = new PointGeo(this.getSouth(), this.getWest()); + return corners; + } +} diff --git a/src/main/java/sml/geoUtils/geometry/IPointGeo.java b/src/main/java/sml/geoUtils/geometry/IPointGeo.java new file mode 100644 index 0000000..952b258 --- /dev/null +++ b/src/main/java/sml/geoUtils/geometry/IPointGeo.java @@ -0,0 +1,11 @@ + +package sml.geoUtils.geometry; + +public interface IPointGeo { + public Double getLatitude(); + public Double getLongitude(); + public Double getElevation(); + public void setLatitude(Double lat); + public void setLongitude(Double lon); + public void setElevation(Double ele); +} diff --git a/src/main/java/sml/geoUtils/geometry/IPolyline.java b/src/main/java/sml/geoUtils/geometry/IPolyline.java new file mode 100644 index 0000000..b2804a3 --- /dev/null +++ b/src/main/java/sml/geoUtils/geometry/IPolyline.java @@ -0,0 +1,12 @@ + +package sml.geoUtils.geometry; + +import java.util.ArrayList; +public interface IPolyline<T extends IPointGeo> { + public ArrayList<T> getNodes(); + public ArrayList<Segment<T>> getSegments(); + public Double getLength(); + public int getNodeCount(); +} + + diff --git a/src/main/java/sml/geoUtils/geometry/PointGeo.java b/src/main/java/sml/geoUtils/geometry/PointGeo.java new file mode 100644 index 0000000..28f3e33 --- /dev/null +++ b/src/main/java/sml/geoUtils/geometry/PointGeo.java @@ -0,0 +1,34 @@ + +package sml.geoUtils.geometry; + + +public class PointGeo implements IPointGeo { + Double latitude = 0.0; + Double longitude = 0.0; + Double elevation = 0.0; + public PointGeo(){ + } + public PointGeo(Double lat, Double lon){ + this.latitude = lat; + this.longitude = lon; + this.elevation = 0.0; + } + public PointGeo(Double lat, Double lon, Double ele){ + this.latitude = lat; + this.longitude = lon; + this.elevation = ele; + } + public Double getLatitude() { return this.latitude; } + public Double getLongitude(){ return this.longitude;} + public Double getElevation(){ return this.elevation;} + + public void setLatitude(Double lat) { this.latitude = lat;} + public void setLongitude(Double lon){ this.longitude = lon;} + public void setElevation(Double ele){ this.elevation = ele;} + @Override + public String toString(){ + String result; + result = "lat:"+this.latitude+" lon:"+this.longitude; + return result; + } +} diff --git a/src/main/java/sml/geoUtils/geometry/Polyline.java b/src/main/java/sml/geoUtils/geometry/Polyline.java new file mode 100644 index 0000000..f02dbe4 --- /dev/null +++ b/src/main/java/sml/geoUtils/geometry/Polyline.java @@ -0,0 +1,66 @@ + +package sml.geoUtils.geometry; + +import java.util.ArrayList; +import sml.geoUtils.Calculations; +import sml.gps.datamodel.GPSPoint; + + +public class Polyline<T extends IPointGeo> implements IPolyline<T> { + + ArrayList<Segment<T>> segments; + ArrayList<T> nodes; + Double length; + public Polyline(){ + this.nodes = new ArrayList<T>(); + //this.nodes. + this.invalidateComputedProperties(null); + + } + private void invalidateComputedProperties(Object sender){ + this.length = Double.NaN; + this.segments = null; + } + + public Double getLength(){ + if (Double.isNaN(this.length)){ + this.length = Calculations.getLength((IPolyline<IPointGeo>)this); + } + Double dist = 0.0; + if ( this.nodes.size() > 1 ){ + T oldNode = this.nodes.get(0); + for(int i=1;i<this.nodes.size();i++){ + T node = this.nodes.get(i); + //System.out.println("\t\t i="+i+" node="+this.nodes.get(i).getLatitude()+","+this.nodes.get(i).getLongitude()); + dist = dist + Calculations.getDistance2D(oldNode,node); + oldNode = node; + } + } + this.length = dist/1000.0; + return this.length; + } + public int getNodeCount(){ + return this.nodes.size(); + } + public ArrayList<Segment<T>> getSegments(){ + ArrayList<Segment<T>> result = new ArrayList<Segment<T>>(); + boolean ltrace = true; + if ( false ){ + System.out.println("# nodes="+this.nodes.size()); + for(int i=0; i < this.nodes.size()-1;i++){ + System.out.println("about to create segment from <"+this.nodes.get(i).getLatitude()+","+this.nodes.get(i).getLongitude()+ + "> -- <"+this.nodes.get(i+1).getLatitude()+","+this.nodes.get(i+1).getLongitude()+">"); + } + } + for(int i=0; i < this.nodes.size()-1;i++){ + result.add(new Segment<T>(this.nodes.get(i), this.nodes.get(i+1))); + } + return result; + } + public ArrayList<T> getNodes() { + return this.nodes; + } + public void setNodes(ArrayList<T> newNodes){ + this.nodes = newNodes; + } +} diff --git a/src/main/java/sml/geoUtils/geometry/Segment.java b/src/main/java/sml/geoUtils/geometry/Segment.java new file mode 100644 index 0000000..cb730f9 --- /dev/null +++ b/src/main/java/sml/geoUtils/geometry/Segment.java @@ -0,0 +1,39 @@ + +package sml.geoUtils.geometry; + +import sml.geoUtils.Calculations; + +public class Segment<T extends IPointGeo> { + T startPoint; + T endPoint; + Double length; + public Segment(T start, T end){ + this.startPoint = start; + this.endPoint = end; + this.length = Calculations.getDistance2D(this.startPoint,this.endPoint); + } + public T getStartPoint(){ + return this.startPoint; + } + private void setStartPoint(T startPoint){ + this.startPoint = startPoint; + } + public T getEndPoint(){ + return this.endPoint; + } + private void setEndPoint(T endPoint){ + this.endPoint = endPoint; + } + public Double getLength(){ + return this.length; + } + public boolean equals(Object obj){ + boolean result = false; + Segment<T> other = (Segment<T>)obj; + if (other != null){ + result = this.startPoint.equals(other.startPoint) && this.endPoint.equals(other.endPoint); + } + + return result; + } +} diff --git a/src/main/java/sml/gps/datamodel/GPSPoint.java b/src/main/java/sml/gps/datamodel/GPSPoint.java new file mode 100644 index 0000000..3d842d8 --- /dev/null +++ b/src/main/java/sml/gps/datamodel/GPSPoint.java @@ -0,0 +1,222 @@ + +package sml.gps.datamodel; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import sml.geoUtils.geometry.IPointGeo; + +public class GPSPoint implements IPointGeo { + private Long time; + private Double latitude; + private Double longitude; + private Double elevation; + private Double speed; + private String name; + private String description; + private String commenet; + private Double orientation; + private Double accuracy; + private int altitudeAccuracy; + private Double heading; + private String id =""; + private String type; + private String mac; + private String cellId; + private int areaId; + private Double maxSpeed = -999.999; + private int tag = -1; + final static String PRETEXT = "sml.gps.datamodel.GPSPoint"; + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + public GPSPoint(String id, Double lat, Double lon){ + this.id = id; + this.latitude = lat; + this.longitude = lon; + this.elevation =-999.999; + this.time = Long.MIN_VALUE; + this.orientation = -999.999; + this.accuracy = -999.999; + this.altitudeAccuracy = -999; + this.heading = -999.999; + } + + public GPSPoint(Double lat, Double lon){ + this.latitude = lat; + this.longitude = lon; + this.elevation =-999.999; + this.time = Long.MIN_VALUE; + this.orientation = -999.999; + this.accuracy = -999.999; + this.altitudeAccuracy = -999; + this.heading = -999.999; + } + public GPSPoint(Double lat, Double lon, Long tim){ + super(); + this.latitude = lat; + this.longitude = lon; + this.elevation = -999.999; + this.speed = -999.999; + this.time = tim; + this.orientation = -999.999; + this.accuracy = -999.999; + this.altitudeAccuracy = -999; + this.heading = -999.999; + + } + /* + public GPSPoint(Double lat, Double lon, Long tim, Double elevation){ + this.latitude = lat; + this.longitude = lon; + this.elevation = elevation; + this.time = tim; + }*/ + public GPSPoint(Long time, Double lat, Double lon, Double speed){ + super(); + this.time = time; + this.latitude = lat; + this.longitude = lon; + this.elevation = -999.999; + this.speed = speed; + this.orientation = -999.999; + this.accuracy = -999.999; + this.altitudeAccuracy = -999; + this.heading = -999.999; + } + public GPSPoint(Long time, Double lat, Double lon, Double alt, Double speed, Double ori, Double acc, int altAcc, Double hea){ + super(); + this.time = time; + this.latitude = lat; + this.longitude = lon; + this.elevation = alt; + this.speed = speed; + this.orientation = ori; + this.accuracy = acc; + this.altitudeAccuracy = altAcc; + this.heading = hea; + } + @Override + public void setLatitude(Double lat) {this.latitude = lat;} + @Override + public Double getLatitude() {return this.latitude;} + @Override + public void setLongitude(Double lon){this.longitude = lon;} + @Override + public Double getLongitude() {return this.longitude;} + @Override + public void setElevation(Double ele){this.elevation = ele;} + @Override + public Double getElevation() {return this.elevation;} + public void setTime(Long tim) {this.time = tim;} + public Long getTime() {return this.time;} + public String getTimeString() { + String out = "--"; + if ( time != Long.MIN_VALUE ){ + Date dd = new Date(this.time); + out = df.format(dd); + } + return out; + } + public String getDescription() { + String out = id; + if ( time != Long.MIN_VALUE ){ + Date dd = new Date(this.time); + out = df.format(dd); + } + if ( this.tag == -1 ){ + if ( this.elevation > -900.00 ){ + out = out +":["+String.format("%.2f", this.elevation)+"] <"+this.latitude+","+this.longitude+">"; + } + else{ + out = out + ":<"+this.latitude+","+this.longitude+">"; + } + } + else{ + out = out +":["+this.tag+"] <"+this.latitude+","+this.longitude+">"; + } + if ( speed != null && speed > -900.0 ){ + out = out + " ("+String.format("%.2E", this.speed)+")"; + } + + return out; + } + public void setSpeed(Double speed) {this.speed = speed; } + public Double getSpeed() {return this.speed; } + public GPSPoint copy(){ + GPSPoint newPnt = new GPSPoint(this.getLatitude(),this.getLongitude()); + newPnt.setAccuracy(this.accuracy); + newPnt.setElevation(this.elevation); + newPnt.setId(this.id); + newPnt.setMaxSpeed(this.maxSpeed); + newPnt.setSpeed(this.speed); + newPnt.setTime(this.time); + newPnt.setType(this.type); + newPnt.setMac(this.mac); + newPnt.setCellId(this.cellId); + newPnt.setAreaId(this.areaId); + return newPnt; + } + public Double getAccuracy() { + return accuracy; + } + + public void setAccuracy(Double accuracy) { + this.accuracy = accuracy; + } + public String getCellId() { + return cellId; + } + + public void setCellId(String cellId) { + this.cellId = cellId; + } + public int getAreaId() { + return areaId; + } + + public void setAreaId(int areaId) { + this.areaId = areaId; + } + public String getMac() { + return mac; + } + + public void setMac(String mac) { + this.mac = mac; + } + public String getType() {return this.type;} + public void setType(String type) {this.type = type;} + + public Double getMaxSpeed() { + return maxSpeed; + } + + public void setMaxSpeed(Double maxSpeed) { + this.maxSpeed = maxSpeed; + } + + private void setId(String id) { + this.id = id; + } + + public void changeTag(){ + if ( false ) System.out.println(PRETEXT+".changeTag()::: initial Tag="+this.tag); + switch (this.tag) { + case -1: + this.tag = 0; + break; + case 0: + this.tag = 1; + break; + case 1: + this.tag = -1; + break; + default: + break; + } + if ( false ) System.out.println(PRETEXT+".changeTag()::: final Tag="+this.tag); + } + + public int getTag(){ + return this.tag; + } +} diff --git a/src/main/java/sml/gps/datamodel/GPSPoints.java b/src/main/java/sml/gps/datamodel/GPSPoints.java new file mode 100644 index 0000000..d6d9814 --- /dev/null +++ b/src/main/java/sml/gps/datamodel/GPSPoints.java @@ -0,0 +1,99 @@ +package sml.gps.datamodel; + +import java.awt.Color; +import java.util.ArrayList; +import sml.visualizer.datamodel.Register; + + +public class GPSPoints implements Register { + String name; + Color lineColor = Color.BLUE; + int lineWidth = 1; + Color symbolColor = Color.BLUE; + int symbolSize = 4; + public ArrayList<GPSPoint> pnts = new ArrayList<>(); + @Override + public void setName(String name) {this.name = name;} + @Override + public String getName() {return this.name;} + @Override + public void setLineColor(Color color){this.lineColor = color;} + @Override + public Color getLineColor() {return this.lineColor;} + + @Override + public int getLineWidth() { + return lineWidth; + } + + @Override + public void setLineWidth(int width) { + this.lineWidth = width; + } + + @Override + public int getSymbolSize() { + return symbolSize; + } + + @Override + public void setSymbolSize(int size) { + this.symbolSize = size; + } + public ArrayList<GPSPoint> getPnts() { + return pnts; + } + + public void setPnts(ArrayList<GPSPoint> pnts) { + this.pnts = pnts; + } + + public void add(GPSPoint pnt){ + this.pnts.add(pnt); + } + + @Override + public int getNodeCount() { + return this.pnts.size(); + } + + @Override + public GPSPoint getNode(int i) { + return this.pnts.get(i); + } + + @Override + public int getType() { + return 0; + } + + @Override + public GPSRoute getGPSRoute(){ + return null; + } + + @Override + public GPSPoints getGPSPoints(){ + return this; + } + + @Override + public void remove(int i){ + this.getPnts().remove(i); + } + + @Override + public ArrayList<GPSPoint> getArrayNodes(){ + return this.getPnts(); + } + + @Override + public void setSymbolColor(Color color) { + this.symbolColor = color; + } + + @Override + public Color getSymbolColor() { + return this.symbolColor; + } +} \ No newline at end of file diff --git a/src/main/java/sml/gps/datamodel/GPSRoute.java b/src/main/java/sml/gps/datamodel/GPSRoute.java new file mode 100644 index 0000000..43fef6f --- /dev/null +++ b/src/main/java/sml/gps/datamodel/GPSRoute.java @@ -0,0 +1,191 @@ +package sml.gps.datamodel; + +import java.awt.Color; +import java.util.ArrayList; +import sml.geoUtils.Calculations; +import sml.geoUtils.geometry.Polyline; +import sml.visualizer.datamodel.Register; + +public class GPSRoute extends Polyline<GPSPoint> implements Register { + String name; + Color lineColor = Color.BLUE; + int lineWidth = 1; + Color symbolColor = Color.BLUE; + int symbolSize = 1; + + public GPSRoute(){} + @Override + public void setName(String name) {this.name = name;} + @Override + public String getName() {return this.name;} + @Override + public void setLineColor(Color color){this.lineColor = color;} + @Override + public Color getLineColor() {return this.lineColor;} + + @Override + public void setLineWidth(int width) { + this.lineWidth = width; + } + + @Override + public int getLineWidth() { + return lineWidth; + } + + @Override + public GPSPoint getNode(int i) { + return this.getNodes().get(i); + } + + @Override + public int getType() { + return 1; + } + @Override + public GPSRoute getGPSRoute(){ + return this; + } + + @Override + public GPSPoints getGPSPoints(){ + return null; + } + @Override + public void remove(int i){ + this.getNodes().remove(i); + } + @Override + public ArrayList<GPSPoint> getArrayNodes(){ + return this.getNodes(); + } + + @Override + public void setSymbolColor(Color color) { + this.symbolColor = color; + } + + @Override + public Color getSymbolColor() { + return this.symbolColor; + } + + @Override + public void setSymbolSize(int size) { + this.symbolSize = size; + } + + @Override + public int getSymbolSize() { + return this.symbolSize; + } + @Override + public GPSRoute clone(){ + GPSRoute newRoute = new GPSRoute(); + for(int i=0;i<this.getNodes().size();i++){ + newRoute.getNodes().add(this.getNodes().get(i)); + } + return newRoute; + } + + public Double getDeltaTime(){ + GPSPoint ini = this.getNodes().get(0); + GPSPoint end = this.getNodes().get(this.getNodeCount()-1); + Double delta = (end.getTime() - ini.getTime())/(1000.0*60.0); + return delta; + } + + public void orderNodes(){ + ArrayList<GPSPoint> newNodes = new ArrayList<>(); + for(int i=0;i<this.getNodeCount();i++){ + GPSPoint pnt = this.getNodes().get(i); + Long t = pnt.getTime(); + if ( newNodes.size() > 0 ){ + if ( t > newNodes.get(newNodes.size()-1).getTime() ){ + newNodes.add(pnt); + } + else{ + int j = 0; + for (GPSPoint pt : newNodes) { + if ( t < pt.getTime() ){ break; } + j = j + 1; + } + newNodes.add(j,pnt); + } + } + else{ + newNodes.add(pnt); + } + } + this.setNodes(newNodes); + + } + public void testOrder(){ + for (int i=1;i<this.getNodeCount();i++){ + Long ots = this.getNodes().get(i-1).getTime(); + Long ts = this.getNodes().get(i).getTime(); + if ( ts < ots ){ + System.out.println("PSRoute.testOrder:::: id="+this.getName()+" i="+i+"/"+this.getNodeCount()+" ts="+ts+" ots="+ots); + } + } + + } + public Double getSpeed(){ + GPSPoint last = this.getNodes().get(0); + Double avgSpeed = 0.0; + for(int i=1;i<this.getNodeCount();i++){ + GPSPoint node = this.getNodes().get(i); + Double dist = Calculations.getDistance2D(node, last)/1000.0; + Double delta = (node.getTime() - last.getTime())/(1000.0*60.0*60); + Double speed = dist/delta; + node.setSpeed(speed); + last = node; + avgSpeed = avgSpeed + speed; + } + return avgSpeed/(1.0*this.getNodeCount()); + + } + public void setSpeed(){ + GPSPoint last = this.getNodes().get(0); + for(int i=1;i<this.getNodeCount();i++){ + GPSPoint node = this.getNodes().get(i); + Double dist = Calculations.getDistance2D(node, last)/1000.0; + Double delta = (node.getTime() - last.getTime())/(1000.0*60.0*60); + Double speed = dist/delta; + node.setSpeed(speed); + last = node; + } + } + public Double getIniEndLength(){ + GPSPoint ini = this.getNodes().get(0); + GPSPoint end = this.getNodes().get(this.getNodeCount()-1); + Double ieLength = Calculations.getDistance2D(ini, end)/1000.0; + return ieLength; + } + + public GPSPoint getInterpolatePnt(Long time){ + if ( this.getNode(0).getTime() > time ) { return new GPSPoint(-1000.0,-1000.0,time);}; + if ( this.getNode(this.getNodeCount()-1).getTime() < time ) {return new GPSPoint(-1000.0,-1000.0,time);}; + int i; + for(i=0;i<getNodeCount();i++){ + if ( getNode(i).getTime() > time ){ + break; + } + } + GPSPoint pntIm1 = this.getNode(i-1); + GPSPoint pntI = this.getNode(i); + Double dTIm1 = (time-pntIm1.getTime())*1.0; + Double dTI = (pntI.getTime()-time)*1.0; + Double dTIIm1 = pntI.getTime()-pntIm1.getTime()*1.0; + Double latIm1 = pntIm1.getLatitude(); + Double latI = pntI.getLatitude(); + Double lonIm1 = pntIm1.getLongitude(); + Double lonI = pntI.getLongitude(); + Double dLat = latI - latIm1; + Double dLon = lonI - lonIm1; + Double lat = ( latI * dTIm1 + latIm1 * dTI ) / dTIIm1; + Double lon = ( lonI * dTIm1 + lonIm1 * dTI ) / dTIIm1; + GPSPoint pnt = new GPSPoint(lat,lon,time); + return pnt; + } +} diff --git a/src/main/java/sml/gps/datamodel/GPSSegment.java b/src/main/java/sml/gps/datamodel/GPSSegment.java new file mode 100644 index 0000000..4b6f6cc --- /dev/null +++ b/src/main/java/sml/gps/datamodel/GPSSegment.java @@ -0,0 +1,21 @@ + +package sml.gps.datamodel; + +import sml.geoUtils.geometry.IPointGeo; +import sml.geoUtils.geometry.Segment; + +public class GPSSegment extends Segment<IPointGeo> { + GPSPoint start; + GPSPoint end; + public GPSSegment(GPSPoint start, GPSPoint end){ + super(start,end); + this.start = start; + this.end = end; + } + public Double getTravelTime(){ + return (this.start.getTime() - this.end.getTime())/1000.0/60.0/60.0; + } + public Double getAverageSpeed(){ + return this.getLength()/1000.0/this.getTravelTime(); + } +} diff --git a/src/main/java/sml/gps/datamodel/GPSTrack.java b/src/main/java/sml/gps/datamodel/GPSTrack.java new file mode 100644 index 0000000..67afa2b --- /dev/null +++ b/src/main/java/sml/gps/datamodel/GPSTrack.java @@ -0,0 +1,20 @@ + +package sml.gps.datamodel; + +import java.util.ArrayList; + + +public class GPSTrack { + String name; + ArrayList<GPSTrackSegment> segments; + public GPSTrack(){ + this.segments = new ArrayList<GPSTrackSegment>(); + } + public GPSTrack(String name){ + this.segments = new ArrayList<GPSTrackSegment>(); + this.name = name; + } + public String getName(){return this.name;} + public void setName(String name){this.name = name;} + public ArrayList<GPSTrackSegment> getSegments(){return this.segments;} +} diff --git a/src/main/java/sml/gps/datamodel/GPSTrackSegment.java b/src/main/java/sml/gps/datamodel/GPSTrackSegment.java new file mode 100644 index 0000000..01d9ee9 --- /dev/null +++ b/src/main/java/sml/gps/datamodel/GPSTrackSegment.java @@ -0,0 +1,17 @@ +package sml.gps.datamodel; + +import java.util.ArrayList; +import sml.geoUtils.geometry.Polyline; + + +public class GPSTrackSegment extends Polyline<GPSPoint> { + public GPSTrackSegment(){ + super(); + } + public GPSTrackSegment(ArrayList<GPSPoint> points){ + for(GPSPoint point : points){ + super.getNodes().add(point); + } + } + +} diff --git a/src/main/java/sml/stops/datamodel/StopData.java b/src/main/java/sml/stops/datamodel/StopData.java new file mode 100644 index 0000000..b626cf0 --- /dev/null +++ b/src/main/java/sml/stops/datamodel/StopData.java @@ -0,0 +1,427 @@ +package sml.stops.datamodel; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; +import sml.geoUtils.Calculations; +import sml.gps.datamodel.GPSPoint; +import sml.utils.GeoDistance; + +public class StopData { + + boolean ltrace = false; + private GPSPoint centroidNode; + private ArrayList<GPSPoint> pnts = new ArrayList<>(); + + private Double radious = 0.0; + private Long iniTime; + private Long endTime; + private Double maxDist; + private String nextStopId; + + + public StopData() { + //APos = new ArrayList<ArrayList<Double>>(); + //ATimes = new ArrayList<Long>(); + //centroidNode = new ArrayList<Double>(); + pnts = new ArrayList<>(); + } + public ArrayList<GPSPoint> getPnts(){ + return this.pnts; + } + public StopData(StopData cd){ + this.pnts = new ArrayList<>(); + for(int i=0;i<cd.getPnts().size();i++){ + GPSPoint cdNode = cd.getPnts().get(i); + GPSPoint newNode = cdNode.copy(); + this.pnts.add(newNode); + } + } + + private void calcCentroid() { + + Double centroid_lat = 0.0; + Double centroid_lon = 0.0; + for(int i=0;i<this.pnts.size();i++){ + centroid_lat = centroid_lat + this.pnts.get(i).getLatitude(); + centroid_lon = centroid_lon + this.pnts.get(i).getLongitude(); + } + centroid_lat = centroid_lat / this.pnts.size(); + centroid_lon = centroid_lon / this.pnts.size(); + this.centroidNode = new GPSPoint(centroid_lat,centroid_lon); + } + private void calcRadious() { + this.calcCentroid(); + Double dist = -1.0; + for (int i=0;i<this.pnts.size();i++){ + Double newDist = Calculations.getDistance2D(this.centroidNode,this.pnts.get(i)); + if ( newDist > dist ) dist = newDist; + } + this.radious = dist; + } + private void calcMaxDistance() { + Double dist = -1.0; + for (int i=0;i<this.pnts.size();i++){ + for (int j=i+1;j<this.pnts.size();j++){ + Double newDist = Calculations.getDistance2D(this.pnts.get(j),this.pnts.get(i)); + if ( newDist > dist ) dist = newDist; + } + } + this.maxDist = dist; + } + private void calcIniTime() { + this.iniTime = Long.MAX_VALUE; + for(int i=0;i<this.pnts.size();i++){if ( pnts.get(i).getTime() < this.iniTime) this.iniTime = pnts.get(i).getTime(); + } + if ( this.pnts.get(0).getTime() != this.iniTime ){ + System.out.println("ClusteringData id="+this.iniTime+" not ordered in time ATimes.get(0)="+this.pnts.get(0).getTime()+", iniTime="+this.iniTime); + } + this.iniTime = this.pnts.get(0).getTime(); + } + private void calcEndTime() { + this.endTime = Long.MIN_VALUE; + for(int i=0;i<this.pnts.size();i++){if ( this.pnts.get(i).getTime() > this.endTime) this.endTime = this.pnts.get(i).getTime();} + if ( this.endTime-this.pnts.get(this.pnts.size()-1).getTime() != 0 ){ + System.out.println("ClusteringData id="+this.iniTime+" not ordered in time ATimes.get(last)="+this.pnts.get(this.pnts.size()-1).getTime()+", endTime="+this.endTime); + } + this.endTime = this.pnts.get(this.pnts.size()-1).getTime(); + } + public void addNode(GPSPoint newNode) { + if ( ltrace ) System.out.println("addNode::in StopData "+this.iniTime+" size="+this.pnts.size()); + boolean done = false; + for(int i=0; i<this.pnts.size();i++){ + if ( this.pnts.get(i).getTime() == newNode.getTime() ){ + this.pnts.set(i,newNode); + done = true; + break; + } + else if ( this.pnts.get(i).getTime() > newNode.getTime() ){ + this.pnts.add(i, newNode); + + done = true; + break; + } + } + if ( !done ){ + this.pnts.add(newNode); + } + calcCentroid(); + calcRadious(); + if ( ltrace ) System.out.println("addNode::in ClusterData "+this.iniTime+" size="+this.pnts.size()); + } + public void addNode(GPSPoint newNode, boolean beginning) { + if ( ltrace ) System.out.println("addNode::in ClusterData "+this.iniTime+" size="+this.pnts.size()); + if ( beginning ){ + this.pnts.add(0,newNode); + } + else{ + this.pnts.add(newNode); + } + calcCentroid(); + calcRadious(); + if ( ltrace ) System.out.println("addNode::in ClusterData "+this.iniTime+" size="+this.pnts.size()); + } + public void writeToFile() { + try { + Long ini = this.getIniTime(); + Date d = new Date(ini*1000); + Calendar cal = null; + cal = Calendar.getInstance(); + cal.setTime(d); + String dirName = cal.get(Calendar.YEAR)+"_"+(cal.get(Calendar.MONTH)+1)+"_"+ cal.get(Calendar.DAY_OF_MONTH); + File theDir = new File(dirName); + if ( ltrace ) + System.out.println("ClusterData.writeToFile::: theDir="+theDir+" ini="+getIniTime()); + if (!theDir.exists()) { + if ( ltrace ) + System.out.println("Creating directory: " + dirName); + boolean result = theDir.mkdir(); + if ( result && ltrace ) {System.out.println("DIR created");} + } + File theFile = new File(dirName+"/"+this.getIniTime()+".csv"); + PrintWriter writer = new PrintWriter(theFile, "UTF-8"); + writer.println(this.iniTime+","+this.nextStopId); + for (int i=0;i<this.pnts.size();i++){ + GPSPoint node = this.pnts.get(i); + writer.println(node.getTime()+","+node.getLatitude()+","+node.getLongitude()); + } + writer.close(); + } catch (FileNotFoundException ex) { + Logger.getLogger(StopData.class.getName()).log(Level.SEVERE, null, ex); + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(StopData.class.getName()).log(Level.SEVERE, null, ex); + } + + } + public String getId() {return this.iniTime+"";} + public String getInfo() { + String info = "#################\n"; + info = info + " id ="+this.getId()+"\n"; + info = info + " size ="+this.getSize()+"\n"; + info = info + " iTime="+this.getIniTime()+"\n"; + int totalSecs = (int) (this.getEndTime()-this.getIniTime()); + int hours = Math.round(totalSecs/3600); + int partSecs = totalSecs - hours*3600; + int mins = Math.round(partSecs/60); + int secs = partSecs - mins*60; + info = info + " ini Date="+new Date( getIniTime()* 1000 ).toString()+"\n"; + info = info + " ini Hour="+this.getIniTimeOfDay()+"\n"; + info = info + " end Date="+new Date( getEndTime()* 1000 ).toString()+"\n"; + info = info + " end Hour="+this.getEndTimeOfDay()+"\n"; + info = info + " DeltaT="+hours+"h"+mins+"m"+secs+"s\n"; + info = info + " Next Clus id="+this.nextStopId+"\n"; + info = info + " Centroid=<"+this.getCentroid().getLatitude()+","+this.getCentroid().getLongitude()+">\n"; + info = info + " Radious="+getRadious()+"\n"; + info = info + "#################\n"; + return info; + } + public int getSize() {return this.pnts.size();} + public Long getIniTime() {this.calcIniTime();return this.iniTime;} + public Long getEndTime() {this.calcEndTime();return this.endTime;} + public Long getDeltaTime() { + Long DeltaTime = (this.getEndTime()-this.getIniTime())/1000; + return DeltaTime; + } + public Date getIniDate() {return new Date( this.getIniTime()* 1000 );} + public Date getEndDate() {return new Date( this.getEndTime()* 1000 );} + public int getIniTimeOfDay() { + Calendar cal = Calendar.getInstance(); + cal.setTime(getIniDate()); + int hour = cal.get(Calendar.HOUR_OF_DAY); + int min = cal.get(Calendar.MINUTE); + int sec = cal.get(Calendar.SECOND); + int timeOfDay = hour*60*60+min*60+sec; + return timeOfDay; + } + public int getEndTimeOfDay() { + Calendar cal = Calendar.getInstance(); + cal.setTime(getEndDate()); + int hour = cal.get(Calendar.HOUR_OF_DAY); + int min = cal.get(Calendar.MINUTE); + int sec = cal.get(Calendar.SECOND); + int timeOfDay = hour*60*60+min*60+sec; + return timeOfDay; + } + public Date getIniDayDate() { + return new Date((this.getIniTime()-getIniTimeOfDay())*1000); + } + public Date getEndDayDate() { + return new Date((this.getEndTime()-getEndTimeOfDay())*1000); + } + public int getIniWeekDay() { + Calendar c = Calendar.getInstance(); + c.setTime(this.getIniDate()); + int dayOfWeek = c.get(Calendar.DAY_OF_WEEK); + return dayOfWeek; + } + public int getEndWeekDay() { + Calendar c = Calendar.getInstance(); + c.setTime(this.getEndDate()); + int dayOfWeek = c.get(Calendar.DAY_OF_WEEK); + return dayOfWeek; + } + public GPSPoint getCentroid() {this.calcCentroid();return this.centroidNode;} + public Double getMaxDist() {this.calcMaxDistance(); return this.maxDist;} + public Double getRadious() {this.calcRadious();return this.radious;} + public String getNextStop() { + return this.nextStopId; + } + public void setNextStop(String nextStopId) { + this.nextStopId = nextStopId; + } + public boolean compare(StopData otherClus, double maxDistance) { + boolean joinable = false; + if ( Calculations.getDistance2D(this.getCentroid(),otherClus.getCentroid()) < maxDistance ){ + // && (otherClus.getIniTime()- this.getEndTime()) < 60*5 ){ + joinable = true; + } + return joinable; + } + public StopData joinTwoStopData (StopData otherStop) { + StopData newStop = new StopData(); + if ( ltrace ) System.out.println("joinTwoStopData:::stop1.size="+this.getSize()+" stop2.size="+otherStop.getSize()); + for (int i=0;i<this.getSize();i++){ + newStop.addNode(this.getPnts().get(i)); + } + for (int i=0;i<otherStop.getSize();i++){ + newStop.addNode(otherStop.getPnts().get(i)); + } + if ( ltrace ) System.out.println("joinTwoStopData:::newStop.size="+newStop.getSize()); + return newStop; + } + public boolean checkStopData ( double maxSpread, int minTimeI ) { + boolean ok = true; + if ( this.getSize() == 1 || this.getMaxDist() > maxSpread || this.getDeltaTime() < minTimeI ){ ok = false; } + return ok; + } + public boolean checkStopData (double maxSpread, + int minTimeI, + int iNumTestPoints, + double randWalkPercent, + boolean beginning ){ + boolean ok = true; + if ( ltrace ) System.out.println(""); + + int numTestPoints = Math.min(iNumTestPoints,this.pnts.size()); + if ( ltrace ) System.out.println("checkClusterData::: randWalkPercent="+randWalkPercent+", numTestPoints="+numTestPoints+", begining="+beginning); + GPSPoint iniNode = null; + GPSPoint endNode = null; + if ( checkStopData(maxSpread,minTimeI) == false ){ + return false; + } + if ( beginning ){ + iniNode = this.pnts.get(0); + endNode = this.pnts.get(numTestPoints-1); + } + else{ + iniNode = this.pnts.get(this.getSize()-numTestPoints); + endNode = this.pnts.get(this.getSize()-1); + } + double ieDist = Calculations.getDistance2D(iniNode, endNode); + double totalDist = 0.0; + int j = 1; + for (int i=1; i<numTestPoints;i++){ + if ( !beginning ) {j = this.getSize()-numTestPoints+i;} + endNode = this.pnts.get(j); + totalDist = totalDist + Calculations.getDistance2D(iniNode, endNode); + iniNode = endNode; + if ( false ) System.out.println("checkClusterData::: "+i+"-> td("+j+")="+totalDist); + j++; + } + if ( totalDist+0.0001 < (1.0+randWalkPercent)*ieDist && + numTestPoints > iNumTestPoints-1 ){ + ok=false; + } + if ( ltrace ) System.out.println("checkClusterData::: ok="+ok+" tD="+totalDist+", ieD="+ieDist); + if ( totalDist+0.0001 < ieDist ){ + System.out.println("\n"); + System.out.println("!!!!!ALARM!!!!!!"); + System.out.println("checkClusterData::: begining="+beginning+", ok="+ok+" tD="+totalDist+", ieD="+ieDist+ + ", numTestPoints="+numTestPoints+", beginning="+beginning); + if ( beginning ){ + iniNode = this.pnts.get(0); + endNode = this.pnts.get(numTestPoints-1); + } + else{ + iniNode = this.pnts.get(this.getSize()-numTestPoints); + endNode = this.pnts.get(this.getSize()-1); + } + + totalDist = 0.0; + j = 1; + for (int i=1; i<numTestPoints;i++){ + if ( !beginning ) {j = this.getSize()-numTestPoints+i;} + endNode = this.pnts.get(j); + totalDist = totalDist + Calculations.getDistance2D(iniNode, endNode); + + if ( true ) System.out.println("checkClusterData::: "+i+"-> td("+j+")="+totalDist+ + " <"+iniNode.getLatitude()+","+iniNode.getLongitude()+"> -- <"+endNode.getLatitude()+","+endNode.getLongitude()+">["+Calculations.getDistance2D(iniNode, endNode)+"]"); + iniNode = endNode; + j++; + } + if ( beginning ){ + for(int i=0;i<numTestPoints;i++){ + GPSPoint node = this.pnts.get(i); + System.out.println("<"+node.getLatitude()+","+node.getLongitude()+">"); + } + }else{ + for(int i=0;i<numTestPoints;i++){ + GPSPoint node = this.pnts.get(this.pnts.size()-1-i); + System.out.println("<"+node.getLatitude()+","+node.getLongitude()+">"); + } + } + System.out.println("!!!!!ALARM!!!!!!"); + System.out.println("\n"); + } + + + return ok; + } + public boolean checkStopDataO ( double maxSpread, + int minTimeI, + int iNumTestPoints, + double randWalkPercent, + boolean beginning ) { + boolean ok = true; + if ( ltrace ) System.out.println(""); + + int numTestPoints = Math.min(iNumTestPoints,this.pnts.size()); + if ( ltrace ) System.out.println("checkClusterData::: randWalkPercent="+randWalkPercent+", numTestPoints="+numTestPoints+", begining="+beginning); + GPSPoint iniNode = null; + GPSPoint endNode = null; + if ( checkStopData(maxSpread,minTimeI) == false ){ + return false; + } + if ( beginning ){ + iniNode = this.pnts.get(0); + endNode = this.pnts.get(numTestPoints-1); + } + else{ + iniNode = this.pnts.get(this.getSize()-numTestPoints); + endNode = this.pnts.get(this.getSize()-1); + } + double ieDist = Calculations.getDistance2D(iniNode, endNode); + double totalDist = 0.0; + int j = 1; + for (int i=1; i<numTestPoints;i++){ + if ( !beginning ) {j = this.getSize()-numTestPoints+i;} + endNode = this.pnts.get(j); + totalDist = totalDist + Calculations.getDistance2D(iniNode, endNode);; + iniNode = endNode; + if ( false ) System.out.println("checkClusterData::: "+i+"-> td("+j+")="+totalDist); + j++; + } + if ( totalDist+0.0001 < (1.0+randWalkPercent)*ieDist && + numTestPoints > iNumTestPoints-1 ){ + ok=false; + } + if ( ltrace ) System.out.println("checkClusterData::: ok="+ok+" tD="+totalDist+", ieD="+ieDist); + if ( totalDist+0.0001 < ieDist ){ + System.out.println("\n"); + System.out.println("!!!!!ALARM!!!!!!"); + System.out.println("checkClusterData::: begining="+beginning+", ok="+ok+" tD="+totalDist+", ieD="+ieDist+ + ", numTestPoints="+numTestPoints+", beginning="+beginning); + if ( beginning ){ + iniNode = this.pnts.get(0); + endNode = this.pnts.get(numTestPoints-1); + } + else{ + iniNode = this.pnts.get(this.getSize()-numTestPoints); + endNode = this.pnts.get(this.getSize()-1); + } + + totalDist = 0.0; + j = 1; + for (int i=1; i<numTestPoints;i++){ + if ( !beginning ) {j = this.getSize()-numTestPoints+i;} + endNode = this.pnts.get(j); + totalDist = totalDist + Calculations.getDistance2D(iniNode, endNode); + + if ( true ) System.out.println("checkClusterData::: "+i+"-> td("+j+")="+totalDist+ + " <"+iniNode.getLatitude()+","+iniNode.getLongitude()+"> -- <"+endNode.getLatitude()+","+endNode.getLongitude()+">["+Calculations.getDistance2D(iniNode, endNode)+"]"); + iniNode = endNode; + j++; + } + if ( beginning ){ + for(int i=0;i<numTestPoints;i++){ + GPSPoint node = this.pnts.get(i); + System.out.println("<"+node.getLatitude()+","+node.getLongitude()+">"); + } + }else{ + for(int i=0;i<numTestPoints;i++){ + GPSPoint node = this.pnts.get(this.pnts.size()-1-i); + System.out.println("<"+node.getLatitude()+","+node.getLongitude()+">"); + } + } + System.out.println("!!!!!ALARM!!!!!!"); + System.out.println("\n"); + } + return ok; + } +} diff --git a/src/main/java/sml/utils/Calculations.java b/src/main/java/sml/utils/Calculations.java new file mode 100644 index 0000000..6cb0af9 --- /dev/null +++ b/src/main/java/sml/utils/Calculations.java @@ -0,0 +1,71 @@ +package sml.utils; + +import sml.geoUtils.geometry.IPointGeo; +import sml.geoUtils.geometry.IPolyline; +import sml.geoUtils.geometry.PointGeo; +import sml.geoUtils.geometry.Segment; +import sml.gps.datamodel.GPSPoint; + + + + + +public class Calculations { + public static Double EARTH_RADIOUS = 6371010.0; + public static Double EPS_LENGTH = 0.01; + //static GreatCircleDistanceCalculator distanceCalculator; + + public static Double getBearing(IPointGeo pt1, IPointGeo pt2){ + Double dLon = Calculations.toRadians(pt1.getLongitude()-pt2.getLongitude()); + Double dLat = Calculations.toRadians(pt1.getLatitude()-pt2.getLatitude()); + + Double y = Math.sin(dLon) * Math.cos(Calculations.toRadians(pt2.getLatitude())); + Double x = Math.cos(Calculations.toRadians(pt1.getLatitude())) * Math.sin(Calculations.toRadians(pt2.getLatitude())) + - Math.sin(Calculations.toRadians(pt1.getLatitude())) * Math.cos(Calculations.toRadians(pt2.getLatitude())) * Math.cos(dLon); + return Calculations.toDegrees(Math.atan2(y, x)); + } + public static Double getBearing(Segment<IPointGeo> segment){ + return Calculations.getBearing(segment.getStartPoint(), segment.getEndPoint()); + }; + public static Double getDistance2D(GPSPoint pt1, GPSPoint pt2){ + return GeoDistance.CalcDistance(pt1,pt2); + } + public static Double getDistance2D(IPointGeo pt1, IPointGeo pt2){ + //System.out.println("pt1=<"+pt1.getLatitude()+","+pt1.getLongitude()+">"); + //System.out.println("pt1=<"+pt2.getLatitude()+","+pt2.getLongitude()+">"); + if( pt1 == null ){ System.err.println("Calculations.getDistance:::pt1=null"); System.exit(1);} + if( pt2 == null ){ System.err.println("Calculations.getDistance:::pt2=null"); System.exit(1);} + return Calculations.getDistance2D(pt1, pt2); + } + public static Double getPathLength(IPointGeo from, IPointGeo to, Segment<IPointGeo> path){ + return Calculations.getDistance2D(from, to); + } + public static Long getPathTime(IPointGeo from, IPointGeo to, Segment<IPointGeo> path){ + Double length = getPathLength(from, to, path); + return 10L; + } + public static Double getLength(IPolyline<IPointGeo> line){ + Double length = 0.0; + for(Segment segment : line.getSegments()){ + length = length + segment.getLength(); + } + return length; + } + public static PointGeo Averaging(Iterable<IPointGeo> points){ + int count = 0; + Double lat = 0.0; + Double lon = 0.0; + for(IPointGeo point : points){ + lat = lat + point.getLatitude(); + lon = lon + point.getLongitude(); + count = count + 1; + } + return new PointGeo(lat/count, lon/count, -1.0092); + } + public static Double toRadians(Double angle){ + return angle * Math.PI / 180.0; + } + public static double toDegrees(Double angle){ + return angle * 180.0 / Math.PI; + } +} diff --git a/src/main/java/sml/utils/GeoDistance.java b/src/main/java/sml/utils/GeoDistance.java new file mode 100644 index 0000000..5ebceb0 --- /dev/null +++ b/src/main/java/sml/utils/GeoDistance.java @@ -0,0 +1,30 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sml.utils; + +import java.util.ArrayList; +import sml.gps.datamodel.GPSPoint; + +public class GeoDistance { + static public Double CalcDistance(GPSPoint pnt1, GPSPoint pnt2){ + return GeoDistance.calcDistance(pnt1.getLatitude(),pnt2.getLatitude(),pnt1.getLongitude(),pnt2.getLongitude()); + } + static public Double calcDistance(Double lat1, Double lat2, Double lon1, Double lon2){ + lat1 = Math.toRadians(lat1); + lat2 = Math.toRadians(lat2); + lon1 = Math.toRadians(lon1); + lon2 = Math.toRadians(lon2); + Double distance = 0.0; + distance = Math.sqrt((lat1-lat2)*(lat1-lat2) + (lon1-lon2)*(lon1-lon2)*Math.cos(lat1)*Math.cos(lat2))*6371.0; + return distance; + } + static public Double calcDist(ArrayList<Double> Node1, ArrayList<Double> Node2){ + Double lat1 = Node1.get(0); + Double lat2 = Node2.get(0); + Double lon1 = Node1.get(1); + Double lon2 = Node2.get(1); + return calcDistance(lat1,lat2,lon1,lon2); + } +} diff --git a/src/main/java/sml/utils/PolyLineEncoder.java b/src/main/java/sml/utils/PolyLineEncoder.java new file mode 100644 index 0000000..9c4420a --- /dev/null +++ b/src/main/java/sml/utils/PolyLineEncoder.java @@ -0,0 +1,89 @@ + +package sml.utils; + +import java.util.ArrayList; + +public class PolyLineEncoder { +private static Double precision = 1.0E6; +private static StringBuffer encodeSignedNumber(int num) { + int sgn_num = num << 1; + if (num < 0) { + sgn_num = ~(sgn_num); + } + return(encodeNumber(sgn_num)); + } + + private static StringBuffer encodeNumber(int num) { + StringBuffer encodeString = new StringBuffer(); + while (num >= 0x20) { + int nextValue = (0x20 | (num & 0x1f)) + 63; + encodeString.append((char)(nextValue)); + num >>= 5; + } + num += 63; + encodeString.append((char)(num)); + return encodeString; + } + + /** + * Encode a polyline with Google polyline encoding method + * @param polyline the polyline + * @param precision 1 for a 6 digits encoding, 10 for a 5 digits encoding. + * @return the encoded polyline, as a String + */ + public static String encode(ArrayList<ArrayList<Double>> polyline) { + StringBuffer encodedPoints = new StringBuffer(); + int prev_lat = 0, prev_lng = 0; + for (ArrayList<Double> trackpoint:polyline) { + int lat = (int) Math.round(trackpoint.get(0)*precision); + int lng = (int) Math.round(trackpoint.get(1)*precision); + encodedPoints.append(encodeSignedNumber(lat - prev_lat)); + encodedPoints.append(encodeSignedNumber(lng - prev_lng)); + prev_lat = lat; + prev_lng = lng; + } + return encodedPoints.toString(); + } + + /** + * Decode a "Google-encoded" polyline + * @param encodedString + * @param precision 1 for a 6 digits encoding, 10 for a 5 digits encoding. + * @return the polyline. + */ + public static ArrayList<ArrayList<Double>> decode(String encodedString) { + ArrayList<ArrayList<Double>> polyline = new ArrayList<ArrayList<Double>>(); + int index = 0; + int len = encodedString.length(); + int lat = 0, lng = 0; + + while (index < len) { + int b, shift = 0, result = 0; + do { + b = encodedString.charAt(index++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); + int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); + lat += dlat; + + shift = 0; + result = 0; + do { + b = encodedString.charAt(index++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); + int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); + lng += dlng; + + ArrayList<Double> pos = new ArrayList<Double>(); + pos.add((Double) (lat/precision)); + pos.add((Double) (lng/precision)); + polyline.add(pos); + } + + return polyline; + } + +} diff --git a/src/main/java/sml/utils/RawData.java b/src/main/java/sml/utils/RawData.java new file mode 100644 index 0000000..b04a748 --- /dev/null +++ b/src/main/java/sml/utils/RawData.java @@ -0,0 +1,54 @@ +package sml.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; + + +public class RawData { + private ArrayList<ArrayList<Double>> APos = new ArrayList<ArrayList<Double>>(); + private ArrayList<Long> ATimes = new ArrayList<Long>(); + private ArrayList<Double> AVels = new ArrayList<Double>(); + private File file; + + public RawData(File file) { + this.file = file; + readData(); + } + private void readData() { + BufferedReader br = null; + String line = ""; + String cvsSplitBy = ","; + try { + br = new BufferedReader(new FileReader(this.file.getAbsolutePath())); + int k=0; + + while ((line = br.readLine()) != null) { + String[] lineText = line.split(cvsSplitBy); + this.ATimes.add(Long.parseLong(lineText[0])/1000); + Double vel = -1.0; + if ( lineText.length > 2 ){ + if (!"".equals(lineText[3]) || lineText[3] != null){ + vel = Double.parseDouble(lineText[3]); + } + } + AVels.add(vel); + ArrayList<Double> Node = new ArrayList<Double>(); + Node.add(Double.parseDouble(lineText[1])); + Node.add(Double.parseDouble(lineText[2])); + this.APos.add(Node); + k++; + } + + } catch (IOException ex) { + System.out.println("problem accessing file"+this.file.getAbsolutePath()); + } + } + public File getFile() {return this.file;} + public int getSize() {return this.APos.size();} + public ArrayList<ArrayList<Double>> getAPos() {return this.APos;} + public ArrayList<Long> getATimes(){return this.ATimes;} + public ArrayList<Double> getAVels() {return this.AVels;} +} diff --git a/src/main/java/sml/visualizer/datamodel/Register.java b/src/main/java/sml/visualizer/datamodel/Register.java new file mode 100644 index 0000000..75872a4 --- /dev/null +++ b/src/main/java/sml/visualizer/datamodel/Register.java @@ -0,0 +1,29 @@ +package sml.visualizer.datamodel; + + +import java.awt.Color; +import java.util.ArrayList; +import sml.gps.datamodel.GPSPoint; +import sml.gps.datamodel.GPSPoints; +import sml.gps.datamodel.GPSRoute; + + +public interface Register { + public int getType(); + public void setName(String name); + public String getName(); + public void setLineColor(Color color); + public Color getLineColor(); + public void setLineWidth(int width); + public int getLineWidth(); + public void setSymbolColor(Color color); + public Color getSymbolColor(); + public void setSymbolSize(int size); + public int getSymbolSize(); + public int getNodeCount(); + public GPSPoint getNode(int i); + public GPSRoute getGPSRoute(); + public GPSPoints getGPSPoints(); + public ArrayList<GPSPoint> getArrayNodes(); + public void remove(int i); +} diff --git a/src/main/java/sml/visualizer/gui/functions/DivideInTraysCover.java b/src/main/java/sml/visualizer/gui/functions/DivideInTraysCover.java new file mode 100644 index 0000000..330710e --- /dev/null +++ b/src/main/java/sml/visualizer/gui/functions/DivideInTraysCover.java @@ -0,0 +1,70 @@ +package sml.visualizer.gui.functions; + +import java.util.ArrayList; +import sml.gps.datamodel.GPSPoint; +import sml.gps.datamodel.GPSRoute; +import sml.stops.datamodel.StopData; + +public class DivideInTraysCover { + + private GPSRoute route; + private final static String PRETEXT = "sml.visualizer.gui.functions.DivideInTraysCover"; + + public DivideInTraysCover(GPSRoute route){ + this.route = route; + //doFindingTrays(); + } + public ArrayList<GPSRoute> doFindingTrays(){ + ArrayList<GPSRoute> out = new ArrayList<>(); + + double maxSpread = 0.2; + double minTime = 10; + double maxVel = 2.0; + int numPoints = 4; + double randWalk = 0.02; + FindStops fs = new FindStops(maxSpread,minTime,maxVel,numPoints,randWalk); + fs.addRawData(route); + ArrayList<StopData> stops = fs.doStops(); + ArrayList<Long> iniStops = new ArrayList<>(); + ArrayList<Long> endStops = new ArrayList<>(); + for(int s=0;s<stops.size();s++){ + iniStops.add(stops.get(s).getIniTime()); + endStops.add(stops.get(s).getEndTime()); + System.out.println(PRETEXT+".doFindingTrays::: CDR stop="+s+" ["+stops.get(s).getIniTime()+","+stops.get(s).getEndTime()+"]"); + } + iniStops.add(Long.MAX_VALUE); + endStops.add(Long.MAX_VALUE); + int s = 0; + GPSRoute routeTray = null; + + Long time; + boolean inStop = false; + time = route.getNodes().get(0).getTime(); + if ( time < iniStops.get(s) ){ + routeTray = new GPSRoute(); + routeTray.setName(route.getName()+"_tray_-1"); + + } + for(int p=0;p<route.getNodeCount();p++){ + time = route.getNodes().get(p).getTime(); + if ( time >= iniStops.get(s) && time < endStops.get(s) ){ + inStop = true; + } + else if ( time >= endStops.get(s) ){ + routeTray = new GPSRoute(); + routeTray.setName(route.getName()+"_tray_"+s); + out.add(routeTray); + + s++; + inStop = false; + } + if ( !inStop ){ + GPSPoint pnt = route.getNodes().get(p); + routeTray.getNodes().add(pnt); + + } + } + + return out; + } +} diff --git a/src/main/java/sml/visualizer/gui/functions/FindStops.java b/src/main/java/sml/visualizer/gui/functions/FindStops.java new file mode 100644 index 0000000..df5819f --- /dev/null +++ b/src/main/java/sml/visualizer/gui/functions/FindStops.java @@ -0,0 +1,364 @@ +package sml.visualizer.gui.functions; + +import java.util.ArrayList; +import sml.gps.datamodel.GPSPoint; +import sml.gps.datamodel.GPSRoute; +import sml.stops.datamodel.StopData; +import sml.utils.GeoDistance; + +public class FindStops { + + private ArrayList<ArrayList<Double>> APos = new ArrayList<ArrayList<Double>>(); + private ArrayList<Long> ATimes = new ArrayList<Long>(); + private ArrayList<Double> AVels = new ArrayList<Double>(); + private ArrayList<StopData> stops = new ArrayList<StopData>(); + private ArrayList<ArrayList<Integer>> AStopIndxs = new ArrayList<ArrayList<Integer>>(); + // For the loop... + private StopData currentStop = null; + private ArrayList<Integer> stopIndxs = new ArrayList<Integer>(); + //////////////////////////////////////////////////////////////////// + private double maxSpread = 0.4; + private double minTime = 0.4; + private int minTimeI = 24; + private double maxVel = 2.0; + private int numTestPoints = 4; + private double randWalkPercent = 0.35; + private int oldI = -1; + public FindStops() { + APos = new ArrayList<>(); + ATimes = new ArrayList<>(); + AVels = new ArrayList<>(); + }; + public FindStops(double maxSpread, // maximum Spreading for clusters + double minTime, // minimum time for a LoI + double maxVel, // maximum velocity for initial cluster identification + int numTestPoints, // # test points for linearity + double randWalkPercent // measure of the random walk-enes. + ) { + APos = new ArrayList<>(); + ATimes = new ArrayList<>(); + AVels = new ArrayList<>(); + this.maxSpread = maxSpread; + this.minTime = minTime; + this.minTimeI = (int) Math.round(minTime*60); + this.maxVel = maxVel; + this.numTestPoints = numTestPoints; + this.randWalkPercent = randWalkPercent; + } + + public void addRawData(GPSRoute rd) { + ArrayList<ArrayList<Double>> newAPos = new ArrayList<>(); + ArrayList<Long> newATimes = new ArrayList<>(); + ArrayList<Double> newAVels = new ArrayList<>(); + for(int i=0;i<rd.getNodeCount();i++){ + ArrayList<Double> pos = new ArrayList<>(); + pos.add(rd.getNodes().get(i).getLatitude()); + pos.add(rd.getNodes().get(i).getLongitude()); + newAPos.add(pos); + newATimes.add(rd.getNodes().get(i).getTime()/1000); + newAVels.add(rd.getNodes().get(i).getSpeed()); + } + for (int j=0;j<newATimes.size();j++){ + Long newTime = newATimes.get(j); + ArrayList<Double> newNode = newAPos.get(j); + Double newVel = newAVels.get(j); + boolean done = false; + if ( oldI >= 0 ){ if ( this.ATimes.get(oldI) > newTime ){ oldI = 0;} } + else { oldI = 0;} + for(int i=oldI; i<this.ATimes.size();i++){ + if ( this.ATimes.get(i) == newTime ){ + this.APos.set(i, newNode); + this.AVels.set(i, newVel); + done = true; + oldI = i; + break; + } + else if ( this.ATimes.get(i) > newTime ){ + this.ATimes.add(i, newTime); + this.APos.add(i,newNode); + this.AVels.add(i,newVel); + done = true; + oldI = i; + break; + } + } + if ( !done ){ + oldI = this.ATimes.size(); + this.ATimes.add(newTime); + this.APos.add(newNode); + this.AVels.add(newVel); + } + } + /* + System.out.println("FindStops.addRawData:::size(output)="+ATimes.size()); + for(int i=0;i<this.ATimes.size();i++){ + System.out.println("time="+this.ATimes.get(i)+" <"+this.APos.get(i).get(0)+","+this.APos.get(i).get(1)+"> ("+this.AVels.get(i)+")"); + }*/ + } + private void calcZeroVelClusters() { + double vel; + boolean ltrace = false; + Long time; + Long lastTime = -1L; + Long minStop = Math.round(maxSpread/maxVel*3600L); + //Long minStop = 5*60L; + System.out.println("minStop="+minStop); + boolean inStop = false; + ArrayList<Double> node = new ArrayList<>(); + ArrayList<Double> lastNode = new ArrayList<>(); + ArrayList<Double> nextNode = new ArrayList<>(); + currentStop = null; + for (int i=0;i<ATimes.size();i++){ + time = ATimes.get(i); + vel = AVels.get(i); + node = APos.get(i); + //if ( time == 1378874028 || lastTime == 1378874028) ltrace = true; + //else ltrace = false; + if (ltrace) + System.out.println("i:: "+i+" time="+time+", vel="+vel+", inStop"+inStop+", currentCluster="+currentStop); + if ( vel < maxVel ){ + if (ltrace) System.out.println("vel<maxVel"); + inStop = addRawPointToCluster(time, i, node, lastNode, inStop); + } + else if ( time-lastTime > minStop && !inStop ){ + if (ltrace) System.out.println("in the past!!"); + inStop = addRawPointToCluster(time, i, node, lastNode, inStop); + } + else if ( i< ATimes.size()-1 && ATimes.get(i+1)-ATimes.get(i) > minStop ){ + if (ltrace) System.out.println("in the future!!"); + nextNode = APos.get(i+1); + inStop = addRawPointToCluster(time, i, node, nextNode, inStop); + } + else{ + inStop = false; + } + lastNode = node; + lastTime = time; + } + for(int i=0;i<stops.size();i++){ + if (stops.get(i).getRadious()> maxSpread ) + System.out.println(i+": radious"+stops.get(i).getRadious()+"!!!!!!!!!!!!!!!!!!!!"); + } + } + private boolean addRawPointToCluster(long time, int i, + ArrayList<Double> node, ArrayList<Double> otherNode, + boolean inStop) { + boolean lInStop = inStop; + boolean ltrace = false; + GPSPoint pnt = new GPSPoint(node.get(0),node.get(1),time*1000); + if ( i == 860 || i == 859 ) ltrace = true; + else ltrace = false; + if ( ltrace ){ + System.out.println("time="+time+" i="+i+" inStop="+inStop+" otherNode.size()="+otherNode.size()+ + " node=<"+node.get(0)+","+node.get(1)+"> otherNode="+otherNode.get(0)+","+otherNode.get(1)+"> D="+GeoDistance.calcDist(node,otherNode)); + } + if ( otherNode.size() > 0 ){ + if ( GeoDistance.calcDist(node,otherNode) < maxSpread ){ + + if ( !lInStop ){ + lInStop = true; + currentStop = new StopData(); + stopIndxs = new ArrayList<>(); + AStopIndxs.add(stopIndxs); + stops.add(currentStop); + } + + currentStop.addNode(pnt); + stopIndxs.add(i); + } + else{ + lInStop = false; + } + } + else{ + if ( !lInStop ){ + lInStop = true; + currentStop = new StopData(); + stopIndxs = new ArrayList<Integer>(); + AStopIndxs.add(stopIndxs); + stops.add(currentStop); + } + currentStop.addNode(pnt); + stopIndxs.add(i); + } + if ( lInStop && ltrace ) System.out.println("point added to cluster cluster.size()="+currentStop.getSize()); + return lInStop; + } + private void joinStops() { + int oldStopsSize = this.stops.size(); + int newStopsSize = -this.stops.size(); + System.out.println("joinClusters::: (on input) clusterSize="+oldStopsSize); + int pass = 0; + while ( newStopsSize != oldStopsSize ){ + System.out.println(" joinStops::: pass="+pass+" size="+newStopsSize); + int initialStop = 0; + this.stops = this.joinStopsSinglePass(this.stops,initialStop); + initialStop = 1; + this.stops = this.joinStopsSinglePass(this.stops,initialStop); + oldStopsSize = newStopsSize; + newStopsSize = this.stops.size(); + pass++; + } + System.out.println("joinStops::: (on output) stopsSize="+newStopsSize); + } + private ArrayList<StopData> joinStopsSinglePass(ArrayList<StopData> clusters, int initialStop){ + int limit = clusters.size(); + ArrayList<StopData> newStops = new ArrayList<StopData>(); + //for (int k=0;k<1;k++){ + for (int c1=initialStop;c1<limit-1;c1=c1+2){ + StopData stop1 = stops.get(c1); + StopData stop2 = stops.get(c1+1); + if ( c1 == 1 ){ + newStops.add(stops.get(0)); + } + boolean joined = false; + StopData stop = null; + if ( stop1.compare(stop2,maxSpread) ) { + stop = stop1.joinTwoStopData(stop2); + joined = true; + if ( stop.checkStopData(maxSpread,minTimeI) ){ joined = true; } + } + if ( joined ){ + newStops.add(stop); + } + else{ + newStops.add(stop1); + newStops.add(stop2); + } + if ( c1 == limit-3 ){ + newStops.add(stops.get(limit-1)); + } + + //} + } + return newStops; + } + private void expandStops() { + int changes = 0; + for(int c=0;c<this.stops.size();c++){ + //System.out.println("expandClusters::: cluster ="+c); + changes = this.expandSingleStop(c); + } + } + private int expandSingleStop(int stopIndx) { + boolean ltrace = false; + int oldSize = stops.get(stopIndx).getSize(); + int newSize = -1; + int changes = -1; + int k=0; + while ( newSize != oldSize ){ + StopData stop = stops.get(stopIndx); + int iniIndx = AStopIndxs.get(stopIndx).get(0); + int endIndx = AStopIndxs.get(stopIndx).get(AStopIndxs.get(stopIndx).size()-1); + StopData newTempStop = new StopData(stop); + if ( ltrace ){ + System.out.print("change "+k+": ["); + for(int j=0;j<AStopIndxs.get(stopIndx).size();j++){ + System.out.print(AStopIndxs.get(stopIndx).get(j)+","); + } + System.out.print("\b\b] size="+stop.getSize()+" \n"); + } + if ( iniIndx > 0 ) { + newTempStop = expandSingleClusterBegining(stop, ATimes.get(iniIndx-1),APos.get(iniIndx-1)); + if ( newTempStop.checkStopData(maxSpread, minTimeI, numTestPoints, randWalkPercent, true) ){ + if ( ltrace ) System.out.println("B"); + stops.set(stopIndx, newTempStop); + AStopIndxs.get(stopIndx).add(0, iniIndx-1); + } + } + stop = stops.get(stopIndx); + if ( endIndx < ATimes.size()-1 ) { + newTempStop = expandSingleClusterEnd(stop, ATimes.get(endIndx+1),APos.get(endIndx+1)); + if ( newTempStop.checkStopData(maxSpread, minTimeI, numTestPoints, randWalkPercent, false) ){ + if ( ltrace ) System.out.println("E"); + stops.set(stopIndx, newTempStop); + AStopIndxs.get(stopIndx).add(endIndx+1); + } + } + if ( ltrace ) System.out.println(""); + oldSize = newSize; + newSize = stops.get(stopIndx).getSize(); + changes++; + k++; + if ( k > 1000000000 ) break; + } + return changes; + } + private StopData expandSingleClusterBegining(StopData stop, Long time, ArrayList<Double> pos) { + StopData newTempStop = new StopData(stop); + GPSPoint pnt = new GPSPoint(pos.get(0),pos.get(1),time*1000); + newTempStop.addNode(pnt, true); + return newTempStop; + } + private StopData expandSingleClusterEnd (StopData stop, Long time, ArrayList<Double> pos) { + StopData newTempClus = new StopData(stop); + GPSPoint pnt = new GPSPoint(pos.get(0),pos.get(1),time*1000); + newTempClus.addNode(pnt, false); + return newTempClus; + } + private void removeShortTimeStops(double minTime) { + ArrayList<Integer> indxsToErase = new ArrayList<Integer>(); + for(int c=0;c<this.stops.size();c++){ + if ( this.stops.get(c).getDeltaTime() < minTime*60 && c!=0 && c!=(this.stops.size()-1) ){ + indxsToErase.add(c); + // System.out.println("removeShortTimeClusters:: this.clusters.getDeltaTime("+c+")="+this.clusters.get(c).getDeltaTime()); + } + } + for(int c=stops.size()-1;c>=0;c--){ + if ( indxsToErase.contains(c) ) this.stops.remove(c); + } + } + private void writeAllStops() { + int wclus = 0; + for (int c=0;c<this.stops.size();c++){ + StopData cluster = this.stops.get(c); + //if ( cluster.checkClusteringData() ){ + cluster.writeToFile(); + wclus++; + //} + } + } + private ArrayList<StopData> orderStops() { + ArrayList<StopData> orderedStops = new ArrayList<StopData>(); + for(int c1=0;c1<this.stops.size();c1++){ + StopData stop = stops.get(c1); + Long stopIni = stop.getIniTime(); + boolean alreadyAdded = false; + for (int c2=0;c2<orderedStops.size();c2++){ + StopData clusO = orderedStops.get(c2); + Long clusOIni = clusO.getIniTime(); + if ( clusOIni>stopIni ){ + orderedStops.add(c2,stop); + alreadyAdded = true; + } + } + if (!alreadyAdded){ + orderedStops.add(stop); + } + } + return orderedStops; + } + private void findAllNextStops() { + ArrayList<StopData> orderedStops = orderStops(); + for(int c=0;c<orderedStops.size()-1;c++){ + StopData clus = orderedStops.get(c); + StopData clusp1 = orderedStops.get(c+1); + if ( clus.getEndTime() < clusp1.getIniTime() ){ + clus.setNextStop(clusp1.getId()); + } + } + } + public ArrayList<StopData> doStops() { + stops = new ArrayList<StopData>(); + this.calcZeroVelClusters(); + System.out.println("Zero Vel Stops identified #(Clus)="+this.stops.size()); + this.expandStops(); + System.out.println("Stops expanded #(Clus)="+this.stops.size()); + this.joinStops(); + System.out.println("Stops joined #(Clus)="+this.stops.size()); + this.removeShortTimeStops(this.minTime); + System.out.println("Small Stops (<"+minTime+" mins) erased #(Clus)="+this.stops.size()); + this.findAllNextStops(); + return stops; + } +} -- GitLab