Skip to content

Tc issue 262 #271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion transitclock/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,12 @@
<dependency>
<groupId>com.esri.geometry</groupId>
<artifactId>esri-geometry-api</artifactId>
<version>1.1</version>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>com.bmw-carit</groupId>
<artifactId>barefoot</artifactId>
<version>0.1.5</version>
</dependency>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,13 @@ public void matchNewFixForPredictableVehicle(VehicleState vehicleState) {
// Find possible spatial matches
List<SpatialMatch> spatialMatches = SpatialMatcher
.getSpatialMatches(vehicleState);

// This will augment the results of the original spatial matcher with the match from barefoot
spatialMatches.add(vehicleState.getMapMatchedSpatialMatch());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be good to record the provenance of the match in spatialMatches that ultimately gets selected in getBestTemporalMatch


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()
Expand Down
8 changes: 8 additions & 0 deletions transitclock/src/main/java/org/transitclock/core/Indices.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -634,4 +635,11 @@ public boolean controlPoint() {
return false;
}

@Override
public int hashCode() {
return Objects.hash(block, segmentIndex, stopPathIndex, tripIndex);
}



}
12 changes: 12 additions & 0 deletions transitclock/src/main/java/org/transitclock/core/MapMatcher.java
Original file line number Diff line number Diff line change
@@ -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);
SpatialMatch getSpatialMatch(AvlReport avlReport);
}
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -732,6 +732,7 @@ && withinAllowableDistanceOfLayover(avlReport.getVehicleId(),
*/
public static List<SpatialMatch>
getSpatialMatches(VehicleState vehicleState) {

// Some convenience variables
TemporalMatch previousMatch = vehicleState.getMatch();
SpatialMatcher spatialMatcher = new SpatialMatcher();
Expand Down
28 changes: 22 additions & 6 deletions transitclock/src/main/java/org/transitclock/core/VehicleState.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -66,6 +65,9 @@ public class VehicleState {
// First is most recent
private LinkedList<AvlReport> avlReportHistory =
new LinkedList<AvlReport>();



private List<IpcPrediction> predictions;
private TemporalDifference realTimeSchedAdh;

Expand Down Expand Up @@ -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;
Expand All @@ -109,8 +112,6 @@ public void setHeadway(Headway headway) {
this.headway = headway;
}



public HoldingTime getHoldingTime() {
return holdingTime;
}
Expand All @@ -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.
Expand Down Expand Up @@ -163,9 +165,23 @@ 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 SpatialMatch getMapMatchedSpatialMatch()
{
if(mapMatcher!=null)
return mapMatcher.getSpatialMatch(getAvlReport());
else
return null;
}



/**
* Sets the block for this VehicleState to null. Also sets assignmentId
* to null and predictable to false.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package org.transitclock.core.barefoot;

import java.util.Date;
import java.util.Set;

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;

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.spatial.SpatialOperator;
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 Block block = null;

private int tripIndex = -1;

private static SpatialOperator spatial = new Geography();

private static final Logger logger = LoggerFactory.getLogger(BareFootMapMatcher.class);

@Override
public void setMatcher(Block block, Date assignmentTime) {

if (block != null) {

this.block = block;

tripIndex = block.activeTripIndex(assignmentTime, 0);

TransitClockRoadReader roadReader = new TransitClockRoadReader(block, tripIndex);

barefootMap = RoadMap.Load(roadReader);

barefootMap.construct();

barefootMatcher = new Matcher(barefootMap, new Dijkstra<Road, RoadPoint>(), new TimePriority(),
new Geography());

barefootMatcher.shortenTurns(false);

barefootState = new MatcherKState();
}
}

@Override
public SpatialMatch getSpatialMatch(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<MatcherCandidate> result = barefootMatcher.execute(barefootState.vector(), barefootState.sample(),
sample);

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());

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;
}

}
Original file line number Diff line number Diff line change
@@ -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;
}

}
Loading