├── README.md ├── data ├── StarTrek.txt └── StarTrek_gps.dat ├── result ├── output.txt └── pic │ ├── 1.png │ ├── 10.png │ ├── 100.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ ├── 2.png │ ├── 20.png │ ├── 21.png │ ├── 22.png │ ├── 23.png │ ├── 24.png │ ├── 25.png │ ├── 26.png │ ├── 27.png │ ├── 28.png │ ├── 29.png │ ├── 3.png │ ├── 30.png │ ├── 31.png │ ├── 32.png │ ├── 33.png │ ├── 34.png │ ├── 35.png │ ├── 36.png │ ├── 37.png │ ├── 38.png │ ├── 39.png │ ├── 4.png │ ├── 40.png │ ├── 41.png │ ├── 42.png │ ├── 43.png │ ├── 44.png │ ├── 45.png │ ├── 46.png │ ├── 47.png │ ├── 48.png │ ├── 49.png │ ├── 5.png │ ├── 50.png │ ├── 51.png │ ├── 52.png │ ├── 53.png │ ├── 54.png │ ├── 55.png │ ├── 56.png │ ├── 57.png │ ├── 58.png │ ├── 59.png │ ├── 6.png │ ├── 60.png │ ├── 61.png │ ├── 62.png │ ├── 63.png │ ├── 64.png │ ├── 65.png │ ├── 66.png │ ├── 67.png │ ├── 68.png │ ├── 69.png │ ├── 7.png │ ├── 70.png │ ├── 71.png │ ├── 72.png │ ├── 73.png │ ├── 74.png │ ├── 75.png │ ├── 76.png │ ├── 77.png │ ├── 78.png │ ├── 79.png │ ├── 8.png │ ├── 80.png │ ├── 81.png │ ├── 82.png │ ├── 83.png │ ├── 84.png │ ├── 85.png │ ├── 86.png │ ├── 87.png │ ├── 88.png │ ├── 89.png │ ├── 9.png │ ├── 90.png │ ├── 91.png │ ├── 92.png │ ├── 93.png │ ├── 94.png │ ├── 95.png │ ├── 96.png │ ├── 97.png │ ├── 98.png │ └── 99.png └── src ├── Arc.py ├── Arc.pyc ├── CarRecord.py ├── CarRecord.pyc └── MapMatching.py /README.md: -------------------------------------------------------------------------------- 1 | 运行环境python2.7解释器,预装matplotlib包 2 | 3 | 在工程目录下打开命令窗口,输入: 4 | python bin/MapMatching.py data/StarTrek.txt data/StarTrek_gps.dat result/output.txt 5 | 6 | 输出结果就会在result目录的output.txt中,同时会输出道路可视化结果在output.txt所在目录的pic文件夹下 7 | 8 | 其中: 9 | StarTrek_gps.dat的每一条数据是某一辆汽车的一个gps坐标和朝向, 每一行数据中,从左到右分别为:汽车编号, 时间, 经度,维度,速度,方向 10 | StarTrek.txt 用来表示地图信息,每一条数据是地图上一条道路的信息 11 | -------------------------------------------------------------------------------- /result/pic/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/1.png -------------------------------------------------------------------------------- /result/pic/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/10.png -------------------------------------------------------------------------------- /result/pic/100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/100.png -------------------------------------------------------------------------------- /result/pic/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/11.png -------------------------------------------------------------------------------- /result/pic/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/12.png -------------------------------------------------------------------------------- /result/pic/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/13.png -------------------------------------------------------------------------------- /result/pic/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/14.png -------------------------------------------------------------------------------- /result/pic/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/15.png -------------------------------------------------------------------------------- /result/pic/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/16.png -------------------------------------------------------------------------------- /result/pic/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/17.png -------------------------------------------------------------------------------- /result/pic/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/18.png -------------------------------------------------------------------------------- /result/pic/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/19.png -------------------------------------------------------------------------------- /result/pic/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/2.png -------------------------------------------------------------------------------- /result/pic/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/20.png -------------------------------------------------------------------------------- /result/pic/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/21.png -------------------------------------------------------------------------------- /result/pic/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/22.png -------------------------------------------------------------------------------- /result/pic/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/23.png -------------------------------------------------------------------------------- /result/pic/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/24.png -------------------------------------------------------------------------------- /result/pic/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/25.png -------------------------------------------------------------------------------- /result/pic/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/26.png -------------------------------------------------------------------------------- /result/pic/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/27.png -------------------------------------------------------------------------------- /result/pic/28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/28.png -------------------------------------------------------------------------------- /result/pic/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/29.png -------------------------------------------------------------------------------- /result/pic/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/3.png -------------------------------------------------------------------------------- /result/pic/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/30.png -------------------------------------------------------------------------------- /result/pic/31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/31.png -------------------------------------------------------------------------------- /result/pic/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/32.png -------------------------------------------------------------------------------- /result/pic/33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/33.png -------------------------------------------------------------------------------- /result/pic/34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/34.png -------------------------------------------------------------------------------- /result/pic/35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/35.png -------------------------------------------------------------------------------- /result/pic/36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/36.png -------------------------------------------------------------------------------- /result/pic/37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/37.png -------------------------------------------------------------------------------- /result/pic/38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/38.png -------------------------------------------------------------------------------- /result/pic/39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/39.png -------------------------------------------------------------------------------- /result/pic/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/4.png -------------------------------------------------------------------------------- /result/pic/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/40.png -------------------------------------------------------------------------------- /result/pic/41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/41.png -------------------------------------------------------------------------------- /result/pic/42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/42.png -------------------------------------------------------------------------------- /result/pic/43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/43.png -------------------------------------------------------------------------------- /result/pic/44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/44.png -------------------------------------------------------------------------------- /result/pic/45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/45.png -------------------------------------------------------------------------------- /result/pic/46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/46.png -------------------------------------------------------------------------------- /result/pic/47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/47.png -------------------------------------------------------------------------------- /result/pic/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/48.png -------------------------------------------------------------------------------- /result/pic/49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/49.png -------------------------------------------------------------------------------- /result/pic/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/5.png -------------------------------------------------------------------------------- /result/pic/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/50.png -------------------------------------------------------------------------------- /result/pic/51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/51.png -------------------------------------------------------------------------------- /result/pic/52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/52.png -------------------------------------------------------------------------------- /result/pic/53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/53.png -------------------------------------------------------------------------------- /result/pic/54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/54.png -------------------------------------------------------------------------------- /result/pic/55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/55.png -------------------------------------------------------------------------------- /result/pic/56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/56.png -------------------------------------------------------------------------------- /result/pic/57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/57.png -------------------------------------------------------------------------------- /result/pic/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/58.png -------------------------------------------------------------------------------- /result/pic/59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/59.png -------------------------------------------------------------------------------- /result/pic/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/6.png -------------------------------------------------------------------------------- /result/pic/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/60.png -------------------------------------------------------------------------------- /result/pic/61.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/61.png -------------------------------------------------------------------------------- /result/pic/62.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/62.png -------------------------------------------------------------------------------- /result/pic/63.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/63.png -------------------------------------------------------------------------------- /result/pic/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/64.png -------------------------------------------------------------------------------- /result/pic/65.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/65.png -------------------------------------------------------------------------------- /result/pic/66.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/66.png -------------------------------------------------------------------------------- /result/pic/67.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/67.png -------------------------------------------------------------------------------- /result/pic/68.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/68.png -------------------------------------------------------------------------------- /result/pic/69.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/69.png -------------------------------------------------------------------------------- /result/pic/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/7.png -------------------------------------------------------------------------------- /result/pic/70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/70.png -------------------------------------------------------------------------------- /result/pic/71.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/71.png -------------------------------------------------------------------------------- /result/pic/72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/72.png -------------------------------------------------------------------------------- /result/pic/73.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/73.png -------------------------------------------------------------------------------- /result/pic/74.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/74.png -------------------------------------------------------------------------------- /result/pic/75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/75.png -------------------------------------------------------------------------------- /result/pic/76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/76.png -------------------------------------------------------------------------------- /result/pic/77.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/77.png -------------------------------------------------------------------------------- /result/pic/78.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/78.png -------------------------------------------------------------------------------- /result/pic/79.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/79.png -------------------------------------------------------------------------------- /result/pic/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/8.png -------------------------------------------------------------------------------- /result/pic/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/80.png -------------------------------------------------------------------------------- /result/pic/81.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/81.png -------------------------------------------------------------------------------- /result/pic/82.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/82.png -------------------------------------------------------------------------------- /result/pic/83.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/83.png -------------------------------------------------------------------------------- /result/pic/84.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/84.png -------------------------------------------------------------------------------- /result/pic/85.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/85.png -------------------------------------------------------------------------------- /result/pic/86.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/86.png -------------------------------------------------------------------------------- /result/pic/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/87.png -------------------------------------------------------------------------------- /result/pic/88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/88.png -------------------------------------------------------------------------------- /result/pic/89.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/89.png -------------------------------------------------------------------------------- /result/pic/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/9.png -------------------------------------------------------------------------------- /result/pic/90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/90.png -------------------------------------------------------------------------------- /result/pic/91.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/91.png -------------------------------------------------------------------------------- /result/pic/92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/92.png -------------------------------------------------------------------------------- /result/pic/93.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/93.png -------------------------------------------------------------------------------- /result/pic/94.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/94.png -------------------------------------------------------------------------------- /result/pic/95.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/95.png -------------------------------------------------------------------------------- /result/pic/96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/96.png -------------------------------------------------------------------------------- /result/pic/97.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/97.png -------------------------------------------------------------------------------- /result/pic/98.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/98.png -------------------------------------------------------------------------------- /result/pic/99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/result/pic/99.png -------------------------------------------------------------------------------- /src/Arc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | 4 | class Arc: 5 | def __init__(self, argv): 6 | self.id = int(argv[0]) 7 | self.from_node = int(argv[1]) 8 | self.to_node = int(argv[2]) 9 | self.len = float(argv[3]) 10 | self.road_class = int(argv[4]) 11 | self.geometry_list = [[float(ele) for ele in geo.strip().split(':')] for geo in argv[5].strip().split(';')] 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Arc.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/src/Arc.pyc -------------------------------------------------------------------------------- /src/CarRecord.py: -------------------------------------------------------------------------------- 1 | class CarRecord: 2 | def __init__(self, argv): 3 | self.car_id = int(argv[0]) 4 | self.time = argv[1] 5 | self.geo = [float(ele) for ele in argv[2:4]] 6 | self.speed = float(argv[4]) 7 | self.direction = float(argv[5]) -------------------------------------------------------------------------------- /src/CarRecord.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinkcious/MapMatching/715ecba6f76ad7967442f44f1c65d0759ea3f953/src/CarRecord.pyc -------------------------------------------------------------------------------- /src/MapMatching.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | 4 | from CarRecord import * 5 | from Arc import * 6 | from math import * 7 | import Queue 8 | import matplotlib.pyplot as plt 9 | import sys 10 | import time 11 | import os 12 | from datetime import datetime 13 | 14 | def DistanceBetween(geo1, geo2): 15 | return pow(pow(float(geo1[0]) - float(geo2[0]), 2) + pow(float(geo1[1]) - float(geo2[1]), 2), 0.5) 16 | 17 | # 知道三个顶点坐标ABC,看角ACB是否是锐角三角形 18 | def CheckOxygon(A, C, B): 19 | a = DistanceBetween(C, B) 20 | b = DistanceBetween(A, C) 21 | c = DistanceBetween(A, B) 22 | if a**2 + b**2 < c**2: 23 | return False 24 | else: 25 | return True 26 | 27 | def CalDirection(geo_list): 28 | if geo_list[-1][0] == geo_list[0][0]: 29 | if geo_list[-1][1] > geo_list[0][1]: 30 | return float(0) 31 | else: 32 | return float(180) 33 | else: 34 | slope = (geo_list[-1][1] - geo_list[0][1]) / (geo_list[-1][0] - geo_list[0][0]) 35 | if geo_list[-1][0] > geo_list[0][0]: # 如果射线在第1,2象限 36 | return 90 - (atan(slope) / pi * 180) # 由于角度是跟y轴的夹角,所以需要90- 37 | else: # 如果射线在第3,4象限 38 | return 90 - (atan(slope) / pi * 180) + 180 39 | 40 | # 传入geo1, geo2为直线y = kx + d上两点,求geo3在直线上的射影(即作垂直后与直线的交点) 41 | # 如果形成钝角三角形,则垂点取geo1,geo2中靠近geo3的那个 42 | def CalProjection(geo1, geo2, geo3): 43 | geo1 = [float(ele) for ele in geo1] 44 | geo2 = [float(ele) for ele in geo2] 45 | geo3 = [float(ele) for ele in geo3] 46 | a = DistanceBetween(geo2, geo3) 47 | b = DistanceBetween(geo1, geo3) 48 | c = DistanceBetween(geo1, geo2) 49 | if (a**2 + c**2) <= b**2: #钝角三角形,且geo3靠近geo2,包括点在线段延长线上的情况 50 | return geo2 51 | elif b**2 + c**2 <= a**2: #钝角三角形,且geo3靠近geo1,包括点在线段延长线上的情况 52 | return geo1 53 | elif a + b == c: # 说明点在线段上 54 | return geo3 55 | else: 56 | if geo1[0] == geo2[0]: # 如果直线竖直 57 | return [geo1[0], geo3[1]] 58 | elif geo1[1] == geo2[1]: # 如果直线水平 59 | return [geo3[0], geo1[1]] 60 | else: 61 | k = (geo1[1] - geo2[1]) / (geo1[0] - geo2[0]) # y = kx+d中的k 62 | d = geo1[1] - k * geo1[0] # y = kx+d中的d 63 | x4 = (k * geo3[1] - k * d + geo3[0]) / (1 + k**2) 64 | y4 = k * x4 + d 65 | return [x4, y4] 66 | 67 | def CalProjectionOfArc(arc, geo): 68 | length = len(arc.geometry_list) 69 | # 先找一个虚拟点,其为点arc.geometry_list[-2]到arc.geometry_list[-1]连线延长线上延长相等距离的点 70 | virtual_p = [(2 * arc.geometry_list[-1][i] - arc.geometry_list[-2][i]) for i in range(2)] 71 | # 找从哪个i开始,三角形ACB变成钝角,其中点A为car_record.geo,点C为arc.geometry_list[i],点B为virtual_p 72 | i = 0 73 | while i < length - 1 and CheckOxygon(geo, arc.geometry_list[i], virtual_p): 74 | i += 1 75 | # 如果最小的i为0或者len() - 1,则取最靠近目标点的两个点计算垂点 76 | # 即使出现钝角三角形的情况,calProjection函数中会处理 77 | if i == 0: 78 | projection = CalProjection(arc.geometry_list[i], arc.geometry_list[i + 1], geo) 79 | else: # 如果垂点在线段上 80 | projection = CalProjection(arc.geometry_list[i - 1], arc.geometry_list[i], geo) 81 | return projection 82 | 83 | # 传入geo1, geo2为直线y = kx + d上两点,求geo3到直线的距离 84 | # 如果形成钝角三角形,则垂点取geo1,geo2中靠近geo3的那个点与geo3的距离 85 | def CalDistance(geo1, geo2, geo3): 86 | geo1 = [float(ele) for ele in geo1] 87 | geo2 = [float(ele) for ele in geo2] 88 | geo3 = [float(ele) for ele in geo3] 89 | a = DistanceBetween(geo2, geo3) 90 | b = DistanceBetween(geo1, geo3) 91 | c = DistanceBetween(geo1, geo2) 92 | if (a ** 2 + c ** 2) <= b ** 2: # 钝角三角形,且geo3靠近geo2,包括点在线段延长线上的情况 93 | return DistanceBetween(geo2, geo3) * 5 # *5是geo点跑到外面去的panelty 94 | elif b ** 2 + c ** 2 <= a ** 2: # 钝角三角形,且geo3靠近geo1,包括点在线段延长线上的情况 95 | return DistanceBetween(geo1, geo3) * 5 96 | elif a + b == c: # 说明点在线段上 97 | return 0 98 | else: 99 | if geo1[0] == geo2[0]: # 如果直线竖直 100 | return abs(geo3[0] - geo1[0]) 101 | elif geo1[1] == geo2[1]: # 如果直线水平 102 | return abs(geo3[1] - geo1[1]) 103 | else: 104 | k = (geo1[1] - geo2[1]) / (geo1[0] - geo2[0]) # y = kx+d中的k 105 | d = geo1[1] - k * geo1[0] # y = kx+d中的d 106 | dist = abs(k * geo3[0] + d - geo3[1]) / sqrt(1 + k**2) # 点到直线距离公式 107 | return dist 108 | 109 | # 如果汽车定位数据跟道路的相差很远或者方向不对,则没有必要取该条arc 110 | def CheckNecessary(arc, car_record): 111 | # 如果edgh方向和汽车的方向不同,则认为车不在该道路上 112 | if car_record.speed > 3 * 3.6: 113 | direction_road = CalDirection(arc.geometry_list) 114 | diff_angle = abs(car_record.direction - direction_road) 115 | if diff_angle > 180: 116 | diff_angle = 360 - diff_angle 117 | if diff_angle > 90: # 如果道路方向和汽车方向不同 118 | return False 119 | 120 | # 我计算了该地图中最长的路是3494m,取大一点10000,防止出现漏判的情况,因为下面这个if是只取道路坐标的第一个点来跟目标点计算距离 121 | if DistanceActual(arc.geometry_list[0], car_record.geo) > 10000: 122 | return False 123 | 124 | # 下面if是计算这条道路上所有gps点跟目标点的最短距离小于100m才返回True。我们认为汽车gps精度为60m,放宽到100m 125 | min_dist = float("inf") 126 | for geo1 in arc.geometry_list: 127 | tmp = DistanceActual(geo1, car_record.geo) 128 | if tmp < min_dist: 129 | min_dist = tmp 130 | if min_dist < 300: 131 | return True 132 | else: 133 | return False 134 | 135 | def CalCost(arc, car_record): 136 | cost = float("inf") 137 | if CheckNecessary(arc, car_record): 138 | length = len(arc.geometry_list) 139 | # 先找一个虚拟点,其为点arc.geometry_list[-2]到arc.geometry_list[-1]连线延长线上延长相等距离的点 140 | virtual_p = [(2 * arc.geometry_list[-1][i] - arc.geometry_list[-2][i]) for i in range(2)] 141 | # 找从哪个i开始,三角形ACB变成钝角,其中点A为car_record.geo,点C为arc.geometry_list[i],点B为virtual_p 142 | i = 0 143 | while i < length - 1 and CheckOxygon(car_record.geo, arc.geometry_list[i], virtual_p): 144 | i += 1 145 | # 如果最小的i为0或者len() - 1,则取最靠近目标点的两个点计算垂点 146 | # 即使出现钝角三角形的情况,calProjection函数中会处理 147 | if i == 0: 148 | dist = CalDistance(arc.geometry_list[i], arc.geometry_list[i + 1], car_record.geo) 149 | direction_road = CalDirection(arc.geometry_list[0:2]) 150 | else: # 如果垂点在线段上 151 | dist = CalDistance(arc.geometry_list[i - 1], arc.geometry_list[i], car_record.geo) 152 | direction_road = CalDirection(arc.geometry_list[i - 1: i + 1]) 153 | diff_angle = abs(car_record.direction - direction_road) 154 | if diff_angle > 180: 155 | diff_angle = 360 - diff_angle 156 | if car_record.speed < 1 * 3.6: #如果车速小于1,方向所占比重为0 157 | angle_ratio = 0 158 | elif car_record.speed < 10 * 3.6: #如果车速在1m/s到10m/s之间,随着车速增加,方向所占比重逐渐增加到0.54 159 | angle_ratio = (car_record.speed / 3.6 - 1) * 0.06 160 | else: #如果速度大于10m/s,方向所占比重保持0.54不变 161 | angle_ratio = 0.54 162 | cost = (dist / 0.00046 * 39.3) * (1 - angle_ratio) + (1.5 * diff_angle) * angle_ratio 163 | return cost 164 | 165 | # 给定car_geo和car_direction,根据最短距离和方向,计算在所有道路的Cost,返回Cost最小的道路id 166 | def CalMinCostArcID(car_record): 167 | min_cost = float("inf") 168 | id = 0 169 | for arc in arc_objects: 170 | cost = CalCost(arc, car_record) 171 | if cost < min_cost: 172 | min_cost = cost 173 | id = arc.id 174 | return id 175 | 176 | #t1 - t2 yyyyMMddHHmmss 177 | def SecondsBetween(t1, t2): 178 | if int(t1) > int(t2): 179 | big = t1 180 | small = t2 181 | else: 182 | big = t2 183 | small = t1 184 | big = time.strptime(big, "%Y%m%d%H%M%S") 185 | small = time.strptime(small, "%Y%m%d%H%M%S") 186 | big = datetime(big[0], big[1], big[2], big[3], big[4], big[5]) 187 | small = datetime(small[0], small[1], small[2], small[3], small[4], small[5]) 188 | return (big - small).seconds 189 | 190 | # 从提供的道路数据的第1条可以知道经纬度的0.00046对应实际距离39.3m 191 | def DistanceActual(geo1, geo2): 192 | dist = DistanceBetween(geo1, geo2) 193 | return dist * 9.745339101028061e4 194 | 195 | # 把单行线用红蓝画出 196 | def PlotMapRoad(arc_objects): 197 | record = {} 198 | for arc in arc_objects: 199 | ploted = False 200 | if record.has_key(arc.to_node): 201 | for ele in record[arc.to_node]: 202 | if ele == arc.from_node: 203 | ploted = True 204 | nodeX = [geo[0] for geo in arc.geometry_list] 205 | nodeY = [geo[1] for geo in arc.geometry_list] 206 | if ploted == True: 207 | plt.plot(nodeX, nodeY, color='r', marker='.', alpha=0.3) 208 | plt.text(nodeX[0], nodeY[0], arc.id, alpha=0.3) 209 | else: 210 | plt.plot(nodeX, nodeY, color='#7f7f7f', marker='.', alpha=0.3) 211 | plt.text(nodeX[0], nodeY[0], arc.id, alpha=0.3) 212 | 213 | if record.has_key(arc.from_node): 214 | record[arc.from_node].append(arc.to_node) 215 | else: 216 | record[arc.from_node] = [arc.to_node] 217 | 218 | # 输入arc_cover是arc_id和cover的列表,该函数输出这个arc_cover包含的道路总长 219 | def CalLenCover(arc_cover): 220 | travel_distance = 0 221 | for k in range(len(arc_cover)): 222 | travel_distance += arc_objects[arc_cover[k][0] - 1].len * arc_cover[k][1] 223 | return round(travel_distance,1) 224 | 225 | # 输入arc_list是arc_id的列表,该函数输出这个arc_list包含的道路总长 226 | def CalLen(arc_list): 227 | travel_distance = 0 228 | for k in range(len(arc_list)): 229 | travel_distance += arc_objects[arc_list[k] - 1].len 230 | return round(travel_distance,1) 231 | 232 | def findMinDist(dist, collected): 233 | min_dist = float("inf") 234 | min_key = -1 235 | for key in dist: 236 | if dist[key] < min_dist and (not collected.has_key(key)): 237 | min_dist = dist[key] 238 | min_key = key 239 | return min_key 240 | 241 | # 用单源最短路径算法,求两条边的最短距离的arc_list 242 | def dijkstra(graph, start_arc_id, end_arc_id): 243 | if start_arc_id == end_arc_id: 244 | return [start_arc_id] 245 | dist = {} 246 | path = {} 247 | collected = {} 248 | for key in graph: 249 | dist[key] = float("inf") 250 | for arc in graph[key]: 251 | if not dist.has_key(arc.to_node): 252 | dist[arc.to_node] = float("inf") 253 | from_node = arc_objects[start_arc_id - 1].to_node 254 | to_node = arc_objects[end_arc_id - 1].from_node 255 | if graph.has_key(from_node): 256 | for arc in graph[from_node]: 257 | dist[arc.to_node] = arc.len 258 | path[arc.to_node] = from_node 259 | dist[from_node] = 0 260 | collected[from_node] = True 261 | while True: 262 | node = findMinDist(dist, collected) 263 | if node == -1: 264 | break 265 | collected[node] = True 266 | if graph.has_key(node): 267 | for arc in graph[node]: 268 | if not collected.has_key(arc.to_node): 269 | if dist[arc.to_node] > dist[node] + arc.len: 270 | dist[arc.to_node] = dist[node] + arc.len 271 | path[arc.to_node] = node 272 | arc_list = [end_arc_id] 273 | while path.has_key(to_node): 274 | for arc in graph[path[to_node]]: 275 | if arc.to_node == to_node: 276 | arc_list.append(arc.id) 277 | to_node = path[to_node] 278 | arc_list.append(start_arc_id) 279 | arc_list = arc_list[::-1] 280 | return arc_list 281 | 282 | def BFSFindPathArc(arc, car_record, dist): 283 | min_cost = 60 284 | arc_list = [] 285 | min_arc_id = 0 286 | visited = {} 287 | graph_around = {} 288 | q = Queue.Queue() 289 | q.put(arc) 290 | visited[arc.id] = True 291 | while not q.empty(): 292 | arc1 = q.get() 293 | # 生成arc附近连通的道路的图,后面用来找最短路径 294 | if graph_around.has_key(arc1.from_node): 295 | graph_around[arc1.from_node].append(arc1) 296 | else: 297 | graph_around[arc1.from_node] = [arc1] 298 | cost = CalCost(arc1, car_record) 299 | if cost < min_cost: 300 | min_cost = cost 301 | min_arc_id = arc1.id 302 | if map_graph.has_key(arc1.to_node): 303 | for arc2 in map_graph[arc1.to_node]: 304 | if not visited.has_key(arc2.id): 305 | if DistanceBetween(arc.geometry_list[-1], arc2.geometry_list[0]) < dist: 306 | q.put(arc2) 307 | visited[arc2.id] = True 308 | if min_arc_id != 0: 309 | arc_list = dijkstra(graph_around, arc.id, min_arc_id) 310 | return arc_list 311 | 312 | # 计算点geo在arc上面的cover, flag="forward"时计算geo点垂点向前占arc的比例,flag="backward"时相反 313 | def CalCover(arc, geo, flag): 314 | length = len(arc.geometry_list) 315 | virtual_p = [(2 * arc.geometry_list[-1][i] - arc.geometry_list[-2][i]) for i in range(2)] 316 | # 找从哪个i开始,三角形ACB变成钝角,其中点A为car_record.geo,点C为arc.geometry_list[i],点B为virtual_p 317 | i = 0 318 | while i < length - 1 and CheckOxygon(geo, arc.geometry_list[i], virtual_p): 319 | i += 1 320 | # 如果最小的i为0或者len() - 1,则取最靠近目标点的两个点计算垂点 321 | # 即使出现钝角三角形的情况,calProjection函数中会处理 322 | if i == 0: 323 | projection = CalProjection(arc.geometry_list[i], arc.geometry_list[i + 1], geo) 324 | else: # 如果垂点在线段上 325 | projection = CalProjection(arc.geometry_list[i - 1], arc.geometry_list[i], geo) 326 | cover = 0 327 | if flag == "forward": 328 | cover = round(DistanceBetween(projection, arc.geometry_list[-1]) \ 329 | / DistanceBetween(arc.geometry_list[0], arc.geometry_list[-1]), 2) 330 | elif flag == "backward": 331 | cover = round(DistanceBetween(projection, arc.geometry_list[0]) \ 332 | / DistanceBetween(arc.geometry_list[0], arc.geometry_list[-1]), 2) 333 | return cover 334 | 335 | def CarRecordsDivide(car_i): 336 | index_start = sum(car_id_count[:car_i]) 337 | index_end = sum(car_id_count[:car_i+1]) 338 | if index_end - index_start == 1: 339 | car_i_start_end_index_list = [[index_start, index_end]] 340 | car_i_start_end_index_list = [] 341 | index_j_start = index_start 342 | for i in range(index_start + 1, index_end): 343 | if SecondsBetween(car_record_objects[i - 1].time, car_record_objects[i].time) > 15*60: 344 | car_i_start_end_index_list.append([index_j_start, i]) 345 | index_j_start = i 346 | car_i_start_end_index_list.append([index_j_start, index_end]) 347 | return car_i_start_end_index_list 348 | 349 | def main(): 350 | for car_i in range(0, car_num): 351 | print "Calculating car track of " + str(car_i + 1) + ", total " + str(car_num) 352 | output_file = open(result_file_name, 'a') 353 | # debug 可视化 354 | if PLOT == True: 355 | fig = plt.figure(car_i + 1) 356 | # 如果,前后两个定位点的时间超过15分钟,则认为前后可以分为两段轨迹,即不计算这两个定位点之间经过的道路 357 | car_i_start_end_index_list = CarRecordsDivide(car_i) 358 | for car_j in range(len(car_i_start_end_index_list)): 359 | car_ij_start_index = car_i_start_end_index_list[car_j][0] # 第i量车的第j段数据的第一个定位数据 360 | car_ij_end_index = car_i_start_end_index_list[car_j][1] # 第i量车的j段数据的第最后一个定位数据,不包括该条记录 361 | 362 | # arc_path存储着car_ij_start_index到car_ij_end_index之间经过的道路列表 363 | arc_path = [] 364 | # 因为刚起步的时候汽车的方向不可信,所以取10米内的几个点的平均方向和坐标 365 | j = car_ij_start_index 366 | while j < car_ij_end_index: 367 | if DistanceActual(car_record_objects[j].geo, car_record_objects[car_ij_start_index].geo) > 10: 368 | break 369 | j += 1 370 | car_record_list = car_record_objects[car_ij_start_index : j] 371 | car_geo_list = [car_record.geo for car_record in car_record_list] 372 | car_x = sum([geo[0] for geo in car_geo_list]) / len(car_geo_list) 373 | car_y = sum([geo[1] for geo in car_geo_list]) / len(car_geo_list) 374 | if len(car_geo_list) == 1: 375 | car_direction = car_record_list[0].direction 376 | else: 377 | car_direction = CalDirection(car_geo_list) 378 | car_record = CarRecord([0,0, car_x, car_y, 3*3.6+1, car_direction]) 379 | arc_path.append(CalMinCostArcID(car_record)) 380 | #算剩下的,基于前面算的结果,从跟前面道路相连通的道路里面找属于哪条道路 381 | while j < car_ij_end_index: 382 | car_record = car_record_objects[j] 383 | arc_list = BFSFindPathArc(arc_objects[arc_path[-1] - 1], car_record, DistanceBetween(car_record.geo, arc_objects[arc_path[-1] - 1].geometry_list[-1])) 384 | if len(arc_list) != 0: 385 | arc_list.pop(0) 386 | if len(arc_list) != 0: 387 | arc_path = arc_path + arc_list 388 | else: 389 | if len(arc_path) > 1: 390 | arc_list = BFSFindPathArc(arc_objects[arc_path[-2] - 1], car_record, DistanceBetween(car_record.geo, arc_objects[arc_path[-2] - 1].geometry_list[-1])) 391 | if len(arc_list) != 0: 392 | arc_list.pop(0) 393 | if len(arc_list) != 0: 394 | arc_path.pop(-1) 395 | arc_path = arc_path + arc_list 396 | else: 397 | arc_id = CalMinCostArcID(car_record) 398 | if arc_id != 0 and arc_id != arc_path[-1]: 399 | arc_path.append(arc_id) 400 | else: 401 | arc_id = CalMinCostArcID(car_record) 402 | if arc_id != 0 and arc_id != arc_path[-1]: 403 | arc_path.append(arc_id) 404 | j += 1 405 | 406 | # debug 可视化 407 | if PLOT == True: 408 | for arc_id in arc_path: # 画汽车经过的道路 409 | nodex = [ele[0] for ele in arc_objects[arc_id - 1].geometry_list] 410 | nodey = [ele[1] for ele in arc_objects[arc_id - 1].geometry_list] 411 | plt.plot(nodex, nodey, color='#7f7f7f', marker='.', alpha=0.5) 412 | plt.text((nodex[0] + nodex[1])/2, (nodey[0] + nodey[1])/2, arc_id, color='r', alpha=0.3) 413 | for j in range(car_ij_start_index, car_ij_end_index): # 画汽车gps坐标点 414 | plt.scatter(car_record_objects[j].geo[0], car_record_objects[j].geo[1], marker='.', color='b', s=40, alpha=0.3) 415 | 416 | ## 下面这段代码计算car_ij_start_index到car_ij_end_index当中的每小段路经过了arc_path中的哪些arc 417 | if len(arc_path) == 1: 418 | projection_before = CalProjectionOfArc(arc_objects[arc_path[0] - 1], car_record_objects[car_ij_start_index].geo) 419 | for j in range(car_ij_start_index+1, car_ij_end_index): 420 | # 去除重复GPS点 421 | if car_record_objects[j].time == car_record_objects[j - 1].time: 422 | continue 423 | projection_now = CalProjectionOfArc(arc_objects[arc_path[0] - 1], car_record_objects[j].geo) 424 | arc_cover = [[arc_path[0], round(DistanceActual(projection_before, projection_now) / arc_objects[arc_path[0] - 1].len, 4)]] 425 | projection_before = projection_now # 更新projection_before的值 426 | # 把arc_cover转换成要求格式,以便于输出 427 | geo_output = [] 428 | for ele in arc_cover: 429 | geo_output.append(':'.join([str(e) for e in ele])) 430 | geo_output = '|'.join(geo_output) 431 | # 输出 432 | output_line = [str(car_i + 1), car_record_objects[j - 1].time, car_record_objects[j].time, str(CalLenCover(arc_cover)), \ 433 | str(SecondsBetween(car_record_objects[j - 1].time,car_record_objects[j].time)), geo_output] 434 | output_file.write(",".join(output_line) + "\n") 435 | else: 436 | # arc_path_i_before代表前一个arc在arc_path中的索引 437 | arc_path_i_before = 0 438 | for j in range(car_ij_start_index+1, car_ij_end_index): 439 | # 去除重复GPS点 440 | if car_record_objects[j].time == car_record_objects[j - 1].time: 441 | continue 442 | # dist 下一个定位点与上一个定位点之间的距离 443 | dist = DistanceBetween(car_record_objects[j].geo, arc_objects[arc_path[arc_path_i_before] - 1].geometry_list[-1]) 444 | # arc_path_i_reachable表示与arc_path_i_before的距离小于dist的arc_path的索引 445 | arc_path_i_reachable = arc_path_i_before + 1 446 | while arc_path_i_reachable < len(arc_path): 447 | if DistanceBetween(arc_objects[arc_path[arc_path_i_reachable] - 1].geometry_list[0], arc_objects[arc_path[arc_path_i_before] - 1].geometry_list[-1]) < dist: 448 | arc_path_i_reachable += 1 449 | else: 450 | break 451 | # 这样arc_path中arc_path_i_before到arc_path_i_reachable之间的arc就是j可能属于的arc 452 | # 下面这段代码找arc_path_i_before到arc_path_i_reachable之间,j到底属于哪一条arc 453 | min_cost = float('inf') 454 | min_arc_path_i = arc_path_i_before 455 | for arc_path_i in range(arc_path_i_before, arc_path_i_reachable): 456 | cost = CalCost(arc_objects[arc_path[arc_path_i] - 1], car_record_objects[j]) 457 | if cost < min_cost: 458 | min_cost = cost 459 | min_arc_path_i = arc_path_i 460 | # 找到min_arc_path_i是j属于的arc_path中的arc的索引 461 | arc_path_output = arc_path[arc_path_i_before:min_arc_path_i+1] # 从j-1到j经过的arc列表 462 | arc_path_output_cover = [[arc_id, 1.0] for arc_id in arc_path_output] # 从j-1到j经过的arc列表,带cover 463 | # 计算首尾的cover 464 | if len(arc_path_output_cover) == 1: 465 | projection1 = CalProjectionOfArc(arc_objects[arc_path_output_cover[0][0] - 1], car_record_objects[j].geo) 466 | projection2 = CalProjectionOfArc(arc_objects[arc_path_output_cover[0][0] - 1], car_record_objects[j - 1].geo) 467 | arc_path_output_cover[0][1] = round(DistanceActual(projection1, projection2) / arc_objects[arc_path_output_cover[0][0] - 1].len, 4) 468 | else: 469 | projection1 = CalProjectionOfArc(arc_objects[arc_path_output_cover[0][0] - 1], car_record_objects[j - 1].geo) 470 | projection2 = CalProjectionOfArc(arc_objects[arc_path_output_cover[-1][0] - 1], car_record_objects[j].geo) 471 | arc_path_output_cover[0][1] = round(DistanceActual(projection1, arc_objects[arc_path_output_cover[0][0] - 1].geometry_list[-1]) \ 472 | / arc_objects[arc_path_output_cover[0][0] - 1].len, 4) 473 | arc_path_output_cover[-1][1] = round(DistanceActual(projection2, arc_objects[arc_path_output_cover[-1][0] - 1].geometry_list[0]) \ 474 | / arc_objects[arc_path_output_cover[-1][0] - 1].len, 4) 475 | # geo_output为处理arc_path_output_cover的数据,以便于输出 476 | geo_output = [] 477 | for ele in arc_path_output_cover: 478 | geo_output.append(':'.join([str(e) for e in ele])) 479 | geo_output = ';'.join(geo_output) 480 | # 输出 481 | output_line = [str(car_i + 1), car_record_objects[j - 1].time, car_record_objects[j].time,str(CalLenCover(arc_path_output_cover)), \ 482 | str(SecondsBetween(car_record_objects[j - 1].time, car_record_objects[j].time)), geo_output] 483 | output_file.write(",".join(output_line) + "\n") 484 | # 更新arc_path_i_before的值 485 | arc_path_i_before = min_arc_path_i 486 | output_file.close() 487 | # debug 可视化图保存 488 | if PLOT == True: 489 | slash_index = result_file_name.rfind('/') 490 | if slash_index != -1: 491 | pic_dir = result_file_name[0:slash_index] + '/pic/' 492 | else: 493 | pic_dir = 'pic/' 494 | if not os.path.exists(pic_dir): 495 | os.mkdir(pic_dir) 496 | ax = plt.gca() 497 | ax.set_aspect(1) 498 | fig.savefig(pic_dir + str(car_i + 1)) 499 | fig.clf() 500 | plt.close() 501 | 502 | return 503 | 504 | 505 | if len(sys.argv) != 4: 506 | print '输入参数数目不对' 507 | exit() 508 | 509 | map_file = open(sys.argv[1]) 510 | map_lines = map_file.readlines() 511 | map_lines.pop(0) # 删除第一行,为说明,非数据 512 | # arc_objects存储着所有边的Arc对象实例,改成Arc不用Edgh命名是因为,Arc是有向边,Edgh是无向边 513 | # 注意此处arc_objects列表中元素Arc的id比对应index大1,因为Arc的id从1开始,list的index从0开始 514 | arc_objects = [Arc(argv.strip().split(',')) for argv in map_lines] 515 | 516 | car_file = open(sys.argv[2]) 517 | car_lines_str = car_file.readlines() 518 | # car_record_objects存储着汽车的每一条gps定位数据 519 | car_record_objects = [CarRecord(line_str.strip().split(',')) for line_str in car_lines_str] 520 | # car_id_count存储着从1到100每一辆车的gps定位数量 521 | car_id = [car_record.car_id for car_record in car_record_objects] 522 | car_num = max(car_id) 523 | car_id_count = [car_id.count(i + 1) for i in range(car_num)] # 100辆车 524 | 525 | # 生成图的邻接表数据结构 526 | map_graph = {} 527 | for arc in arc_objects: 528 | if map_graph.has_key(arc.from_node): 529 | map_graph[arc_objects[arc.id - 1].from_node].append(arc) 530 | else: 531 | map_graph[arc_objects[arc.id - 1].from_node] = [arc] 532 | 533 | # 输出文件名字 534 | result_file_name = sys.argv[3] 535 | if os.path.exists(result_file_name): 536 | os.remove(result_file_name) 537 | 538 | # 是否画图 539 | PLOT = False 540 | 541 | if __name__ == '__main__': 542 | start = time.clock() 543 | main() 544 | end = time.clock() 545 | print "Spent " + str(int(end - start)) + " seconds" --------------------------------------------------------------------------------