From 3390937e144307dfe81f09da87090ead88083ba3 Mon Sep 17 00:00:00 2001 From: Arne Seime Date: Wed, 16 Nov 2016 14:21:43 +0100 Subject: [PATCH 1/6] Added field compassBearing to StopArea, indicates general direction of traffic --- .../main/java/mobi/chouette/model/StopArea.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mobi.chouette.model/src/main/java/mobi/chouette/model/StopArea.java b/mobi.chouette.model/src/main/java/mobi/chouette/model/StopArea.java index 5473a4dbfa..782733c387 100644 --- a/mobi.chouette.model/src/main/java/mobi/chouette/model/StopArea.java +++ b/mobi.chouette.model/src/main/java/mobi/chouette/model/StopArea.java @@ -278,6 +278,20 @@ public void setTimeZone(String value) { @Column(name = "stairs_availability") private Boolean stairsAvailable = false; + /** + * general compass bearing of traffic to stoparea + * + * + * + * @param compassBearing in degrees from 1 to 360 + * + + */ + @Getter + @Setter + @Column(name = "compass_bearing") + private Integer compassBearing; + /** * coded user needs as binary map
* From ba12c92872c6d09d0d79b4bd75e431342404946d Mon Sep 17 00:00:00 2001 From: Arne Seime Date: Thu, 17 Nov 2016 10:46:39 +0100 Subject: [PATCH 2/6] Added generic compass bearing generator --- .../exchange/CompassBearingGenerator.java | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java diff --git a/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java b/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java new file mode 100644 index 0000000000..21fa09616b --- /dev/null +++ b/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java @@ -0,0 +1,148 @@ +package mobi.chouette.exchange; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; + +import lombok.extern.log4j.Log4j; +import mobi.chouette.model.JourneyPattern; +import mobi.chouette.model.Route; +import mobi.chouette.model.StopArea; +import mobi.chouette.model.StopPoint; +import mobi.chouette.model.type.ChouetteAreaEnum; +import mobi.chouette.model.util.Referential; + +@Log4j +public class CompassBearingGenerator { + private static final int MAX_DIFF_BEARING_DEGREES = 60; + + public void cacluateCompassBearings(Referential referential) { + + for (StopArea sa : referential.getSharedStopAreas().values()) { + + if (sa.getAreaType() == ChouetteAreaEnum.CommercialStopPoint) { + for (StopArea boardingPosition : sa.getContainedStopAreas()) { + + if(boardingPosition.getAreaType() == ChouetteAreaEnum.BoardingPosition && boardingPosition.getCompassBearing() == null) { + // Find all bearings used + Set compassBearings = findCompassBearingForBoardingPosition(boardingPosition); + + if (compassBearings.size() > 1) { + // See if we can merge some nearly identical + Integer min = Collections.min(compassBearings); + Integer max = Collections.max(compassBearings); + int angle = getAngle(min, max); + if (Math.abs(angle) < MAX_DIFF_BEARING_DEGREES) { + compassBearings.clear(); + compassBearings.add((max + (angle / 2)) % 360); + log.info("Average compass bearing is " + compassBearings.iterator().next() + + " for BoardingPosition " + boardingPosition.getObjectId() + " and name " + + boardingPosition.getName()); + + } + } + + if (compassBearings.size() == 1) { + // TODO set on object + boardingPosition.setComment("Compass bearing " + compassBearings.iterator().next()); + + } else if (compassBearings.size() > 1) { + log.warn("Found at least 2 conflicting compass bearings " + + ToStringBuilder.reflectionToString(compassBearings.toArray(), + ToStringStyle.SIMPLE_STYLE) + + " for BoardingPosition " + boardingPosition.getObjectId() + " and name " + + boardingPosition.getName()); + } else { + } + + + } + + } + + } + + } + + } + + + + protected Set findCompassBearingForBoardingPosition(StopArea sa) { + Set compassBearings = new TreeSet(); + List stopPoints = sa.getContainedStopPoints(); + for (StopPoint stop : stopPoints) { + Route route = stop.getRoute(); + List journeyPatterns = route.getJourneyPatterns(); + for (JourneyPattern jp : journeyPatterns) { + StopPoint previous = null; + StopPoint next = null; + + List stopPointsInJourneyPattern = jp.getStopPoints(); + + if (jp.getDepartureStopPoint().getContainedInStopArea().getObjectId() + .equals(stop.getContainedInStopArea().getObjectId())) { + next = stopPointsInJourneyPattern.get(1); + } else if (jp.getArrivalStopPoint().getContainedInStopArea().getObjectId() + .equals(stop.getContainedInStopArea().getObjectId())) { + previous = stopPointsInJourneyPattern.get(stopPointsInJourneyPattern.size() - 2); + } else { + // In the middle somewhere + for (int i = 0; i < stopPointsInJourneyPattern.size(); i++) { + if (stop.getContainedInStopArea().getObjectId() + .equals(stopPointsInJourneyPattern.get(i).getContainedInStopArea().getObjectId())) { + previous = stopPointsInJourneyPattern.get(i - 1); + next = stopPointsInJourneyPattern.get(i + 1); + break; + } + } + } + + // Calculate general direction previous -> stop -> next + if (previous != null && next != null) { + // Use previous and next + compassBearings.add(bearing(previous, next)); + } else if (previous != null) { + compassBearings.add(bearing(previous, stop)); + } else { + compassBearings.add(bearing(stop, next)); + } + + } + + } + + return compassBearings; + + } + + private Integer bearing(StopPoint from, StopPoint to) { + StopArea fromArea = from.getContainedInStopArea(); + StopArea toArea = to.getContainedInStopArea(); + + double longitude1 = fromArea.getLongitude().doubleValue(); + double longitude2 = toArea.getLongitude().doubleValue(); + double latitude1 = Math.toRadians(fromArea.getLatitude().doubleValue()); + double latitude2 = Math.toRadians(toArea.getLatitude().doubleValue()); + double longDiff = Math.toRadians(longitude2 - longitude1); + double y = Math.sin(longDiff) * Math.cos(latitude2); + double x = Math.cos(latitude1) * Math.sin(latitude2) + - Math.sin(latitude1) * Math.cos(latitude2) * Math.cos(longDiff); + + double bearing = (Math.toDegrees(Math.atan2(y, x)) + 360) % 360; + + // 1 to 360 degrees, not 0 to 359 + + return new Integer((int) bearing + 1); + } + + private int getAngle(Integer bearing, Integer heading) { + return ((((bearing - heading) % 360) + 540) % 360) - 180; + + } + +} From fa92a6eb2da4c1b736106e3beb73281eaa0ee124 Mon Sep 17 00:00:00 2001 From: Arne Seime Date: Thu, 17 Nov 2016 12:01:54 +0100 Subject: [PATCH 3/6] Added support in StopUpdater for compass bearing --- .../exchange/CompassBearingGenerator.java | 63 ++++++++----------- .../importer/updater/StopAreaUpdater.java | 4 ++ 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java b/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java index 21fa09616b..d16297aa9d 100644 --- a/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java +++ b/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java @@ -22,46 +22,37 @@ public class CompassBearingGenerator { public void cacluateCompassBearings(Referential referential) { - for (StopArea sa : referential.getSharedStopAreas().values()) { - - if (sa.getAreaType() == ChouetteAreaEnum.CommercialStopPoint) { - for (StopArea boardingPosition : sa.getContainedStopAreas()) { - - if(boardingPosition.getAreaType() == ChouetteAreaEnum.BoardingPosition && boardingPosition.getCompassBearing() == null) { - // Find all bearings used - Set compassBearings = findCompassBearingForBoardingPosition(boardingPosition); - - if (compassBearings.size() > 1) { - // See if we can merge some nearly identical - Integer min = Collections.min(compassBearings); - Integer max = Collections.max(compassBearings); - int angle = getAngle(min, max); - if (Math.abs(angle) < MAX_DIFF_BEARING_DEGREES) { - compassBearings.clear(); - compassBearings.add((max + (angle / 2)) % 360); - log.info("Average compass bearing is " + compassBearings.iterator().next() - + " for BoardingPosition " + boardingPosition.getObjectId() + " and name " - + boardingPosition.getName()); - - } - } + for (StopArea boardingPosition : referential.getSharedStopAreas().values()) { + + if (boardingPosition.getAreaType() == ChouetteAreaEnum.BoardingPosition + && boardingPosition.getCompassBearing() == null) { + Set compassBearings = findCompassBearingForBoardingPosition(boardingPosition); + + if (compassBearings.size() > 1) { + // See if we can merge some nearly identical + Integer min = Collections.min(compassBearings); + Integer max = Collections.max(compassBearings); + int angle = getAngle(min, max); + if (Math.abs(angle) < MAX_DIFF_BEARING_DEGREES) { + compassBearings.clear(); + compassBearings.add((max + (angle / 2)) % 360); + log.info("Average compass bearing is " + compassBearings.iterator().next() + + " for BoardingPosition " + boardingPosition.getObjectId() + " and name " + + boardingPosition.getName()); - if (compassBearings.size() == 1) { - // TODO set on object - boardingPosition.setComment("Compass bearing " + compassBearings.iterator().next()); - - } else if (compassBearings.size() > 1) { - log.warn("Found at least 2 conflicting compass bearings " + } + } + + if (compassBearings.size() == 1) { + boardingPosition.setCompassBearing(compassBearings.iterator().next()); + } else if (compassBearings.size() > 1) { + log.warn( + "Found at least 2 conflicting compass bearings " + ToStringBuilder.reflectionToString(compassBearings.toArray(), ToStringStyle.SIMPLE_STYLE) + " for BoardingPosition " + boardingPosition.getObjectId() + " and name " + boardingPosition.getName()); - } else { - } - - - } - + } else { } } @@ -70,8 +61,6 @@ public void cacluateCompassBearings(Referential referential) { } - - protected Set findCompassBearingForBoardingPosition(StopArea sa) { Set compassBearings = new TreeSet(); List stopPoints = sa.getContainedStopPoints(); diff --git a/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/importer/updater/StopAreaUpdater.java b/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/importer/updater/StopAreaUpdater.java index fd4839eb76..f48c3c5c5c 100644 --- a/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/importer/updater/StopAreaUpdater.java +++ b/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/importer/updater/StopAreaUpdater.java @@ -108,6 +108,7 @@ public void update(Context context, StopArea oldValue, StopArea newValue) throws oldValue.setZipCode(newValue.getZipCode()); oldValue.setCityName(newValue.getCityName()); oldValue.setStreetName(newValue.getStreetName()); + oldValue.setCompassBearing(newValue.getCompassBearing()); oldValue.setDetached(false); } else { twoDatabaseStopAreaTwoTest(validationReporter, context, oldValue, newValue, data); @@ -186,6 +187,9 @@ public void update(Context context, StopArea oldValue, StopArea newValue) throws if (newValue.getStreetName() != null && !newValue.getStreetName().equals(oldValue.getStreetName())) { oldValue.setStreetName(newValue.getStreetName()); } + if (newValue.getCompassBearing() != null && !newValue.getCompassBearing().equals(oldValue.getCompassBearing())) { + oldValue.setCompassBearing(newValue.getCompassBearing()); + } } From 5db463932a5e937d836a18805c90d3b9f4da55b3 Mon Sep 17 00:00:00 2001 From: Arne Seime Date: Fri, 18 Nov 2016 14:11:08 +0100 Subject: [PATCH 4/6] Updated chouette.sql with stoparea/compass bearing --- src/main/sql/chouette.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/sql/chouette.sql b/src/main/sql/chouette.sql index 38321e4824..1907955a13 100644 --- a/src/main/sql/chouette.sql +++ b/src/main/sql/chouette.sql @@ -885,7 +885,8 @@ CREATE TABLE stop_areas ( zip_code character varying(255), city_name character varying(255), url character varying(255), - time_zone character varying(255) + time_zone character varying(255), + compass_bearing integer ); From 983d620f6d6effcbf8ee684effdca5e86c8f1ee5 Mon Sep 17 00:00:00 2001 From: Arne Seime Date: Mon, 21 Nov 2016 15:51:37 +0100 Subject: [PATCH 5/6] Do not fail on missing coordinates for stoparea --- .../exchange/CompassBearingGenerator.java | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java b/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java index d16297aa9d..2e69e99724 100644 --- a/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java +++ b/mobi.chouette.exchange/src/main/java/mobi/chouette/exchange/CompassBearingGenerator.java @@ -91,14 +91,19 @@ protected Set findCompassBearingForBoardingPosition(StopArea sa) { } } + Integer bearing = null; // Calculate general direction previous -> stop -> next if (previous != null && next != null) { // Use previous and next - compassBearings.add(bearing(previous, next)); + bearing = bearing(previous, next); } else if (previous != null) { - compassBearings.add(bearing(previous, stop)); + bearing = bearing(previous, stop); } else { - compassBearings.add(bearing(stop, next)); + bearing = bearing(stop, next); + } + + if(bearing != null) { + compassBearings.add(bearing); } } @@ -110,23 +115,41 @@ protected Set findCompassBearingForBoardingPosition(StopArea sa) { } private Integer bearing(StopPoint from, StopPoint to) { + StopArea fromArea = from.getContainedInStopArea(); StopArea toArea = to.getContainedInStopArea(); - double longitude1 = fromArea.getLongitude().doubleValue(); - double longitude2 = toArea.getLongitude().doubleValue(); - double latitude1 = Math.toRadians(fromArea.getLatitude().doubleValue()); - double latitude2 = Math.toRadians(toArea.getLatitude().doubleValue()); - double longDiff = Math.toRadians(longitude2 - longitude1); - double y = Math.sin(longDiff) * Math.cos(latitude2); - double x = Math.cos(latitude1) * Math.sin(latitude2) - - Math.sin(latitude1) * Math.cos(latitude2) * Math.cos(longDiff); - - double bearing = (Math.toDegrees(Math.atan2(y, x)) + 360) % 360; - - // 1 to 360 degrees, not 0 to 359 - - return new Integer((int) bearing + 1); + if(fromArea != null && toArea != null && hasCoordinates(fromArea) && hasCoordinates(toArea)) { + + double longitude1 = fromArea.getLongitude().doubleValue(); + double longitude2 = toArea.getLongitude().doubleValue(); + double latitude1 = Math.toRadians(fromArea.getLatitude().doubleValue()); + double latitude2 = Math.toRadians(toArea.getLatitude().doubleValue()); + double longDiff = Math.toRadians(longitude2 - longitude1); + double y = Math.sin(longDiff) * Math.cos(latitude2); + double x = Math.cos(latitude1) * Math.sin(latitude2) + - Math.sin(latitude1) * Math.cos(latitude2) * Math.cos(longDiff); + + double bearing = (Math.toDegrees(Math.atan2(y, x)) + 360) % 360; + + // 1 to 360 degrees, not 0 to 359 + + return new Integer((int) bearing + 1); + } else { + if(fromArea == null) { + log.warn("StopPoint "+from.getObjectId()+" in route "+from.getRoute().getObjectId()+" and line "+from.getRoute().getLine().getObjectId()+"/" +from.getRoute().getLine().getName()+" has no StopArea"); + } + if(toArea == null) { + log.warn("StopPoint "+to.getObjectId()+" in route "+to.getRoute().getObjectId()+" and line "+to.getRoute().getLine().getObjectId()+"/" +to.getRoute().getLine().getName()+" has no StopArea"); + } + + return null; + } + + } + + private boolean hasCoordinates(StopArea stopArea) { + return stopArea.getLatitude() != null && stopArea.getLongitude() != null; } private int getAngle(Integer bearing, Integer heading) { From a763d23ba6a0c8f7c0d24531ba0cab87bce2ab92 Mon Sep 17 00:00:00 2001 From: Arne Seime Date: Tue, 22 Nov 2016 12:43:44 +0100 Subject: [PATCH 6/6] Updated sql schema for test database --- src/test/sql/chouette_test.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/sql/chouette_test.sql b/src/test/sql/chouette_test.sql index bd79b4f3be..d555e1927f 100644 --- a/src/test/sql/chouette_test.sql +++ b/src/test/sql/chouette_test.sql @@ -885,7 +885,8 @@ CREATE TABLE stop_areas ( zip_code character varying(255), city_name character varying(255), url character varying(255), - time_zone character varying(255) + time_zone character varying(255), + compass_bearing integer );