1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.Linq;
|
---|
4 | using System.Text;
|
---|
5 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
6 | using HeuristicLab.Common;
|
---|
7 | using HeuristicLab.Data;
|
---|
8 | using HeuristicLab.Parameters;
|
---|
9 | using HeuristicLab.PDPSimulation.DomainModel;
|
---|
10 |
|
---|
11 | namespace HeuristicLab.PDPSimulation.DistanceMeasures {
|
---|
12 | [StorableClass]
|
---|
13 | public class PathMeasure: DistanceMatrixMeasure {
|
---|
14 | private ValueParameter<BoolMatrix> EdgesParameter {
|
---|
15 | get { return (ValueParameter<BoolMatrix>)Parameters["Edges"]; }
|
---|
16 | }
|
---|
17 |
|
---|
18 | private ValueParameter<IntMatrix> VerticesParameter {
|
---|
19 | get { return (ValueParameter<IntMatrix>)Parameters["Vertices"]; }
|
---|
20 | }
|
---|
21 |
|
---|
22 | public ValueParameter<BoolValue> UseDistanceMatrix {
|
---|
23 | get { return (ValueParameter<BoolValue>)Parameters["UseDistanceMatrix"]; }
|
---|
24 | }
|
---|
25 |
|
---|
26 | public ValueParameter<DoubleValue> PixelScalingFactor {
|
---|
27 | get { return (ValueParameter<DoubleValue>)Parameters["PixelScalingFactor"]; }
|
---|
28 | }
|
---|
29 |
|
---|
30 | public BoolMatrix Edges {
|
---|
31 | get {
|
---|
32 | return EdgesParameter.Value;
|
---|
33 | }
|
---|
34 | set {
|
---|
35 | EdgesParameter.Value = value;
|
---|
36 | }
|
---|
37 | }
|
---|
38 |
|
---|
39 | public IntMatrix Vertices {
|
---|
40 | get {
|
---|
41 | return VerticesParameter.Value;
|
---|
42 | }
|
---|
43 | set {
|
---|
44 | VerticesParameter.Value = value;
|
---|
45 | }
|
---|
46 | }
|
---|
47 |
|
---|
48 | public PathMeasure()
|
---|
49 | : base() {
|
---|
50 | Parameters.Add(new ValueParameter<BoolMatrix>("Edges", new BoolMatrix()));
|
---|
51 | Parameters.Add(new ValueParameter<IntMatrix>("Vertices", new IntMatrix()));
|
---|
52 | Parameters.Add(new ValueParameter<BoolValue>("UseDistanceMatrix", new BoolValue(true)));
|
---|
53 | Parameters.Add(new ValueParameter<DoubleValue>("PixelScalingFactor", new DoubleValue(1.0)));
|
---|
54 |
|
---|
55 | EdgesParameter.GetsCollected = false;
|
---|
56 | VerticesParameter.GetsCollected = false;
|
---|
57 |
|
---|
58 | graph = null;
|
---|
59 |
|
---|
60 | AttachEventHandlers();
|
---|
61 | }
|
---|
62 |
|
---|
63 | [StorableConstructor]
|
---|
64 | private PathMeasure(bool deserializing) : base(deserializing) {
|
---|
65 | }
|
---|
66 | private PathMeasure(PathMeasure original, Cloner cloner)
|
---|
67 | : base(original, cloner) {
|
---|
68 | }
|
---|
69 | public override IDeepCloneable Clone(Cloner cloner) {
|
---|
70 | return new PathMeasure(this, cloner);
|
---|
71 | }
|
---|
72 |
|
---|
73 | private void AttachEventHandlers() {
|
---|
74 | EdgesParameter.ValueChanged += new EventHandler(EdgesParameter_ValueChanged);
|
---|
75 | VerticesParameter.ValueChanged += new EventHandler(VerticesParameter_ValueChanged);
|
---|
76 | }
|
---|
77 |
|
---|
78 | void VerticesParameter_ValueChanged(object sender, EventArgs e) {
|
---|
79 | graph = null;
|
---|
80 | }
|
---|
81 | void EdgesParameter_ValueChanged(object sender, EventArgs e) {
|
---|
82 | graph = null;
|
---|
83 | }
|
---|
84 |
|
---|
85 | [StorableHook(HookType.AfterDeserialization)]
|
---|
86 | private void AfterDeserializationHook() {
|
---|
87 | graph = null;
|
---|
88 | AttachEventHandlers();
|
---|
89 | }
|
---|
90 |
|
---|
91 | #region Graph
|
---|
92 | private List<Vertex> graph;
|
---|
93 |
|
---|
94 | class Vertex {
|
---|
95 | public int Index { get; set; }
|
---|
96 | public Dictionary<Vertex, double> Edges { get; set; }
|
---|
97 |
|
---|
98 | public Vertex() {
|
---|
99 | Edges = new Dictionary<Vertex, double>();
|
---|
100 | }
|
---|
101 | }
|
---|
102 |
|
---|
103 | private void BuildGraph() {
|
---|
104 | graph = new List<Vertex>();
|
---|
105 |
|
---|
106 | IntMatrix vertices = VerticesParameter.Value;
|
---|
107 | BoolMatrix edges = EdgesParameter.Value;
|
---|
108 | for (int i = 0; i < vertices.Rows; i++) {
|
---|
109 | Vertex v = new Vertex();
|
---|
110 | v.Index = i;
|
---|
111 | graph.Add(v);
|
---|
112 | }
|
---|
113 |
|
---|
114 | for (int i = 0; i < vertices.Rows; i++) {
|
---|
115 | for (int j = 0; j < vertices.Rows; j++) {
|
---|
116 | if (edges[i, j]) {
|
---|
117 | double weight = GetEuclideanDistance(vertices[i, 0], vertices[i, 1], vertices[j, 0], vertices[j, 1]);
|
---|
118 | graph[i].Edges.Add(graph[j], weight);
|
---|
119 | }
|
---|
120 | }
|
---|
121 | }
|
---|
122 | }
|
---|
123 |
|
---|
124 | private List<Vertex> FindShortestPath(Vertex source, Vertex destination) {
|
---|
125 | Dictionary<Vertex, double> distance = new Dictionary<Vertex, double>();
|
---|
126 | Dictionary<Vertex, Vertex> previous = new Dictionary<Vertex, Vertex>();
|
---|
127 | foreach (Vertex v in graph) {
|
---|
128 | distance[v] = double.MaxValue;
|
---|
129 | previous[v] = null;
|
---|
130 | }
|
---|
131 |
|
---|
132 | List<Vertex> Q = new List<Vertex>(graph);
|
---|
133 | distance[source] = 0;
|
---|
134 | Q.Remove(source);
|
---|
135 | Q.Insert(0, source);
|
---|
136 |
|
---|
137 | bool found = false;
|
---|
138 | while (!found && Q.Count > 0) {
|
---|
139 | Vertex u = Q[0];
|
---|
140 | if (distance[u] == double.MaxValue)
|
---|
141 | break;
|
---|
142 | Q.Remove(u);
|
---|
143 | if (u == destination) {
|
---|
144 | found = true;
|
---|
145 | } else {
|
---|
146 | foreach (Vertex v in u.Edges.Keys) {
|
---|
147 | if (Q.Contains(v)) {
|
---|
148 | double alt = distance[u] + u.Edges[v];
|
---|
149 | if (alt < distance[v]) {
|
---|
150 | distance[v] = alt;
|
---|
151 | previous[v] = u;
|
---|
152 |
|
---|
153 | Q.Remove(v);
|
---|
154 | int i = 0;
|
---|
155 | while (i < Q.Count && distance[Q[i]] < alt) {
|
---|
156 | i++;
|
---|
157 | }
|
---|
158 | Q.Insert(i, v);
|
---|
159 | }
|
---|
160 | }
|
---|
161 | }
|
---|
162 | }
|
---|
163 | }
|
---|
164 |
|
---|
165 | if (found) {
|
---|
166 | List<Vertex> shortestPath = new List<Vertex>();
|
---|
167 | Vertex u = destination;
|
---|
168 |
|
---|
169 | while (previous[u] != null) {
|
---|
170 | shortestPath.Insert(0, u);
|
---|
171 | u = previous[u];
|
---|
172 | }
|
---|
173 |
|
---|
174 | shortestPath.Insert(0, source);
|
---|
175 |
|
---|
176 | if(shortestPath.Count == 1)
|
---|
177 | shortestPath.Insert(0, source);
|
---|
178 |
|
---|
179 | return shortestPath;
|
---|
180 | } else {
|
---|
181 | return null;
|
---|
182 | }
|
---|
183 | }
|
---|
184 |
|
---|
185 | private double GetPathLength(List<Vertex> path) {
|
---|
186 | double length = 0;
|
---|
187 |
|
---|
188 | if (path.Count > 2) {
|
---|
189 | for (int i = 0; i < path.Count - 1; i++) {
|
---|
190 | length += path[i].Edges[path[i + 1]];
|
---|
191 | }
|
---|
192 | }
|
---|
193 |
|
---|
194 | return length;
|
---|
195 | }
|
---|
196 | #endregion
|
---|
197 |
|
---|
198 | protected int GetVertexMapping(double x, double y) {
|
---|
199 | IntMatrix vertices = VerticesParameter.Value;
|
---|
200 | int index = -1;
|
---|
201 |
|
---|
202 | int ix = (int)Math.Round(x);
|
---|
203 | int iy = (int)Math.Round(y);
|
---|
204 |
|
---|
205 | int i = 0;
|
---|
206 | while (index < 0 && i < vertices.Rows) {
|
---|
207 | if (vertices[i, 0] == ix && vertices[i, 1] == iy) {
|
---|
208 | index = i;
|
---|
209 | }
|
---|
210 | i++;
|
---|
211 | }
|
---|
212 |
|
---|
213 | return index;
|
---|
214 | }
|
---|
215 |
|
---|
216 | public override double GetDistance(double sourceX, double sourceY,
|
---|
217 | double destX, double destY) {
|
---|
218 | if (UseDistanceMatrix.Value.Value)
|
---|
219 | return base.GetDistance(sourceX, sourceY, destX, destY);
|
---|
220 | else {
|
---|
221 | int i = GetVertexMapping(sourceX, sourceY);
|
---|
222 | int j = GetVertexMapping(destX, destY);
|
---|
223 |
|
---|
224 | if (graph == null)
|
---|
225 | BuildGraph();
|
---|
226 |
|
---|
227 | List<Vertex> path = FindShortestPath(graph[i], graph[j]);
|
---|
228 | if (path == null)
|
---|
229 | return int.MaxValue;
|
---|
230 | else
|
---|
231 | return GetPathLength(path) / PixelScalingFactor.Value.Value;
|
---|
232 | }
|
---|
233 | }
|
---|
234 |
|
---|
235 | public override void Move(double sourceX, double sourceY,
|
---|
236 | double currentX, double currentY,
|
---|
237 | double destX, double destY, double time, Vehicle.MoveInformation moveInfo,
|
---|
238 | out double newPosX, out double newPosY, out double length) {
|
---|
239 | if (graph == null)
|
---|
240 | BuildGraph();
|
---|
241 |
|
---|
242 | int i = GetVertexMapping(sourceX, sourceY);
|
---|
243 | int j = GetVertexMapping(destX, destY);
|
---|
244 |
|
---|
245 | if (moveInfo.Source != i || moveInfo.Dest != j) {
|
---|
246 | moveInfo.Source = i;
|
---|
247 | moveInfo.Dest = j;
|
---|
248 | moveInfo.Segment = 0;
|
---|
249 | moveInfo.Path = null;
|
---|
250 | }
|
---|
251 |
|
---|
252 | if (moveInfo.Path == null) {
|
---|
253 | moveInfo.Path = FindShortestPath(graph[i], graph[j]);
|
---|
254 | }
|
---|
255 | List<Vertex> path = (List<Vertex>)(moveInfo.Path);
|
---|
256 | double step = 0;
|
---|
257 | double pathDist = GetPathLength(path);
|
---|
258 | double actualDist = 0;
|
---|
259 | if (UseDistanceMatrix.Value.Value)
|
---|
260 | actualDist = base.GetDistance(sourceX, sourceY, destX, destY);
|
---|
261 | else
|
---|
262 | actualDist = pathDist / PixelScalingFactor.Value.Value;
|
---|
263 |
|
---|
264 | if (actualDist != 0)
|
---|
265 | step = pathDist / actualDist;
|
---|
266 |
|
---|
267 | IntMatrix vertices = VerticesParameter.Value;
|
---|
268 | length = 0;
|
---|
269 | newPosX = currentX;
|
---|
270 | newPosY = currentY;
|
---|
271 | while (time > 0 && moveInfo.Segment < path.Count - 1) {
|
---|
272 | int nextIndex = path[moveInfo.Segment + 1].Index;
|
---|
273 | double nextX = vertices[nextIndex, 0];
|
---|
274 | double nextY = vertices[nextIndex, 1];
|
---|
275 |
|
---|
276 | double distance = 0;
|
---|
277 | if(step != 0)
|
---|
278 | distance = GetEuclideanDistance(newPosX, newPosY, nextX, nextY) / step;
|
---|
279 | if (distance <= time) {
|
---|
280 | newPosX = nextX;
|
---|
281 | newPosY = nextY;
|
---|
282 |
|
---|
283 | length += distance;
|
---|
284 | time -= distance;
|
---|
285 | moveInfo.Segment++;
|
---|
286 | } else {
|
---|
287 | double vx = nextX - newPosX;
|
---|
288 | double vy = nextY - newPosY;
|
---|
289 | double vl = GetEuclideanDistance(newPosX, newPosY, nextX, nextY);
|
---|
290 | vx = (vx / vl) * time * step;
|
---|
291 | vy = (vy / vl) * time * step;
|
---|
292 |
|
---|
293 | length += GetEuclideanDistance(newPosX, newPosY, newPosX + vx, newPosY + vy) / step;
|
---|
294 | newPosX = newPosX + vx;
|
---|
295 | newPosY = newPosY + vy;
|
---|
296 | time = 0;
|
---|
297 | }
|
---|
298 | }
|
---|
299 | }
|
---|
300 | }
|
---|
301 | }
|
---|