Skip to content

Commit 983d45d

Browse files
committed
refactor
1 parent 8af75bd commit 983d45d

File tree

14 files changed

+181
-81
lines changed

14 files changed

+181
-81
lines changed

examples/Sandwych.MapMatchingKit.Examples.HelloWorldApp/Program.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ static void Main(string[] args)
2929
Console.WriteLine("The road map has been loaded");
3030

3131
var matcher = new Matcher(map, new DijkstraRouter<Road, RoadPoint>(), Costs.TimePriorityCost, spatial);
32-
matcher.MaxDistance = 500; // set maximum searching distance between two GPS points to 500 meters.
33-
matcher.MaxRadius = 100.0; // sets maximum radius for candidate selection to 200 meters
32+
matcher.MaxDistance = 1000; // set maximum searching distance between two GPS points to 500 meters.
33+
matcher.MaxRadius = 200.0; // sets maximum radius for candidate selection to 200 meters
3434

3535
var kstate = new MatcherKState();
3636

@@ -43,7 +43,6 @@ static void Main(string[] args)
4343
var startedOn = DateTime.Now;
4444
foreach (var sample in samples)
4545
{
46-
Console.WriteLine("Matching GPS Sample: [ID={0}, Time={1}]", sample.Id, sample.Time);
4746
var vector = matcher.Execute(kstate.Vector(), kstate.Sample, sample);
4847
kstate.Update(vector, sample);
4948
}
@@ -55,7 +54,15 @@ static void Main(string[] args)
5554
Console.WriteLine("Results:");
5655
foreach (var cand in candidatesSequence)
5756
{
58-
Console.WriteLine("Matched: [SampleID={0}, EdgeID={1}]", cand.RoadPoint.Coordinate, cand.RoadPoint.Edge.Id);
57+
var roadId = cand.Point.Edge.RoadInfo.Id; // original road id
58+
var heading = cand.Point.Edge.Headeing; // heading
59+
var coord = cand.Point.Coordinate; // GPS position (on the road)
60+
Console.WriteLine("RoadID={0}\t\tFraction={1}", roadId, cand.Point.Fraction);
61+
if (cand.Transition != null)
62+
{
63+
var geom = cand.Transition.Route.ToGeometry(); // path geometry from last matching candidate
64+
Console.WriteLine("fuck");
65+
}
5966
}
6067

6168
Console.WriteLine("All done!");

src/Sandwych.MapMatchingKit/Markov/AbstractFilter.cs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public abstract class AbstractFilter<TCandidate, TTransition, TSample> :
2828
/// <param name="predecessors">Predecessor state candidate <i>s<sub>t-1</sub></i>.</param>
2929
/// <param name="sample">Measurement sample.</param>
3030
/// <returns>Set of tuples consisting of a {@link StateCandidate} and its emission probability.</returns>
31-
public abstract IReadOnlyCollection<(TCandidate, double)> Candidates(IEnumerable<TCandidate> predecessors, in TSample sample);
31+
public abstract IReadOnlyCollection<CandidateProbability<TCandidate>> Candidates(IEnumerable<TCandidate> predecessors, in TSample sample);
3232

3333

3434
/// <summary>
@@ -44,7 +44,7 @@ public abstract class AbstractFilter<TCandidate, TTransition, TSample> :
4444
/// <i>s<sub>t</sub></i> and its transition probability, or null if there is no
4545
/// transition.
4646
/// </returns>
47-
public abstract (TTransition, double) Transition(in (TSample, TCandidate) predecessor, in (TSample, TCandidate) candidate);
47+
public abstract TransitionProbability<TTransition> Transition(in (TSample, TCandidate) predecessor, in (TSample, TCandidate) candidate);
4848

4949

