-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathutil.py
251 lines (185 loc) · 8.51 KB
/
util.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
242
243
244
245
246
247
248
249
import math
import random
import string
import threading
import socket
import time
from shapely.geometry import Point
from shapely.geometry.polygon import Polygon
from Constants import OTHER_CONTROLLERS, INACTIVE_SECTORS, PORT, FLEET, AIRPORTS
from PlaneMode import PlaneMode
from sfparser import loadSectorData, sfCoordsToNormalCoords
def haversine(lat1, lon1, lat2, lon2): # from https://rosettacode.org/wiki/Haversine_formula#Python
R = 6372.8 # Earth radius in kilometers
dLat = math.radians(lat2 - lat1)
dLon = math.radians(lon2 - lon1)
lat1 = math.radians(lat1)
lat2 = math.radians(lat2)
a = math.sin(dLat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dLon / 2)**2
c = 2 * math.asin(math.sqrt(a))
return R * c
def haversineNM(lat1, lon1, lat2, lon2):
return haversine(lat1, lon1, lat2, lon2) / 1.852
def callsignGen(dest,planes,attempts=5):
"""
Returns a random callsign in the FORM ICAO NUMBER NUMBER LETTER LETTER
and a random aircraft type as defined in Constants.py
"""
for _ in range(attempts):
callsign = ""
if dest in AIRPORTS.keys():
callsign += random.choice(AIRPORTS[dest])
else:
callsign += random.choice(list(FLEET.keys()))
ac_type = random.choice(FLEET[callsign])
callsign += random.choice(string.digits[1:])
callsign += random.choice(string.digits) if random.random() < 0.8 else ""
callsign += random.choice(string.ascii_uppercase) if random.random() < 0.5 else ""
callsign += random.choice(string.ascii_uppercase) if random.random() < 0.5 else ""
if callsign not in planes:
return callsign, ac_type
return callsign, ac_type # you got VERY unlucky lolz(1 in a very big number)
def squawkGen():
from Constants import CCAMS_SQUAWKS
from globalVars import allocatedSquawks
squawk = random.choice(CCAMS_SQUAWKS)
while squawk in allocatedSquawks:
squawk = random.choice(CCAMS_SQUAWKS)
allocatedSquawks.append(squawk)
return squawk
def lerpBetweenCoords(start: tuple[float, float], end: tuple[float, float], t: float):
return (start[0] + t * (end[0] - start[0]), start[1] + t * (end[1] - start[1]))
def headingFromTo(fromCoord: tuple[float, float], toCoord: tuple[float, float]) -> int:
return (math.degrees(math.atan2(toCoord[1] - fromCoord[1], (1 / math.cos(math.radians(fromCoord[0]))) * (toCoord[0] - fromCoord[0]))) + 360) % 360
def deltaLatLonCalc(lat: float, tas: float, heading: float, deltaT: float) -> tuple[float, float]:
return ((tas * math.cos(math.radians(heading)) * (deltaT / 3600)) / 60, (1 / math.cos(math.radians(lat))) * (tas * math.sin(math.radians(heading)) * (deltaT / 3600)) / 60)
def modeConverter(mode: PlaneMode) -> str:
match mode:
case PlaneMode.GROUND_STATIONARY:
return "Stationary"
case PlaneMode.GROUND_READY:
return "Ready"
case PlaneMode.GROUND_TAXI:
return "Taxiing"
case PlaneMode.FLIGHTPLAN:
return "Flightplan"
case PlaneMode.HEADING:
return "Heading"
case PlaneMode.ILS:
return "ILS"
case PlaneMode.NONE:
return "Error"
case _:
return str(mode)
def whichSector(lat: float, lon: float, alt: int) -> str:
sectorData = loadSectorData()
pos = Point(lat, lon)
possibilities = []
sectorOut = None
for sectorName, sector in sectorData.items():
polygon = Polygon(sector)
if polygon.contains(pos):
if sectorName in INACTIVE_SECTORS:
continue
possibilities.append(sectorName)
if ("LTC" in sectorName or "STC" in sectorName or "MAN" in sectorName) and alt < 19500: # TODO: WTF!
sectorOut = sectorName
break
elif "LON" in sectorName:
sectorOut = sectorName
if sectorOut is None:
if len(possibilities) >= 1:
sectorOut = possibilities[0] # TODO: :(
return sectorOut
def pbd(lat: float, lon: float, bearing: int, dist: int):
lat_rad = math.radians(lat)
lon_rad = math.radians(lon)
bearing_rad = math.radians(bearing)
R = 3440.065
dest_lat_rad = math.asin(math.sin(lat_rad) * math.cos(dist / R) +
math.cos(lat_rad) * math.sin(dist / R) * math.cos(bearing_rad))
dest_lon_rad = lon_rad + math.atan2(math.sin(bearing_rad) * math.sin(dist / R) * math.cos(lat_rad),
math.cos(dist / R) - math.sin(lat_rad) * math.sin(dest_lat_rad))
dest_lat = math.degrees(dest_lat_rad)
dest_lon = math.degrees(dest_lon_rad)
return dest_lat, dest_lon
def otherControllerIndex(callsign: str) -> int:
for i, controller in enumerate(OTHER_CONTROLLERS):
if controller[0] == callsign:
return i
class EsSocket(socket.socket):
def esSend(self, *args):
output = b':'.join([str(arg).encode("UTF-8") for arg in args]) + b'\r\n'
self.sendall(output)
class ControllerSocket(EsSocket):
@staticmethod
def StartController(callsign: str) -> 'ControllerSocket':
s = ControllerSocket()
s.connect(("127.0.0.1", PORT))
# Login controller:
s.esSend("#AA" + callsign, "SERVER", "Alice Ford", "1646235", "pass", "7", "9", "1", "0", "51.14806", "-0.19028", "100")
s.esSend("%" + callsign, "29430", "3", "100", "7", "51.14806", "-0.19028", "0")
message = s.recv(1024)
print(message)
s.esSend("$CQ" + callsign, "SERVER", "ATC", callsign)
s.esSend("$CQ" + callsign, "SERVER", "CAPS")
s.esSend("$CQ" + callsign, "SERVER", "IP")
infoResponse = s.recv(1024)
print(infoResponse)
return s
class PlaneSocket(EsSocket):
@staticmethod
def StartPlane(plane, masterCallsign: str, masterSock: ControllerSocket) -> 'PlaneSocket':
s = PlaneSocket(socket.AF_INET, socket.SOCK_STREAM)
plane.masterSocketHandleData = (masterSock, masterCallsign)
s.connect(("127.0.0.1", PORT))
s.esSend("#AP" + plane.callsign, "SERVER", "1646235", "pass", "1", "9", "1", "Alice Ford")
s.sendall(plane.positionUpdateText(calculatePosition=False))
s.sendall(b'$FP' + plane.callsign.encode("UTF-8") + str(plane.flightPlan).encode("UTF-8") + b'\r\n') # TODO
masterSock.esSend(f"$CQ{masterCallsign}", "SERVER", "FP", plane.callsign)
masterSock.esSend(f"$CQ{masterCallsign}", "@94835", "WH", plane.callsign)
masterSock.esSend(f"$CQ{masterCallsign}", plane.callsign, "CAPS")
if plane.currentlyWithData is not None:
PausableTimer(1, masterSock.esSend, args=["$CQ" + plane.currentlyWithData[0], "@94835", "IT", plane.callsign]) # Controller takes plane
PausableTimer(1, masterSock.esSend, args=["$CQ" + plane.currentlyWithData[0], "@94835", "TA", plane.callsign, plane.altitude]) # Temp alt for arrivals
PausableTimer(1, masterSock.esSend, args=["$CQ" + masterCallsign, "@94835", "BC", plane.callsign, plane.squawk]) # Assign squawk
return s
class PausableTimer(threading.Thread):
timers: list['PausableTimer'] = []
def __init__(self, interval, function, args=[], kwargs={}):
threading.Timer.__init__(self, interval, function, args, kwargs)
self.delay = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.timeElapsed = 0
self.cancel = False
self.daemon = True
self.startTime = time.time()
PausableTimer.timers.append(self)
self.start()
def pause(self):
self.cancel = True
self.delay -= time.time() - self.startTime
def restart(self):
PausableTimer.timers.remove(self)
self.__init__(self.delay, self.function, self.args, self.kwargs)
def run(self) -> None:
while self.timeElapsed < self.delay:
if self.cancel:
return
self.timeElapsed = time.time() - self.startTime
time.sleep(0.5)
PausableTimer.timers.remove(self)
try:
self.function(*self.args, **self.kwargs)
except Exception as e:
print(e)
if __name__ == "__main__":
print(whichSector(*sfCoordsToNormalCoords(*"N052.24.50.722:W001.15.26.594".split(":")), 5000))
start_lat, start_lon = 51.47767, -0.43328
bearing = 269-180
for i in range(-5,20):
print(pbd(start_lat, start_lon, bearing, i))
for _ in range(100):
print(callsignGen("EGKK",[])[0])