From b0f5d810e6b041a295389e35298aacdd3ab63024 Mon Sep 17 00:00:00 2001 From: Sean Og Crudden Date: Wed, 3 May 2023 13:03:13 +0100 Subject: [PATCH 1/6] Remove hardcoded URL from avlMap. --- transitclock/pom.xml | 5 +++++ transitclockWebapp/src/main/webapp/map/javascript/avlMap.js | 3 ++- transitclockWebapp/src/main/webapp/map/map.jsp | 4 +++- transitclockWebapp/src/main/webapp/reports/avlMap.jsp | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/transitclock/pom.xml b/transitclock/pom.xml index cab10d5d0..f890a378a 100755 --- a/transitclock/pom.xml +++ b/transitclock/pom.xml @@ -92,6 +92,11 @@ esri-geometry-api 1.1 + + com.bmw-carit + barefoot + 0.1.5 + From 09a4fe2649c51892c452138bee7b5408d3c86abc Mon Sep 17 00:00:00 2001 From: Sean Og Crudden Date: Thu, 4 May 2023 15:36:31 +0100 Subject: [PATCH 2/6] Set tile url --- transitclockWebapp/src/main/webapp/map/javascript/avlMap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transitclockWebapp/src/main/webapp/map/javascript/avlMap.js b/transitclockWebapp/src/main/webapp/map/javascript/avlMap.js index 1b31bd2e9..d531e3205 100644 --- a/transitclockWebapp/src/main/webapp/map/javascript/avlMap.js +++ b/transitclockWebapp/src/main/webapp/map/javascript/avlMap.js @@ -198,7 +198,7 @@ function createExport(vehicles) { //when selections change without having to redraw tiles. var map = L.map('map'); L.control.scale({metric: false}).addTo(map); -var mapTileUrl = '<%= WebConfigParams.getMapTileUrl() %>'; +var mapTileUrl = 'http://tile.openstreetmap.org/{z}/{x}/{y}.png'; L.tileLayer(mapTileUrl, { attribution: '© OpenStreetMap & CC-BY-SA, Imagery © Mapbox', maxZoom: 19 From 1504b3729209539dca3d04ac289735c215ba2704 Mon Sep 17 00:00:00 2001 From: Sean Og Crudden Date: Mon, 26 Jun 2023 16:58:05 +0100 Subject: [PATCH 3/6] Use barefoot to map match an avlreport against a trip shape. Result not used yet. --- .../java/org/transitclock/core/Indices.java | 8 ++ .../org/transitclock/core/MapMatcher.java | 12 +++ .../transitclock/core/MapMatcherFactory.java | 51 +++++++++ .../org/transitclock/core/SpatialMatcher.java | 5 +- .../org/transitclock/core/VehicleState.java | 27 +++-- .../core/barefoot/BareFootMapMatcher.java | 94 ++++++++++++++++ .../core/barefoot/TransitClockRoadReader.java | 102 ++++++++++++++++++ transitclock/src/main/resources/logback.xml | 24 +++++ 8 files changed, 316 insertions(+), 7 deletions(-) create mode 100644 transitclock/src/main/java/org/transitclock/core/MapMatcher.java create mode 100644 transitclock/src/main/java/org/transitclock/core/MapMatcherFactory.java create mode 100644 transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java create mode 100644 transitclock/src/main/java/org/transitclock/core/barefoot/TransitClockRoadReader.java diff --git a/transitclock/src/main/java/org/transitclock/core/Indices.java b/transitclock/src/main/java/org/transitclock/core/Indices.java index 1db8b953c..9460c0ac9 100644 --- a/transitclock/src/main/java/org/transitclock/core/Indices.java +++ b/transitclock/src/main/java/org/transitclock/core/Indices.java @@ -17,6 +17,7 @@ package org.transitclock.core; import java.io.Serializable; +import java.util.Objects; import org.transitclock.applications.Core; import org.transitclock.db.structs.ArrivalDeparture; @@ -634,4 +635,11 @@ public boolean controlPoint() { return false; } + @Override + public int hashCode() { + return Objects.hash(block, segmentIndex, stopPathIndex, tripIndex); + } + + + } diff --git a/transitclock/src/main/java/org/transitclock/core/MapMatcher.java b/transitclock/src/main/java/org/transitclock/core/MapMatcher.java new file mode 100644 index 000000000..e29c65ecc --- /dev/null +++ b/transitclock/src/main/java/org/transitclock/core/MapMatcher.java @@ -0,0 +1,12 @@ +package org.transitclock.core; + +import java.util.Date; + +import org.transitclock.db.structs.AvlReport; +import org.transitclock.db.structs.Block; +import org.transitclock.db.structs.Location; + +public interface MapMatcher { + void setMatcher(Block block, Date assignmentTime); + Location getEstimateLocation(AvlReport avlReport); +} diff --git a/transitclock/src/main/java/org/transitclock/core/MapMatcherFactory.java b/transitclock/src/main/java/org/transitclock/core/MapMatcherFactory.java new file mode 100644 index 000000000..92fd5cf7a --- /dev/null +++ b/transitclock/src/main/java/org/transitclock/core/MapMatcherFactory.java @@ -0,0 +1,51 @@ +/* + * This file is part of Transitime.org + * + * Transitime.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License (GPL) as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Transitime.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Transitime.org . If not, see . + */ + +package org.transitclock.core; + +import org.transitclock.config.StringConfigValue; +import org.transitclock.utils.ClassInstantiator; + +/** + * For instantiating a map matcher object that matches avl locations to trip shapes + * + * @author Sean Óg Crudden + * + */ +public class MapMatcherFactory { + + // The name of the class to instantiate + private static StringConfigValue className = + new StringConfigValue("transitclock.core.mapMatcherClass", + "org.transitclock.core.barefoot.BareFootMapMatcher", + "Specifies the name of the class used for map matching."); + + /********************** Member Functions **************************/ + + public static MapMatcher getInstance() { + + + try { + return ClassInstantiator.instantiate(className.getValue(), + MapMatcher.class); + } catch (Exception e) { + + e.printStackTrace(); + } + return null; + } +} diff --git a/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java b/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java index 5d70b9efb..39734f78d 100644 --- a/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java +++ b/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java @@ -68,7 +68,7 @@ public class SpatialMatcher { private SpatialMatch smallestDistanceSpatialMatch = null; // For keeping track of what kind of spatial matching being done - public enum MatchingType {STANDARD_MATCHING, AUTO_ASSIGNING_MATCHING}; + public enum MatchingType {STANDARD_MATCHING, AUTO_ASSIGNING_MATCHING, BAREFOOT_MATCHING}; private static final Logger logger = LoggerFactory.getLogger(SpatialMatcher.class); @@ -732,6 +732,9 @@ && withinAllowableDistanceOfLayover(avlReport.getVehicleId(), */ public static List getSpatialMatches(VehicleState vehicleState) { + + vehicleState.getMapMatchedLocation(); + // Some convenience variables TemporalMatch previousMatch = vehicleState.getMatch(); SpatialMatcher spatialMatcher = new SpatialMatcher(); diff --git a/transitclock/src/main/java/org/transitclock/core/VehicleState.java b/transitclock/src/main/java/org/transitclock/core/VehicleState.java index f2dafca38..68bd74b1d 100644 --- a/transitclock/src/main/java/org/transitclock/core/VehicleState.java +++ b/transitclock/src/main/java/org/transitclock/core/VehicleState.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.transitclock.configData.CoreConfig; @@ -66,6 +65,9 @@ public class VehicleState { // First is most recent private LinkedList avlReportHistory = new LinkedList(); + + + private List predictions; private TemporalDifference realTimeSchedAdh; @@ -100,7 +102,8 @@ public class VehicleState { private HoldingTime holdingTime=null; //Used for schedPred AVL. Identify if trip is canceled. private boolean isCanceled; - + + MapMatcher mapMatcher = null; public Headway getHeadway() { return headway; @@ -109,8 +112,6 @@ public void setHeadway(Headway headway) { this.headway = headway; } - - public HoldingTime getHoldingTime() { return holdingTime; } @@ -131,8 +132,9 @@ public void incrementTripCounter() { public VehicleState(String vehicleId) { this.vehicleId = vehicleId; + } - + /** * Sets the block assignment for vehicle. Also, this is how it is specified * whether a vehicle is predictable or not. @@ -163,9 +165,22 @@ public void setBlock(Block newBlock, BlockAssignmentMethod assignmentMethod, this.assignmentMethod = assignmentMethod; this.assignmentId = assignmentId; this.predictable = predictable; - this.assignmentTime = getAvlReport().getDate(); + this.assignmentTime = getAvlReport().getDate(); + + this.mapMatcher=(MapMatcher) MapMatcherFactory.getInstance(); + mapMatcher.setMatcher(block, assignmentTime); + + } + + public Location getMapMatchedLocation() + { + if(mapMatcher!=null) + return mapMatcher.getEstimateLocation(getAvlReport()); + else + return null; } + /** * Sets the block for this VehicleState to null. Also sets assignmentId * to null and predictable to false. diff --git a/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java b/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java new file mode 100644 index 000000000..81f9e9707 --- /dev/null +++ b/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java @@ -0,0 +1,94 @@ +package org.transitclock.core.barefoot; + +import java.util.Date; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.transitclock.core.MapMatcher; +import org.transitclock.db.structs.AvlReport; +import org.transitclock.db.structs.Block; +import org.transitclock.db.structs.Location; + +import com.bmwcarit.barefoot.matcher.Matcher; +import com.bmwcarit.barefoot.matcher.MatcherCandidate; +import com.bmwcarit.barefoot.matcher.MatcherKState; +import com.bmwcarit.barefoot.matcher.MatcherSample; +import com.bmwcarit.barefoot.roadmap.Road; +import com.bmwcarit.barefoot.roadmap.RoadMap; +import com.bmwcarit.barefoot.roadmap.RoadPoint; +import com.bmwcarit.barefoot.roadmap.TimePriority; +import com.bmwcarit.barefoot.spatial.Geography; +import com.bmwcarit.barefoot.topology.Dijkstra; +import com.esri.core.geometry.Point; +import org.transitclock.utils.Geo; + +public class BareFootMapMatcher implements MapMatcher { + + private RoadMap barefootMap = null; + + private Matcher barefootMatcher = null; + + private MatcherKState barefootState = null; + + private static final Logger logger = LoggerFactory.getLogger(BareFootMapMatcher.class); + + @Override + public void setMatcher(Block block, Date assignmentTime) { + + if (block != null) { + + int tripIndex = block.activeTripIndex(assignmentTime, 0); + + TransitClockRoadReader roadReader = new TransitClockRoadReader(block, tripIndex); + + barefootMap = RoadMap.Load(roadReader); + + barefootMap.construct(); + + barefootMatcher = new Matcher(barefootMap, new Dijkstra(), new TimePriority(), + new Geography()); + + barefootState = new MatcherKState(); + } + } + + @Override + public Location getEstimateLocation(AvlReport avlReport) { + + if (barefootState != null) { + Point point = new Point(); + point.setX(avlReport.getLon()); + point.setY(avlReport.getLat()); + MatcherSample sample = new MatcherSample(avlReport.getTime(), point); + + Set result = barefootMatcher.execute(barefootState.vector(), barefootState.sample(), + sample); + + barefootState.update(result, sample); + + MatcherCandidate estimate = barefootState.estimate(); + + if (estimate != null) { + + estimate.point().edge().base().id(); // road id + estimate.point().edge().heading(); // heading + estimate.point().geometry(); // GPS position (on the road) + if (estimate.transition() != null) + estimate.transition().route().geometry(); // path geometry from last matching + // candidate + Location location = new Location(estimate.point().geometry().getY(), + estimate.point().geometry().getX()); + + if (!location.equals(avlReport.getLocation())) { + + logger.debug("Vehicle {} assigned to {} is {} metres from GPS coordindates.", avlReport.getVehicleId(),avlReport.getAssignmentId(),Geo.distance(location, avlReport.getLocation())); + } + return location; + } + + } + return null; + } + +} diff --git a/transitclock/src/main/java/org/transitclock/core/barefoot/TransitClockRoadReader.java b/transitclock/src/main/java/org/transitclock/core/barefoot/TransitClockRoadReader.java new file mode 100644 index 000000000..223a1435f --- /dev/null +++ b/transitclock/src/main/java/org/transitclock/core/barefoot/TransitClockRoadReader.java @@ -0,0 +1,102 @@ +package org.transitclock.core.barefoot; + +import java.util.HashSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.transitclock.applications.Core; +import org.transitclock.core.Indices; +import org.transitclock.db.structs.Block; +import org.transitclock.db.structs.Trip; +import org.transitclock.db.structs.VectorWithHeading; + +import com.bmwcarit.barefoot.road.BaseRoad; +import com.bmwcarit.barefoot.road.RoadReader; +import com.bmwcarit.barefoot.util.SourceException; +import com.esri.core.geometry.Line; +import com.esri.core.geometry.Point; +import com.esri.core.geometry.Polygon; +import com.esri.core.geometry.Polyline; + +public class TransitClockRoadReader implements RoadReader { + Trip trip = null; + + Indices indices = null; + + int tripIndex = -1; + + long segmentCounter = 0; + private static final Logger logger = + LoggerFactory.getLogger(TransitClockRoadReader.class); + + public TransitClockRoadReader(Block block, int tripIndex) { + + trip = block.getTrip(tripIndex); + indices = new Indices(block, tripIndex, 0, 0); + } + + @Override + public BaseRoad next() throws SourceException { + + if (indices.atEndOfTrip()) + return null; + + Polyline polyLine = new Polyline(); + + Point startPoint = null; + Point endPoint = null; + Line polyLineSegment = new Line(); + + indices.increment(Core.getInstance().getSystemTime()); + + VectorWithHeading segment = indices.getSegment(); + + startPoint = new Point(); + endPoint = new Point(); + startPoint.setXY(segment.getL1().getLon(), segment.getL1().getLat()); + endPoint.setXY(segment.getL2().getLon(), segment.getL2().getLat()); + polyLineSegment.setStart(startPoint); + polyLineSegment.setEnd(endPoint); + + polyLine.addSegment(polyLineSegment, false); + + logger.debug("Adding segment -->" +startPoint.toString() + " : "+endPoint.toString()); + + return new BaseRoad(indices.hashCode(), segmentCounter, segmentCounter++, indices.hashCode(), true, (short) 1, 1F, 60F, 60F, 100F, + polyLine); + + } + + + + @Override + public boolean isOpen() { + // TODO Auto-generated method stub + return false; + } + + + + @Override + public void open() throws SourceException { + // TODO Auto-generated method stub + + } + + + + @Override + public void open(Polygon polygon, HashSet exclusion) throws SourceException { + // TODO Auto-generated method stub + + } + + + + @Override + public void close() throws SourceException { + // TODO Auto-generated method stub + + } + +} diff --git a/transitclock/src/main/resources/logback.xml b/transitclock/src/main/resources/logback.xml index 8b3920f1e..4352bce24 100755 --- a/transitclock/src/main/resources/logback.xml +++ b/transitclock/src/main/resources/logback.xml @@ -313,6 +313,22 @@ ${DEFAULT_PATTERN} + + + + + ${LOG_FILE_ROOT}/barefoot.log.gz + + + 3 + 1GB + + + UTF-8 + ${DEFAULT_PATTERN} + + + + + + + + " +startPoint.toString() + " : "+endPoint.toString()); - - return new BaseRoad(indices.hashCode(), segmentCounter, segmentCounter++, indices.hashCode(), true, (short) 1, 1F, 60F, 60F, 100F, + + return new BaseRoad(indices.hashCode(), segmentCounter, segmentCounter++, indices.getStopPathIndex(), true, (short) 1, 1F, 60F, 60F, 100F, polyLine); } From a95822f18f1fd2f31a69b5d19eb33a0e4d96f2e8 Mon Sep 17 00:00:00 2001 From: Sean Og Crudden Date: Wed, 28 Jun 2023 13:52:37 +0100 Subject: [PATCH 5/6] Now finds a SpatialMatch and sets all values including distance along segment. Uses value found to augment list of spatial matches found using legacy method. --- transitclock/pom.xml | 2 +- .../org/transitclock/core/AvlProcessor.java | 8 ++- .../org/transitclock/core/MapMatcher.java | 4 +- .../org/transitclock/core/SpatialMatcher.java | 4 +- .../org/transitclock/core/VehicleState.java | 5 +- .../core/barefoot/BareFootMapMatcher.java | 41 +++++++++---- .../core/barefoot/ReferenceId.java | 60 +++++++++++++++++++ .../core/barefoot/TransitClockRoadReader.java | 16 +++-- transitclock/src/main/resources/logback.xml | 8 ++- 9 files changed, 120 insertions(+), 28 deletions(-) create mode 100644 transitclock/src/main/java/org/transitclock/core/barefoot/ReferenceId.java diff --git a/transitclock/pom.xml b/transitclock/pom.xml index f890a378a..1a3979bd1 100755 --- a/transitclock/pom.xml +++ b/transitclock/pom.xml @@ -90,7 +90,7 @@ com.esri.geometry esri-geometry-api - 1.1 + 2.2.4 com.bmw-carit diff --git a/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java b/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java index 31b2a5a2b..6c18deb31 100644 --- a/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java +++ b/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java @@ -444,9 +444,13 @@ public void matchNewFixForPredictableVehicle(VehicleState vehicleState) { // Find possible spatial matches List spatialMatches = SpatialMatcher .getSpatialMatches(vehicleState); + + // This will augment the results of the original spatial matcher with the match from barefoot + spatialMatches.add(vehicleState.getMapMatchedSpatialMatch()); + logger.debug("For vehicleId={} found the following {} spatial " - + "matches: {}", vehicleState.getVehicleId(), - spatialMatches.size(), spatialMatches); + + "matches: {} ", vehicleState.getVehicleId(), + spatialMatches.size(), spatialMatches); // Find best temporal match of the spatial matches TemporalMatch bestTemporalMatch = TemporalMatcher.getInstance() diff --git a/transitclock/src/main/java/org/transitclock/core/MapMatcher.java b/transitclock/src/main/java/org/transitclock/core/MapMatcher.java index e29c65ecc..84da22cb8 100644 --- a/transitclock/src/main/java/org/transitclock/core/MapMatcher.java +++ b/transitclock/src/main/java/org/transitclock/core/MapMatcher.java @@ -7,6 +7,6 @@ import org.transitclock.db.structs.Location; public interface MapMatcher { - void setMatcher(Block block, Date assignmentTime); - Location getEstimateLocation(AvlReport avlReport); + void setMatcher(Block block, Date assignmentTime); + SpatialMatch getSpatialMatch(AvlReport avlReport); } diff --git a/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java b/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java index 39734f78d..abaeeae6a 100644 --- a/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java +++ b/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java @@ -732,9 +732,7 @@ && withinAllowableDistanceOfLayover(avlReport.getVehicleId(), */ public static List getSpatialMatches(VehicleState vehicleState) { - - vehicleState.getMapMatchedLocation(); - + // Some convenience variables TemporalMatch previousMatch = vehicleState.getMatch(); SpatialMatcher spatialMatcher = new SpatialMatcher(); diff --git a/transitclock/src/main/java/org/transitclock/core/VehicleState.java b/transitclock/src/main/java/org/transitclock/core/VehicleState.java index 68bd74b1d..885874130 100644 --- a/transitclock/src/main/java/org/transitclock/core/VehicleState.java +++ b/transitclock/src/main/java/org/transitclock/core/VehicleState.java @@ -172,13 +172,14 @@ public void setBlock(Block newBlock, BlockAssignmentMethod assignmentMethod, } - public Location getMapMatchedLocation() + public SpatialMatch getMapMatchedSpatialMatch() { if(mapMatcher!=null) - return mapMatcher.getEstimateLocation(getAvlReport()); + return mapMatcher.getSpatialMatch(getAvlReport()); else return null; } + /** diff --git a/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java b/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java index 506e9a7cf..7c308ef5a 100644 --- a/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java +++ b/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java @@ -5,7 +5,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.transitclock.configData.CoreConfig; import org.transitclock.core.MapMatcher; +import org.transitclock.core.SpatialMatch; import org.transitclock.db.structs.AvlReport; import org.transitclock.db.structs.Block; import org.transitclock.db.structs.Location; @@ -19,6 +21,7 @@ import com.bmwcarit.barefoot.roadmap.RoadPoint; import com.bmwcarit.barefoot.roadmap.TimePriority; import com.bmwcarit.barefoot.spatial.Geography; +import com.bmwcarit.barefoot.spatial.SpatialOperator; import com.bmwcarit.barefoot.topology.Dijkstra; import com.esri.core.geometry.Point; import org.transitclock.utils.Geo; @@ -31,6 +34,12 @@ public class BareFootMapMatcher implements MapMatcher { private MatcherKState barefootState = null; + private Block block = null; + + private int tripIndex = -1; + + private static SpatialOperator spatial = new Geography(); + private static final Logger logger = LoggerFactory.getLogger(BareFootMapMatcher.class); @Override @@ -38,7 +47,9 @@ public void setMatcher(Block block, Date assignmentTime) { if (block != null) { - int tripIndex = block.activeTripIndex(assignmentTime, 0); + this.block = block; + + tripIndex = block.activeTripIndex(assignmentTime, 0); TransitClockRoadReader roadReader = new TransitClockRoadReader(block, tripIndex); @@ -49,12 +60,14 @@ public void setMatcher(Block block, Date assignmentTime) { barefootMatcher = new Matcher(barefootMap, new Dijkstra(), new TimePriority(), new Geography()); + barefootMatcher.shortenTurns(false); + barefootState = new MatcherKState(); } } @Override - public Location getEstimateLocation(AvlReport avlReport) { + public SpatialMatch getSpatialMatch(AvlReport avlReport) { if (barefootState != null) { Point point = new Point(); @@ -68,19 +81,27 @@ public Location getEstimateLocation(AvlReport avlReport) { barefootState.update(result, sample); MatcherCandidate estimate = barefootState.estimate(); - + + logger.debug("Vehicle {} has {} samples.", avlReport.getVehicleId(), barefootState.samples().size()); + if (estimate != null) { - + Location location = new Location(estimate.point().geometry().getY(), estimate.point().geometry().getX()); - if (!location.equals(avlReport.getLocation())) { - - logger.debug("Vehicle {} assigned to {} is {} metres from GPS coordindates on stoppath {}. Proability is {}.", avlReport.getVehicleId(),avlReport.getAssignmentId(),Geo.distance(location, avlReport.getLocation()), estimate.point().edge().base().refid(),estimate.seqprob()); - } - return location; - } + ReferenceId refId = ReferenceId.deconstructRefId(estimate.point().edge().base().refid()); + logger.debug( + "Vehicle {} assigned to {} is {} metres from GPS coordindates on {}. Probability is {} and Sequence probabilty is {}.", + avlReport.getVehicleId(), avlReport.getAssignmentId(), + Geo.distance(location, avlReport.getLocation()), refId, estimate.filtprob(), + estimate.seqprob()); + + return new SpatialMatch(avlReport.getTime(), block, tripIndex, refId.getStopPathIndex(), + refId.getSegmentIndex(), 0, spatial.intercept(estimate.point().edge().geometry(), point) + * spatial.length(estimate.point().edge().geometry())); + + } } return null; } diff --git a/transitclock/src/main/java/org/transitclock/core/barefoot/ReferenceId.java b/transitclock/src/main/java/org/transitclock/core/barefoot/ReferenceId.java new file mode 100644 index 000000000..8a8ea6e77 --- /dev/null +++ b/transitclock/src/main/java/org/transitclock/core/barefoot/ReferenceId.java @@ -0,0 +1,60 @@ +package org.transitclock.core.barefoot; + +import java.util.Objects; + +public class ReferenceId { + int stopPathIndex; + int segmentIndex; + static long mutiplier=1000; + public ReferenceId(int stopPathIndex, int segmentIndex) { + super(); + this.stopPathIndex = stopPathIndex; + this.segmentIndex = segmentIndex; + } + + public int getStopPathIndex() { + return stopPathIndex; + } + public void setStopPathIndex(int stopPathIndex) { + this.stopPathIndex = stopPathIndex; + } + public int getSegmentIndex() { + return segmentIndex; + } + public void setSegmentIndex(int segmentIndex) { + this.segmentIndex = segmentIndex; + } + static ReferenceId deconstructRefId(long refId) + { + int segmentIndex=(int) Math.floorDiv(refId,mutiplier); + int stopPathIndex=(int) Math.floorMod(refId,mutiplier); + return new ReferenceId(stopPathIndex, segmentIndex); + } + long getRefId() + { + return stopPathIndex+segmentIndex*mutiplier; + } + + @Override + public String toString() { + return "ReferenceId [stopPathIndex=" + stopPathIndex + ", segmentIndex=" + segmentIndex + "]"; + } + + @Override + public int hashCode() { + return Objects.hash(segmentIndex, stopPathIndex); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ReferenceId other = (ReferenceId) obj; + return segmentIndex == other.segmentIndex && stopPathIndex == other.stopPathIndex; + } + +} diff --git a/transitclock/src/main/java/org/transitclock/core/barefoot/TransitClockRoadReader.java b/transitclock/src/main/java/org/transitclock/core/barefoot/TransitClockRoadReader.java index 54ccef9e5..30c113f6c 100644 --- a/transitclock/src/main/java/org/transitclock/core/barefoot/TransitClockRoadReader.java +++ b/transitclock/src/main/java/org/transitclock/core/barefoot/TransitClockRoadReader.java @@ -5,6 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.transitclock.applications.Core; +import org.transitclock.configData.CoreConfig; import org.transitclock.core.Indices; import org.transitclock.db.structs.Block; import org.transitclock.db.structs.Trip; @@ -12,6 +13,8 @@ import com.bmwcarit.barefoot.road.BaseRoad; import com.bmwcarit.barefoot.road.RoadReader; +import com.bmwcarit.barefoot.spatial.Geography; +import com.bmwcarit.barefoot.spatial.SpatialOperator; import com.bmwcarit.barefoot.util.SourceException; import com.esri.core.geometry.Line; import com.esri.core.geometry.Point; @@ -29,6 +32,8 @@ public class TransitClockRoadReader implements RoadReader { private static final Logger logger = LoggerFactory.getLogger(TransitClockRoadReader.class); + private static SpatialOperator spatial = new Geography(); + public TransitClockRoadReader(Block block, int tripIndex) { trip = block.getTrip(tripIndex); @@ -59,12 +64,11 @@ public BaseRoad next() throws SourceException { polyLineSegment.setEnd(endPoint); polyLine.addSegment(polyLineSegment, false); - - logger.debug("Adding segment -->" +startPoint.toString() + " : "+endPoint.toString()); - - return new BaseRoad(indices.hashCode(), segmentCounter, segmentCounter++, indices.getStopPathIndex(), true, (short) 1, 1F, 60F, 60F, 100F, - polyLine); - + + ReferenceId refId=new ReferenceId(indices.getStopPathIndex(),indices.getSegmentIndex()); + + return new BaseRoad(indices.hashCode(), segmentCounter, segmentCounter++, refId.getRefId(), true, (short) 1, 1F, 60F, 60F, (float)spatial.length(polyLine), + polyLine); } diff --git a/transitclock/src/main/resources/logback.xml b/transitclock/src/main/resources/logback.xml index 4352bce24..2b5af3bf5 100755 --- a/transitclock/src/main/resources/logback.xml +++ b/transitclock/src/main/resources/logback.xml @@ -326,7 +326,7 @@ UTF-8 - ${DEFAULT_PATTERN} + ${DATA_PATTERN} @@ -484,7 +484,7 @@ - + @@ -593,6 +593,10 @@ level="info" additivity="true"> + + + From 8723a40c3e4999812b6b6cad98abbf23697b0af8 Mon Sep 17 00:00:00 2001 From: Sean Og Crudden Date: Mon, 3 Jul 2023 15:23:14 +0100 Subject: [PATCH 6/6] Record source of spatial match. Set config paramters for which matcher(s) to use. --- .../transitclock/configData/CoreConfig.java | 4 ++++ .../ArrivalDepartureGeneratorDefaultImpl.java | 2 +- .../org/transitclock/core/AvlProcessor.java | 13 ++++++----- .../org/transitclock/core/SpatialMatch.java | 22 +++++++++++++++---- .../org/transitclock/core/SpatialMatcher.java | 6 +++-- .../transitclock/core/TemporalMatcher.java | 3 ++- .../core/barefoot/BareFootMapMatcher.java | 7 +++--- .../org/transitclock/db/structs/Match.java | 15 +++++++++++++ 8 files changed, 56 insertions(+), 16 deletions(-) diff --git a/transitclock/src/main/java/org/transitclock/configData/CoreConfig.java b/transitclock/src/main/java/org/transitclock/configData/CoreConfig.java index f8a189989..fe066c8d0 100755 --- a/transitclock/src/main/java/org/transitclock/configData/CoreConfig.java +++ b/transitclock/src/main/java/org/transitclock/configData/CoreConfig.java @@ -49,6 +49,10 @@ public static int getDaysPopulateHistoricalCache() { private static IntegerConfigValue daysPopulateHistoricalCache = new IntegerConfigValue("transitclock.cache.core.daysPopulateHistoricalCache", 0, "How many days data to read in to populate historical cache on start up."); + + public static BooleanConfigValue useDefaultSpatialMatcher = new BooleanConfigValue("transitclock.cache.core.useDefaultSpatialMatcher", false, "Set to true to use default matcher"); + + public static BooleanConfigValue useBarefootSpatialMatcher = new BooleanConfigValue("transitclock.cache.core.useBarefootSpatialMatcher", true, "Set to true to use default matcher"); /** * When in playback mode or some other situations don't want to store * generated data such as arrivals/departures, events, and such to the diff --git a/transitclock/src/main/java/org/transitclock/core/ArrivalDepartureGeneratorDefaultImpl.java b/transitclock/src/main/java/org/transitclock/core/ArrivalDepartureGeneratorDefaultImpl.java index 80b7e6c53..591331b74 100755 --- a/transitclock/src/main/java/org/transitclock/core/ArrivalDepartureGeneratorDefaultImpl.java +++ b/transitclock/src/main/java/org/transitclock/core/ArrivalDepartureGeneratorDefaultImpl.java @@ -625,7 +625,7 @@ private void estimateArrivalsDeparturesWithoutPreviousMatch( // Determine departure time for first stop of trip SpatialMatch beginningOfTrip = new SpatialMatch(0, block, - tripIndex, 0, 0, 0.0, 0.0); + tripIndex, 0, 0, 0.0, 0.0, SpatialMatch.MatchType.TRANSITCLOCK); long travelTimeFromFirstStopToMatch = TravelTimes.getInstance() .expectedTravelTimeBetweenMatches(vehicleId, avlReportTime, beginningOfTrip, newMatch); diff --git a/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java b/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java index 6c18deb31..127bee8a6 100644 --- a/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java +++ b/transitclock/src/main/java/org/transitclock/core/AvlProcessor.java @@ -440,13 +440,16 @@ public void matchNewFixForPredictableVehicle(VehicleState vehicleState) { logger.debug("STARTOFMATCHING"); logger.debug("Matching already predictable vehicle using new AVL " + "report. The old spatial match is {}", vehicleState); + + List spatialMatches = new ArrayList<>(); // Find possible spatial matches - List spatialMatches = SpatialMatcher - .getSpatialMatches(vehicleState); + if(CoreConfig.useDefaultSpatialMatcher.getValue()) + spatialMatches.addAll(SpatialMatcher + .getSpatialMatches(vehicleState)); - // This will augment the results of the original spatial matcher with the match from barefoot - spatialMatches.add(vehicleState.getMapMatchedSpatialMatch()); + if(CoreConfig.useBarefootSpatialMatcher.getValue()) + spatialMatches.add(vehicleState.getMapMatchedSpatialMatch()); logger.debug("For vehicleId={} found the following {} spatial " + "matches: {} ", vehicleState.getVehicleId(), @@ -828,7 +831,7 @@ private boolean matchVehicleToBlockAssignment(Block block, block, block.getTripIndex(trip), 0, // stopPathIndex 0, // segmentIndex distanceToSegment, - 0.0); // distanceAlongSegment + 0.0,SpatialMatch.MatchType.TRANSITCLOCK); // distanceAlongSegment bestMatch = new TemporalMatch(beginningOfTrip, new TemporalDifference(0)); diff --git a/transitclock/src/main/java/org/transitclock/core/SpatialMatch.java b/transitclock/src/main/java/org/transitclock/core/SpatialMatch.java index c965d12d2..9b6cbadfa 100644 --- a/transitclock/src/main/java/org/transitclock/core/SpatialMatch.java +++ b/transitclock/src/main/java/org/transitclock/core/SpatialMatch.java @@ -49,6 +49,12 @@ public class SpatialMatch { protected final double distanceAlongSegment; protected final VehicleAtStopInfo atStop; protected final Location predictedLocation; + protected final MatchType type; + + public enum MatchType { + TRANSITCLOCK, + BAREFOOT + } ; private static final Logger logger = LoggerFactory.getLogger(SpatialMatch.class); @@ -58,7 +64,7 @@ public class SpatialMatch { public SpatialMatch(long avlTime, Block block, int tripIndex, int stopPathIndex, int segmentIndex, - double distanceToSegment, double distanceAlongSegment) { + double distanceToSegment, double distanceAlongSegment, MatchType type) { this.avlTime = avlTime; this.block = block; this.tripIndex = tripIndex; @@ -69,7 +75,12 @@ public SpatialMatch(long avlTime, Block block, // Determine whether at stop this.atStop = atStop(); - this.predictedLocation = computeLocation(); + this.predictedLocation = computeLocation(); + this.type=type; + } + + public MatchType getType() { + return type; } /** @@ -145,6 +156,7 @@ public SpatialMatch(SpatialMatch toCopy, Trip newTrip) { } // recomupte predictedLocation for above reasons as well this.predictedLocation = toCopy.computeLocation(toCopy.getIndices(), toCopy.distanceAlongSegment); + this.type=toCopy.type; } /** @@ -167,6 +179,7 @@ public SpatialMatch(SpatialMatch toCopy, Indices newIndices, this.distanceAlongSegment = distanceAlongSegment; this.atStop = toCopy.atStop; this.predictedLocation = computeLocation(newIndices, distanceAlongSegment); + this.type = toCopy.type; } /** @@ -184,6 +197,7 @@ protected SpatialMatch(SpatialMatch toCopy) { this.distanceAlongSegment = toCopy.distanceAlongSegment; this.atStop = toCopy.atStop; this.predictedLocation = toCopy.predictedLocation; + this.type = toCopy.type; } /** @@ -452,7 +466,7 @@ public SpatialMatch getMatchAtJustBeforeNextStop() { m.getStopPathIndex(), segmentIndex, Double.NaN, // distanceToSegment not set to a valid value - segmentLength); + segmentLength, this.type); } /** @@ -511,7 +525,7 @@ public SpatialMatch getMatchAtPreviousStop() { indices.getStopPathIndex(), indices.getSegmentIndex(), Double.NaN, // distanceToSegment not set to a valid value - segmentVectorLength); + segmentVectorLength, this.type); } /** diff --git a/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java b/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java index abaeeae6a..caeaba980 100644 --- a/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java +++ b/transitclock/src/main/java/org/transitclock/core/SpatialMatcher.java @@ -618,7 +618,8 @@ private void processPossiblePotentialMatch(AvlReport avlReport, potentialMatchIndices.getStopPathIndex(), potentialMatchIndices.getSegmentIndex(), distanceToSegment, - distanceAlongSegment); + distanceAlongSegment, + SpatialMatch.MatchType.TRANSITCLOCK); logger.debug("For vehicleId={} examining match to see if it should " + "be included in list of spatial matches. {}", avlReport.getVehicleId(), spatialMatch); @@ -856,7 +857,8 @@ && withinAllowableDistanceOfLayover(avlReport.getVehicleId(), indexOfLastStopPath, indexOfLastSegment, Double.NaN, // distanceToSegment set to a non-valid value - segmentLength); + segmentLength, + SpatialMatch.MatchType.TRANSITCLOCK); // Add that match to list of possible SpatialMatches logger.debug("Because vehicleId={} within specified distance " + diff --git a/transitclock/src/main/java/org/transitclock/core/TemporalMatcher.java b/transitclock/src/main/java/org/transitclock/core/TemporalMatcher.java index fc2cac910..88f83eb1d 100644 --- a/transitclock/src/main/java/org/transitclock/core/TemporalMatcher.java +++ b/transitclock/src/main/java/org/transitclock/core/TemporalMatcher.java @@ -102,7 +102,8 @@ private static TemporalDifference determineHowFarOffScheduledTime( 0, // stopPathIndex 0, // segmentIndex 0.0, // distanceToSegment - 0.0); // distanceAlongSegment + 0.0, + SpatialMatch.MatchType.TRANSITCLOCK); // distanceAlongSegment int tripStartTimeSecs = spatialMatch.getTrip().getStartTime(); int travelTimeForCurrentTrip = TravelTimes.getInstance().expectedTravelTimeBetweenMatches(vehicleId, diff --git a/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java b/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java index 7c308ef5a..38df632b8 100644 --- a/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java +++ b/transitclock/src/main/java/org/transitclock/core/barefoot/BareFootMapMatcher.java @@ -25,6 +25,7 @@ import com.bmwcarit.barefoot.topology.Dijkstra; import com.esri.core.geometry.Point; import org.transitclock.utils.Geo; +import org.transitclock.core.SpatialMatch; public class BareFootMapMatcher implements MapMatcher { @@ -60,7 +61,7 @@ public void setMatcher(Block block, Date assignmentTime) { barefootMatcher = new Matcher(barefootMap, new Dijkstra(), new TimePriority(), new Geography()); - barefootMatcher.shortenTurns(false); + barefootMatcher.shortenTurns(false); barefootState = new MatcherKState(); } @@ -96,10 +97,10 @@ public SpatialMatch getSpatialMatch(AvlReport avlReport) { avlReport.getVehicleId(), avlReport.getAssignmentId(), Geo.distance(location, avlReport.getLocation()), refId, estimate.filtprob(), estimate.seqprob()); - + return new SpatialMatch(avlReport.getTime(), block, tripIndex, refId.getStopPathIndex(), refId.getSegmentIndex(), 0, spatial.intercept(estimate.point().edge().geometry(), point) - * spatial.length(estimate.point().edge().geometry())); + * spatial.length(estimate.point().edge().geometry()), SpatialMatch.MatchType.BAREFOOT); } } diff --git a/transitclock/src/main/java/org/transitclock/db/structs/Match.java b/transitclock/src/main/java/org/transitclock/db/structs/Match.java index 590781d0f..c00e399f0 100644 --- a/transitclock/src/main/java/org/transitclock/db/structs/Match.java +++ b/transitclock/src/main/java/org/transitclock/db/structs/Match.java @@ -39,6 +39,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.transitclock.applications.Core; +import org.transitclock.core.SpatialMatch; +import org.transitclock.core.SpatialMatch.MatchType; import org.transitclock.core.TemporalMatch; import org.transitclock.core.VehicleState; import org.transitclock.db.hibernate.HibernateUtils; @@ -127,6 +129,9 @@ public class Match implements Lifecycle, Serializable { @Column private final boolean atStop; + @Column + private SpatialMatch.MatchType type; + // Needed because serializable due to Hibernate requirement private static final long serialVersionUID = -7582135605912244678L; @@ -157,6 +162,7 @@ public Match(VehicleState vehicleState) { this.distanceAlongStopPath = (float) (lastMatch!=null ? lastMatch.getDistanceAlongStopPath() : 0.0); this.atStop = vehicleState.getMatch().isAtStop(); + this.type=lastMatch.getType(); // Log each creation of a Match to the match.log log file logger.info(this.toString()); @@ -186,6 +192,15 @@ protected Match() { this.distanceAlongSegment = Float.NaN; this.distanceAlongStopPath = Float.NaN; this.atStop = false; + this.type= MatchType.TRANSITCLOCK; + } + + public SpatialMatch.MatchType getType() { + return type; + } + + public void setType(SpatialMatch.MatchType type) { + this.type = type; } /**