source: src/mlx/gates.py@ 1174:e5668ec0ad5f

python3
Last change on this file since 1174:e5668ec0ad5f was 1172:6cb71d6b4572, checked in by István Váradi <ivaradi@…>, 2 days ago

The gate data can be read from a JSON file

File size: 12.7 KB
Line 
1#--------------------------------------------------------------------------------------
2
3## @package mlx.gates
4#
5# The module to handle the LHBP gate information.
6#
7
8#--------------------------------------------------------------------------------------
9
10class Gate(object):
11 """Information about a gate."""
12 @staticmethod
13 def fromJSON(data):
14 """Create the gate from the given JSON data."""
15 return Gate(data["number"], data["terminal"],
16 data["type"],
17 maxSpan = data["maxSpan"],
18 maxLength = data["maxLength"])
19
20 def __init__(self, number, terminal, type,
21 availableFn = None, taxiThrough = False,
22 maxSpan = 0.0, maxLength = 0.0):
23 """Construct the gate with the given information.
24
25 number is the gate's number as a string (as it can contain letters).
26 terminal is the terminal the gate belongs to (not used currently).
27 type is the gate's type: G for gate, S for stand.
28 availableFn is a function that can determine if the gate is available based on
29 the statuses of other gates. Its arguments are:
30 - a collection of the gates, and
31 - a set of occupied gate numbers."""
32 self.number = number
33 self.terminal = terminal
34 self.type = type
35 self._availableFn = availableFn
36 self.taxiThrough = taxiThrough
37 self.maxSpan = maxSpan
38 self.maxLength = maxLength
39
40 def isAvailable(self, plane, gates, occupiedGateNumbers):
41 """Determine if this gate is available for the given plane and the
42 given the set of gates and occupied gate numbers."""
43 if self.number in occupiedGateNumbers:
44 return False
45 if self._availableFn is None or \
46 self._availableFn(gates, occupiedGateNumbers):
47 return plane is None or \
48 ((self.maxSpan<0.1 or plane.wingSpan <= self.maxSpan) and
49 (self.maxLength<0.1 or plane.fuselageLength <= self.maxLength) and
50 (not plane.hasStairs or self.type!="G"))
51 else:
52 return False
53
54 def toJSON(self):
55 """Create a JSON representation of the gate."""
56 data = {}
57 for attributeName in ["number", "terminal", "type",
58 "maxSpan", "maxLength"]:
59 data[attributeName] = getattr(self, attributeName)
60 return data
61
62#--------------------------------------------------------------------------------------
63
64class Gates(object):
65 """A collection of gates."""
66 # Display info type: a gate (number)
67 DISPLAY_GATE=1
68
69 # Display info type: a space
70 DISPLAY_SPACE=2
71
72 # Display info type: a new column
73 DISPLAY_NEW_COLUMN=3
74
75 @staticmethod
76 def fromJSON(data):
77 """Create a gates object from the given JSON data."""
78 gates = Gates()
79 for gateData in data:
80 gates.add(Gate.fromJSON(gateData))
81 return gates
82
83 def __init__(self):
84 """Construct the gate collection."""
85 self._gates = []
86 self._displayInfos = []
87 self._numColumns = 1
88 self._numRows = 0
89 self._numRowsInColumn = 0
90
91 @property
92 def gates(self):
93 """Get an iterator over the gates."""
94 return iter(self._gates)
95
96 @property
97 def displayInfos(self):
98 """Get an iterator over the display info tuples.
99
100 Each tuple consists of
101 - a type (one of the DISPLAY_XXX constants), and
102 - an additional data (the gate for DISPLAY_GATE, None for others)."""
103 return iter(self._displayInfos)
104
105 @property
106 def numRows(self):
107 """Get the number of rows."""
108 return self._numRows
109
110 @property
111 def numColumns(self):
112 """Get the number of columns."""
113 return self._numColumns
114
115 def add(self, gate):
116 """Add a gate to the collection."""
117 self._gates.append(gate)
118 self._displayInfos.append((Gates.DISPLAY_GATE, gate))
119 self._addRow()
120
121 def find(self, gateNumber):
122 """Find a gate by its number."""
123 for gate in self._gates:
124 if gate.number == gateNumber:
125 return gate
126
127 def addSpace(self):
128 """Add a space between subsequent gates."""
129 self._displayInfos.append((Gates.DISPLAY_SPACE, None))
130 self._addRow()
131
132 def addNewColumn(self):
133 """Start a new column of gates."""
134 self._displayInfos.append((Gates.DISPLAY_NEW_COLUMN, None))
135 self._numRowsInColumn = 0
136 self._numColumns += 1
137
138 def merge(self, otherGates):
139 """Merge the information from the given gate list (retrieved from the
140 MAVA server) into this gate list."""
141 for otherGate in otherGates.gates:
142 gate = self.find(otherGate.number)
143 if gate is None:
144 print("Received data for gate %s, but it does not exist locally!" %
145 (otherGate.number,))
146 else:
147 if gate.terminal != otherGate.terminal:
148 print("The terminal for gate %s is received as: %s" %
149 (gate.number, otherGate.terminal))
150 gate.terminal = otherGate.terminal
151 if gate.type != otherGate.type:
152 print("The type for gate %s is received as: %s" %
153 (gate.number, otherGate.type))
154 gate.type = otherGate.type
155
156 gate.maxSpan = otherGate.maxSpan
157 gate.maxLength = otherGate.maxLength
158
159 for gate in self.gates:
160 if gate.maxSpan==0.0 or gate.maxLength==0.0:
161 print("Gate %s has no maximal dimensions from the database" %
162 (gate.number,))
163
164 def toJSON(self):
165 """Convert the list of gates into a JSON data."""
166 return [gate.toJSON() for gate in self._gates]
167
168 def _addRow(self):
169 """Add a new row."""
170 self._numRowsInColumn += 1
171 if self._numRowsInColumn > self._numRows:
172 self._numRows = self._numRowsInColumn
173
174#--------------------------------------------------------------------------------------
175
176def availableIf(occupiedGateNumbers, othersAvailable = []):
177 """Determine if a gate is available.
178
179 othersAvailable is a list of numbers of gates, that must be available so
180 that the one we are considering is available."""
181 for otherNumber in othersAvailable:
182 if otherNumber in occupiedGateNumbers:
183 return False
184 return True
185
186#--------------------------------------------------------------------------------------
187
188def getAvailableIf(othersAvailable = []):
189 """Get a function that determines if a gate is available based on the
190 statuses of other gates."""
191 return lambda gates, occupiedGateNumbers: availableIf(occupiedGateNumbers,
192 othersAvailable =
193 othersAvailable)
194
195#--------------------------------------------------------------------------------------
196
197# The gates at LHBP
198lhbpGates = Gates()
199
200lhbpGates.add(Gate("R101", "1", "S", taxiThrough = True))
201lhbpGates.add(Gate("R102", "1", "S"))
202lhbpGates.add(Gate("R103", "1", "S"))
203lhbpGates.add(Gate("R104", "1", "S",
204 availableFn = getAvailableIf(othersAvailable = ["R105"])))
205lhbpGates.add(Gate("R105", "1", "S",
206 availableFn = getAvailableIf(othersAvailable = ["R104", "R106"])))
207lhbpGates.add(Gate("R106", "1", "S",
208 availableFn = getAvailableIf(othersAvailable = ["R105", "R108"])))
209lhbpGates.add(Gate("R107", "1", "S",
210 availableFn = getAvailableIf(othersAvailable = ["R108"])))
211lhbpGates.add(Gate("R108", "1", "S",
212 availableFn = getAvailableIf(othersAvailable = ["R106", "R107"])))
213
214lhbpGates.addSpace()
215lhbpGates.add(Gate("R110", "1", "S",
216 availableFn = getAvailableIf(othersAvailable = ["R111"])))
217lhbpGates.add(Gate("R111", "1", "S",
218 availableFn = getAvailableIf(othersAvailable = ["R110", "R112"])))
219lhbpGates.add(Gate("R112", "1", "S",
220 availableFn = getAvailableIf(othersAvailable = ["R111"])))
221lhbpGates.add(Gate("R113", "1", "S",
222 availableFn = getAvailableIf(othersAvailable = ["R112", "R114"])))
223lhbpGates.add(Gate("R114", "1", "S",
224 availableFn = getAvailableIf(othersAvailable = ["R113"])))
225lhbpGates.add(Gate("R115", "1", "S"))
226lhbpGates.add(Gate("R116", "1", "S",
227 availableFn = getAvailableIf(othersAvailable = ["R117"]),
228 taxiThrough = True))
229lhbpGates.add(Gate("R117", "1", "S",
230 availableFn = getAvailableIf(othersAvailable = ["R116", "R117A"])))
231lhbpGates.add(Gate("R117A", "1", "S",
232 availableFn = getAvailableIf(othersAvailable = ["R116", "R117"])))
233lhbpGates.addNewColumn()
234
235lhbpGates.add(Gate("G150", "1", "S"))
236lhbpGates.add(Gate("G151", "1", "S"))
237lhbpGates.add(Gate("G152", "1", "S"))
238lhbpGates.add(Gate("G153", "1", "S"))
239lhbpGates.add(Gate("G154", "1", "S"))
240lhbpGates.add(Gate("G155", "1", "S"))
241
242lhbpGates.addSpace()
243lhbpGates.add(Gate("G170", "1", "S", taxiThrough = True))
244lhbpGates.add(Gate("G171", "1", "S", taxiThrough = True))
245lhbpGates.add(Gate("G172", "1", "S", taxiThrough = True))
246lhbpGates.addNewColumn()
247
248lhbpGates.add(Gate("31", "2B", "G"))
249lhbpGates.add(Gate("32", "2B", "G"))
250lhbpGates.add(Gate("33", "2B", "G"))
251lhbpGates.add(Gate("34", "2B", "G",
252 availableFn = getAvailableIf(othersAvailable = ["34L", "34R"])))
253lhbpGates.add(Gate("34L", "2B", "G",
254 availableFn = getAvailableIf(othersAvailable = ["34", "34R"])))
255lhbpGates.add(Gate("34R", "2B", "G",
256 availableFn = getAvailableIf(othersAvailable = ["34L", "34"])))
257lhbpGates.add(Gate("35", "2B", "G",
258 availableFn = getAvailableIf(othersAvailable = ["35L", "35R"])))
259lhbpGates.add(Gate("35L", "2B", "G",
260 availableFn = getAvailableIf(othersAvailable = ["35", "35R"])))
261lhbpGates.add(Gate("35R", "2B", "G",
262 availableFn = getAvailableIf(othersAvailable = ["35L", "35"])))
263lhbpGates.add(Gate("36", "2B", "G",
264 availableFn = getAvailableIf(othersAvailable = ["36L", "36R"])))
265lhbpGates.add(Gate("36L", "2B", "G",
266 availableFn = getAvailableIf(othersAvailable = ["36", "36R"])))
267lhbpGates.add(Gate("36R", "2B", "G",
268 availableFn = getAvailableIf(othersAvailable = ["36L", "36"])))
269lhbpGates.addSpace()
270
271lhbpGates.add(Gate("37", "2B", "G"))
272lhbpGates.add(Gate("38", "2B", "G"))
273lhbpGates.add(Gate("39", "2B", "G",
274 availableFn = getAvailableIf(othersAvailable = ["37L", "37R"])))
275lhbpGates.add(Gate("39L", "2B", "G",
276 availableFn = getAvailableIf(othersAvailable = ["37", "37R"])))
277lhbpGates.add(Gate("39R", "2B", "G",
278 availableFn = getAvailableIf(othersAvailable = ["37L", "37"])))
279lhbpGates.addNewColumn()
280
281lhbpGates.add(Gate("42", "2A", "G"))
282lhbpGates.add(Gate("43", "2A", "G"))
283lhbpGates.add(Gate("44", "2A", "G"))
284lhbpGates.add(Gate("45", "2A", "G"))
285lhbpGates.addSpace()
286
287lhbpGates.add(Gate("R210", "2A", "S",
288 availableFn = getAvailableIf(othersAvailable = ["R212A"]),
289 taxiThrough = True))
290lhbpGates.add(Gate("R211", "2A", "S",
291 availableFn = getAvailableIf(othersAvailable = ["R212A"]),
292 taxiThrough = True))
293lhbpGates.add(Gate("R212", "2A", "S",
294 availableFn = getAvailableIf(othersAvailable = ["R212A"]),
295 taxiThrough = True))
296lhbpGates.add(Gate("R212A", "2A", "S",
297 availableFn = getAvailableIf(othersAvailable = ["R210", "R211", "R212"]),
298 taxiThrough = True))
299lhbpGates.addSpace()
300
301lhbpGates.add(Gate("R220", "2B", "S"))
302lhbpGates.add(Gate("R221", "2B", "S"))
303lhbpGates.add(Gate("R222", "2B", "S"))
304lhbpGates.add(Gate("R223", "2B", "S"))
305lhbpGates.addSpace()
306
307lhbpGates.add(Gate("R224", "2A", "S"))
308lhbpGates.add(Gate("R225", "2A", "S"))
309lhbpGates.add(Gate("R226", "2A", "S"))
310lhbpGates.add(Gate("R227", "2A", "S"))
311lhbpGates.addNewColumn()
312
313lhbpGates.add(Gate("R270", "2A", "S"))
314lhbpGates.add(Gate("R271", "2A", "S"))
315lhbpGates.add(Gate("R272", "2A", "S"))
316lhbpGates.add(Gate("R273", "2A", "S"))
317lhbpGates.add(Gate("R274", "2A", "S"))
318lhbpGates.add(Gate("R275", "2A", "S"))
319lhbpGates.add(Gate("R276", "2A", "S"))
320lhbpGates.add(Gate("R277", "2A", "S"))
321lhbpGates.add(Gate("R278", "2A", "S",
322 availableFn = getAvailableIf(othersAvailable = ["R278A"]),
323 taxiThrough = True))
324lhbpGates.add(Gate("R278A", "2A", "S",
325 availableFn = getAvailableIf(othersAvailable = ["R278", "R279"])))
326lhbpGates.add(Gate("R279", "2A", "S",
327 availableFn = getAvailableIf(othersAvailable = ["R278A"]),
328 taxiThrough = True))
Note: See TracBrowser for help on using the repository browser.