5050
/// <summary>
@@ -65,18 +65,17 @@ public abstract class AbstractFilter<TCandidate, TTransition, TSample> :
6565
/// all transitions from <i>s<sub>t-1</sub></i> to <i>s<sub>t</sub></i> and its
6666
/// transition probability, or null if there no transition.
6767
/// </returns>
68-
public virtual IDictionary<TCandidate, IDictionary<TCandidate, (TTransition, double)>> Transitions(
68+
public virtual IDictionary<TCandidate, IDictionary<TCandidate, TransitionProbability<TTransition>>> Transitions(
6969
in (TSample, IEnumerable<TCandidate>) predecessors, in (TSample, IEnumerable<TCandidate>) candidates)
7070
{
7171
TSample sample = candidates.Item1;
7272
TSample previous = predecessors.Item1;
7373

74-
IDictionary<TCandidate, IDictionary<TCandidate, (TTransition, double)>> map =
75-
new Dictionary<TCandidate, IDictionary<TCandidate, (TTransition, double)>>();
74+
var map = new Dictionary<TCandidate, IDictionary<TCandidate, TransitionProbability<TTransition>>>();
7675

7776
foreach (TCandidate predecessor in predecessors.Item2)
7877
{
79-
map.Add(predecessor, new Dictionary<TCandidate, (TTransition, double)>());
78+
map.Add(predecessor, new Dictionary<TCandidate, TransitionProbability<TTransition>>());
8079

8180
foreach (TCandidate candidate in candidates.Item2)
8281
{
@@ -120,34 +119,34 @@ public virtual ICollection<TCandidate> Execute(IEnumerable<TCandidate> predecess
120119
var states = new HashSet<TCandidate>();
121120
foreach (var candidate in candidates)
122121
{
123-
states.Add(candidate.Item1);
122+
states.Add(candidate.Candidate);
124123
}
125124

126125
var transitions = this.Transitions((previous, predecessors), (sample, states));
127126

128127
foreach (var candidate in candidates)
129128
{
130-
var candidate_ = candidate.Item1;
129+
var candidate_ = candidate.Candidate;
131130
candidate_.Seqprob = Double.NegativeInfinity;
132131

133132
foreach (var predecessor in predecessors)
134133
{
135134
if (transitions[predecessor].TryGetValue(candidate_, out var transition))
136135
{
137136
//if (transition == null || transition.Item2 == 0)
138-
if (transition.Item2 == 0D)
137+
if (transition.Probability == 0D)
139138
{
140139
continue;
141140
}
142141

143-
candidate_.Filtprob = candidate_.Filtprob + (transition.Item2 * predecessor.Filtprob);
142+
candidate_.Filtprob = candidate_.Filtprob + (transition.Probability * predecessor.Filtprob);
144143

145-
var seqprob = predecessor.Seqprob + Math.Log10(transition.Item2) + Math.Log10(candidate.Item2);
144+
var seqprob = predecessor.Seqprob + Math.Log10(transition.Probability) + Math.Log10(candidate.Probability);
146145

147146
if (seqprob > candidate_.Seqprob)
148147
{
149148
candidate_.Predecessor = predecessor;
150-
candidate_.Transition = transition.Item1;
149+
candidate_.Transition = transition.Transition;
151150
candidate_.Seqprob = seqprob;
152151
}
153152
}
@@ -158,7 +157,7 @@ public virtual ICollection<TCandidate> Execute(IEnumerable<TCandidate> predecess
158157
continue;
159158
}
160159

161-
candidate_.Filtprob = candidate_.Filtprob * candidate.Item2;
160+
candidate_.Filtprob = candidate_.Filtprob * candidate.Probability;
162161
result.Add(candidate_);
163162

164163
normsum += candidate_.Filtprob;
@@ -174,14 +173,14 @@ public virtual ICollection<TCandidate> Execute(IEnumerable<TCandidate> predecess
174173
{
175174
foreach (var candidate in candidates)
176175
{
177-
if (candidate.Item2 == 0)
176+
if (candidate.Probability == 0)
178177
{
179178
continue;
180179
}
181-
TCandidate candidate_ = candidate.Item1;
182-
normsum += candidate.Item2;
183-
candidate_.Filtprob = candidate.Item2;
184-
candidate_.Seqprob = Math.Log10(candidate.Item2);
180+
TCandidate candidate_ = candidate.Candidate;
181+
normsum += candidate.Probability;
182+
candidate_.Filtprob = candidate.Probability;
183+
candidate_.Seqprob = Math.Log10(candidate.Probability);
185184
result.Add(candidate_);
186185
}
187186
}

src/Sandwych.MapMatchingKit/Markov/AbstractStateCandidate.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ public abstract class AbstractStateCandidate<TCandidate, TTransition, TSample> :
1616
public AbstractStateCandidate()
1717
{
1818
}
19+
20+
public abstract bool Equals(TCandidate other);
1921
}
2022
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Sandwych.MapMatchingKit.Markov
6+
{
7+
public readonly struct CandidateProbability<TCandidate>
8+
{
9+
public TCandidate Candidate { get; }
10+
public double Probability { get; }
11+
12+
public CandidateProbability(TCandidate cand, double prob)
13+
{
14+
this.Candidate = cand;
15+
this.Probability = prob;
16+
}
17+
}
18+
}

src/Sandwych.MapMatchingKit/Markov/IStateCandidate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Sandwych.MapMatchingKit.Markov
66
{
7-
public interface IStateCandidate<TCandidate, TTransition, TSample>
7+
public interface IStateCandidate<TCandidate, TTransition, TSample> : IEquatable<TCandidate>
88
where TCandidate : IStateCandidate<TCandidate, TTransition, TSample>
99
{
1010
double Seqprob { get; set; }
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Sandwych.MapMatchingKit.Markov
6+
{
7+
public readonly struct TransitionProbability<TTransition>
8+
{
9+
public TTransition Transition { get; }
10+
public double Probability { get; }
11+
12+
public TransitionProbability(TTransition transition, double prob)
13+
{
14+
this.Transition = transition;
15+
this.Probability = prob;
16+
}
17+
}
18+
}

src/Sandwych.MapMatchingKit/Matching/Matcher.cs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
namespace Sandwych.MapMatchingKit.Matching
1111
{
12+
using CandidateProbability = CandidateProbability<MatcherCandidate>;
13+
using TransitionProbability = TransitionProbability<MatcherTransition>;
14+
15+
1216
/// <summary>
1317
/// Matcher filter for Hidden Markov Model (HMM) map matching. It is a HMM filter (<see cref="IFilter{TCandidate, TTransition, TSample}"/>)
1418
/// and determines emission and transition probabilities for map matching with HMM.
@@ -77,7 +81,7 @@ public double Sigma
7781
public double MaxDistance { get; set; } = 15000.0;
7882

7983

80-
public override IReadOnlyCollection<(MatcherCandidate, double)> Candidates(
84+
public override IReadOnlyCollection<CandidateProbability> Candidates(
8185
IEnumerable<MatcherCandidate> predecessors, in MatcherSample sample)
8286
{
8387
var points_ = this._map.Radius(sample.Coordinate, this.MaxRadius);
@@ -91,20 +95,20 @@ public double Sigma
9195

9296
foreach (var predecessor in predecessors)
9397
{
94-
var pointExisted = dict.TryGetValue(predecessor.RoadPoint.Edge.Id, out var point);
98+
var pointExisted = dict.TryGetValue(predecessor.Point.Edge.Id, out var point);
9599
if (pointExisted && point.Edge != null
96-
&& _spatial.Distance(point.Coordinate, predecessor.RoadPoint.Coordinate) < this.Sigma
100+
&& _spatial.Distance(point.Coordinate, predecessor.Point.Coordinate) < this.Sigma
97101
&& ((point.Edge.Headeing == Heading.Forward
98-
&& point.Fraction < predecessor.RoadPoint.Fraction)
102+
&& point.Fraction < predecessor.Point.Fraction)
99103
|| (point.Edge.Headeing == Heading.Backward
100-
&& point.Fraction > predecessor.RoadPoint.Fraction)))
104+
&& point.Fraction > predecessor.Point.Fraction)))
101105
{
102106
points.Remove(point);
103-
points.Add(predecessor.RoadPoint);
107+
points.Add(predecessor.Point);
104108
}
105109
}
106110

107-
var candidates = new List<(MatcherCandidate, double)>(points.Count);
111+
var candidates = new List<CandidateProbability>(points.Count);
108112

109113
foreach (var point in points)
110114
{
@@ -121,39 +125,39 @@ public double Sigma
121125
}
122126

123127
var candidate = new MatcherCandidate(point);
124-
candidates.Add((candidate, emission));
128+
candidates.Add(new CandidateProbability(candidate, emission));
125129
}
126130

127131
return candidates;
128132
}
129133

130-
public override (MatcherTransition, double) Transition(
134+
public override TransitionProbability Transition(
131135
in (MatcherSample, MatcherCandidate) predecessor, in (MatcherSample, MatcherCandidate) candidate)
132136
{
133137
throw new NotSupportedException();
134138
}
135139

136-
public override IDictionary<MatcherCandidate, IDictionary<MatcherCandidate, (MatcherTransition, double)>> Transitions(
140+
public override IDictionary<MatcherCandidate, IDictionary<MatcherCandidate, TransitionProbability>> Transitions(
137141
in (MatcherSample, IEnumerable<MatcherCandidate>) predecessors,
138142
in (MatcherSample, IEnumerable<MatcherCandidate>) candidates)
139143
{
140-
var targets = candidates.Item2.Select(c => c.RoadPoint);
144+
var targets = candidates.Item2.Select(c => c.Point);
141145

142-
var transitions = new Dictionary<MatcherCandidate, IDictionary<MatcherCandidate, (MatcherTransition, double)>>();
146+
var transitions = new Dictionary<MatcherCandidate, IDictionary<MatcherCandidate, TransitionProbability>>();
143147
var base_ = 1.0 * _spatial.Distance(predecessors.Item1.Coordinate, candidates.Item1.Coordinate) / 60.0;
144148
var bound = Math.Max(1000.0, Math.Min(this.MaxDistance, ((candidates.Item1.Time - predecessors.Item1.Time) / 1000.0) * 100.0));
145149

146150
foreach (var predecessor in predecessors.Item2)
147151
{
148-
var map = new Dictionary<MatcherCandidate, (MatcherTransition, double)>();
152+
var map = new Dictionary<MatcherCandidate, TransitionProbability>();
149153
//TODO check return
150-
var routes = _router.Route(predecessor.RoadPoint, targets, _cost, Costs.DistanceCost, bound);
154+
var routes = _router.Route(predecessor.Point, targets, _cost, Costs.DistanceCost, bound);
151155

152156
foreach (var candidate in candidates.Item2)
153157
{
154-
if (routes.TryGetValue(candidate.RoadPoint, out var edges))
158+
if (routes.TryGetValue(candidate.Point, out var edges))
155159
{
156-
var route = new Route(predecessor.RoadPoint, candidate.RoadPoint, edges);
160+
var route = new Route(predecessor.Point, candidate.Point, edges);
157161

158162
// According to Newson and Krumm 2009, transition probability is lambda *
159163
// Math.exp((-1.0) * lambda * Math.abs(dt - route.length())), however, we
@@ -168,7 +172,7 @@ public override (MatcherTransition, double) Transition(
168172
var transition = (1D / beta) * Math.Exp(
169173
(-1.0) * Math.Max(0D, route.Cost(_cost) - base_) / beta);
170174

171-
map.Add(candidate, (new MatcherTransition(route), transition));
175+
map.Add(candidate, new TransitionProbability(new MatcherTransition(route), transition));
172176
}
173177
}
174178

src/Sandwych.MapMatchingKit/Matching/MatcherCandidate.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,33 @@
66

77
namespace Sandwych.MapMatchingKit.Matching
88
{
9-
public class MatcherCandidate :
10-
AbstractStateCandidate<MatcherCandidate, MatcherTransition, MatcherSample>
9+
public sealed class MatcherCandidate : IStateCandidate<MatcherCandidate, MatcherTransition, MatcherSample>
1110
{
12-
public RoadPoint RoadPoint { get; }
11+
private readonly RoadPoint _point;
1312

14-
public MatcherCandidate(RoadPoint roadPoint)
13+
public ref readonly RoadPoint Point => ref _point;
14+
15+
public double Seqprob { get; set; }
16+
public double Filtprob { get; set; }
17+
public MatcherCandidate Predecessor { get; set; }
18+
public MatcherTransition Transition { get; set; }
19+
20+
public MatcherCandidate(in RoadPoint point)
1521
{
16-
this.RoadPoint = roadPoint;
22+
this._point = point;
1723
}
1824

1925
public override int GetHashCode() =>
20-
(this.RoadPoint, this.Predecessor, this.Transition, this.Filtprob, this.Seqprob).GetHashCode();
26+
(this.Point, this.Predecessor, this.Transition, this.Filtprob, this.Seqprob).GetHashCode();
27+
28+
public bool Equals(MatcherCandidate other)
29+
{
30+
if (object.ReferenceEquals(this, other))
31+
{
32+
return true;
33+
}
34+
35+
return this.Point.Equals(other.Point) && this.Predecessor.Equals(other.Predecessor) && this.Transition.Equals(other.Transition);
36+
}
2137
}
2238
}

src/Sandwych.MapMatchingKit/Matching/MatcherTransition.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55

66
namespace Sandwych.MapMatchingKit.Matching
77
{
8-
public readonly struct MatcherTransition
8+
public class MatcherTransition
99
{
1010
public Route Route { get; }
1111

1212
public MatcherTransition(Route route)
1313
{
14-
this.Route = route;
14+
this.Route = route ?? throw new ArgumentNullException(nameof(route));
1515
}
16+
17+
public override int GetHashCode() =>
18+
this.Route.GetHashCode();
1619
}
1720
}

src/Sandwych.MapMatchingKit/Roads/RoadPoint.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace Sandwych.MapMatchingKit.Roads
1010
{
11-
public readonly struct RoadPoint : IEdgePoint<Road>
11+
public readonly struct RoadPoint : IEdgePoint<Road>, IEquatable<RoadPoint>
1212
{
1313
public Road Edge { get; }
1414

@@ -46,5 +46,10 @@ public RoadPoint(in Road road, double fraction) : this(road, fraction, Geography
4646
public override int GetHashCode() =>
4747
(this.Edge, this.Fraction, this.Coordinate, this.Azimuth).GetHashCode();
4848

49+
50+
public bool Equals(RoadPoint other)
51+
{
52+
return object.ReferenceEquals(this.Edge, other.Edge) && this.Fraction == other.Fraction && this.Coordinate == other.Coordinate && this.Azimuth == other.Azimuth;
53+
}
4954
}
5055
}

0 commit comments

Comments
 (0)