-
Notifications
You must be signed in to change notification settings - Fork 0
/
alignments.py
241 lines (204 loc) · 7.07 KB
/
alignments.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# coding: utf8
#!/usr/bin/env python
from scipy import spatial
import math
from math import pi
import os
import difflib
from geopy.distance import geodesic
import threading
##########################
angle_max = 6 # In degrees
points_aligned = 15
# Set limitation
lookup_nearest = 70
# Set max distance between portal to origin
max_dist = True # either True or False
max_dist_val = 5 # In km
# Set on True to limit the range
limit = True
limit_range = 10
limit_origin = (48.6,2.1)
##########################
def export_ref():
actions = ["deployed", "captured", "hacked", "created", "destroyed"]
geo = {}
with open("game_log.tsv", encoding="utf8") as logs:
for line in logs:
for action in actions:
if action in line:
line_a = line.split("\t")
geo[line_a[1]] = line_a[1]+","+line_a[2]
with open("coos.geo", "w") as f:
for coo in geo.values():
f.write(coo+"\n")
def merge_geo():
geo = []
i = 1
while os.path.exists("coos"+str(i)+".geo"):
i += 1
for k in range(i):
str_i = str(i) if i != 0 else ""
with open(f"coos{str_i}.geo", encoding="utf8") as f:
for line in f:
line_a = line.split(",")
if line_a[0] == "None":
continue
line_a = (float(line_a[0]), float(line_a[1]))
if line_a in geo:
continue
geo.append(line_a)
with open("coos.geo", "w") as f:
for coo in geo.values():
f.write(coo+"\n")
def dotproduct(v1, v2):
return sum((a*b) for a, b in zip(v1, v2))
def length(v):
return math.sqrt(dotproduct(v, v))
def angle_sub(v1, v2):
try:
return math.acos(dotproduct(v1, v2) / (length(v1) * length(v2)))
except ValueError:
return 2
def angle(v1, v2):
return angle_sub(v1, v2)*180/pi
def angle_in(origin, ref, point):
v1 = (ref[0] - origin[0], ref[1] - origin[1])
v2 = (point[0] - origin[0], point[1] - origin[1])
return angle(v1, v2)
def get_geo():
geo = []
with open("coos.geo", encoding="utf8") as f:
for line in f:
line_a = line.split(",")
if line_a[0] == "None":
continue
line_a = (float(line_a[0]), float(line_a[1]))
geo.append(line_a)
return geo
def progress_calc(i):
#Progress calculation
progress = float(i) / progress_calc.progress_max * 100
if progress > progress_calc.progress_last + 5:
progress_calc.progress_last = progress
print(str(int(progress)) +"% done")
best_alignments = []
lock = threading.Lock()
def manage_aligned(best_alignments, aligned):
global lock
aligned_nb = len(aligned)
if aligned_nb <= points_aligned:
return best_alignments
for x in best_alignments:
for y in x:
if difflib.SequenceMatcher(None, y, aligned).ratio() > 0.9:
return best_alignments
lock.acquire()
while len(best_alignments) < aligned_nb + 1:
best_alignments.append([])
best_alignments[aligned_nb].append(aligned)
lock.release()
print("Found "+str(aligned_nb)+"!")
return best_alignments
class compute(threading.Thread):
def __init__(self, tree, geo, j):
threading.Thread.__init__(self)
self.state = 0
self.tree = tree
self.geo = geo
self.j = j
def run(self):
self.state = 1
lock.acquire()
self.points = [self.geo[index] for index in self.tree.query([self.origin], lookup_nearest)[1][0][1:]]
lock.release()
self.is_cluster_aligned()
self.state = 2
def set_params(self, origin, j):
self.origin = origin
self.state = 0
self.j = j
def is_cluster_aligned(self):
global best_alignments
points = self.points
origin = self.origin
#For each nearest points, set one as the reference point
for ref in points:
aligned = [origin, ref]
v1 = (ref[0] - origin[0], ref[1] - origin[1])
#For each remaining nearest points
for point in points:
if point == ref:
continue
v2 = (point[0] - origin[0], point[1] - origin[1])
#If the angle (ref, origin, point) and
#(previous, previous-1, point) are low enough -> aligned
if angle(v1, v2) < angle_max and angle_in(aligned[-2], aligned[-1], point) < angle_max:
if not max_dist or geodesic(point, origin).km < max_dist_val:
aligned.append(point)
#If there are enough aligned points
best_alignments = manage_aligned(best_alignments, aligned)
def get_best_alignments(geo):
tree = spatial.KDTree(geo)
global best_alignments
try:
progress_calc.progress_last = 0
nb_points = len(geo)
progress_calc.progress_max = float(nb_points)
nb_threads = (os.cpu_count() + 1)
threads = [compute(tree, geo, 0)] * nb_threads
j = 0
for i in range(nb_points): # For each point
progress_calc(i)
origin = geo[i]
if limit:
if geodesic(limit_origin, origin).km > limit_range:
continue
#nearest = tree.query([origin], lookup_nearest)
#points = [geo[index] for index in tree.query([origin], lookup_nearest)[1][0][1:]]
done = False
while not done:
done = True
if j == 0 and threads[j].is_alive():
threads[j].join()
threads[j].set_params(origin, j)
threads[j].run()
elif not threads[j].is_alive():
threads[j].set_params(origin, j)
threads[j].run()
else:
done = False
j += 1
j = j % nb_threads
#best_alignments = is_cluster_aligned(best_alignments, points, origin)
except KeyboardInterrupt:
pass
try:
for thread in threads:
thread.join()
except:
pass
return best_alignments
def print_best_alignments(best_alignments):
if not best_alignments:
return
for x in range(len(best_alignments)):
if len(best_alignments[x]) > 0:
print(str(x)+" aligned -> " + str(len(best_alignments[x])) + " found !")
for x in range(len(best_alignments)):
aligned_n = best_alignments[x]
for aligned in aligned_n:
#print("")
# print in a format readable by http://www.hamstermap.com/quickmap.php
for point in aligned:
print(str(point[0])+","+str(point[1]))
def main():
if not os.path.exists("coos.geo"):
print("Parsing game_log.tsv")
export_ref()
if os.path.exists("coos1.geo"):
merge_geo()
print("looking for alignments")
print_best_alignments(get_best_alignments(get_geo()))
if __name__ == "__main__":
main()