-
Notifications
You must be signed in to change notification settings - Fork 78
/
model.py
executable file
·93 lines (73 loc) · 3.31 KB
/
model.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
import json
import math
class Agent:
def __init__(self, position, **agent_attributes):
self.position = position
for attr_name, attr_value in agent_attributes.items():
setattr(self, attr_name, attr_value)
class Position:
def __init__(self, longitude_degrees, latitude_degrees):
self.latitude_degrees = latitude_degrees
self.longitude_degrees = longitude_degrees
@property
def longitude(self):
# Longitude in radians
return self.longitude_degrees * math.pi / 180
@property
def latitude(self):
# Latitude in radians
return self.latitude_degrees * math.pi / 180
class Zone:
ZONES = []
MIN_LONGITUDE_DEGREES = -180
MAX_LONGITUDE_DEGREES = 180
MIN_LATITUDE_DEGREES = -90
MAX_LATITUDE_DEGREES = 90
WIDTH_DEGREES = 1 # degrees of longitude
HEIGHT_DEGREES = 1 # degrees of latitude
def __init__(self, corner1, corner2):
self.corner1 = corner1
self.corner2 = corner2
self.inhabitants = []
@property
def population(self):
return len(self.inhabitants)
def add_inhabitant(self, inhabitant):
self.inhabitants.append(inhabitant)
def contains(self, position):
return position.longitude >= min(self.corner1.longitude, self.corner2.longitude) and \
position.longitude < max(self.corner1.longitude, self.corner2.longitude) and \
position.latitude >= min(self.corner1.latitude, self.corner2.latitude) and \
position.latitude < max(self.corner1.latitude, self.corner2.latitude)
@classmethod
def find_zone_that_contains(cls, position):
# Compute the index in the ZONES array that contains the given position
longitude_index = int((position.longitude_degrees - cls.MIN_LONGITUDE_DEGREES)/ cls.WIDTH_DEGREES)
latitude_index = int((position.latitude_degrees - cls.MIN_LATITUDE_DEGREES)/ cls.HEIGHT_DEGREES)
longitude_bins = int((cls.MAX_LONGITUDE_DEGREES - cls.MIN_LONGITUDE_DEGREES) / cls.WIDTH_DEGREES) # 180-(-180) / 1
zone_index = latitude_index * longitude_bins + longitude_index
# Just checking that the index is correct
zone = cls.ZONES[zone_index]
assert zone.contains(position)
return zone
@classmethod
def initialize_zones(cls):
# Note that this method is "private": we prefix the method name with "_".
cls.ZONES = []
for latitude in range(cls.MIN_LATITUDE_DEGREES, cls.MAX_LATITUDE_DEGREES, cls.HEIGHT_DEGREES):
for longitude in range(cls.MIN_LONGITUDE_DEGREES, cls.MAX_LONGITUDE_DEGREES, cls.WIDTH_DEGREES):
bottom_left_corner = Position(longitude, latitude)
top_right_corner = Position(longitude + cls.WIDTH_DEGREES, latitude + cls.HEIGHT_DEGREES)
zone = Zone(bottom_left_corner, top_right_corner)
cls.ZONES.append(zone)
def main():
Zone.initialize_zones()
for agent_attributes in json.load(open("agents-100k.json")):
latitude = agent_attributes.pop("latitude")
longitude = agent_attributes.pop("longitude")
position = Position(longitude, latitude)
agent = Agent(position, **agent_attributes)
zone = Zone.find_zone_that_contains(position)
zone.add_inhabitant(agent)
print(zone.population)
main()