flock-server/model.py

115 lines
3.7 KiB
Python

"""
Object-Document Map for bike model
"""
from mongoengine import Document, DateTimeField, GeoPointField, \
FloatField, connection
from road_agent import Agent
import datetime
from LatLon import LatLon, Latitude, Longitude
class Flock:
"""
Flock object is created from a list of agents
and has a useful centroid
"""
def __init__(self, bikes):
lats = list()
lons = list()
speeds = list()
n = 0
for b in bikes:
speeds.append(b['speed'])
lats.append(float(b['point'][1]))
lons.append(float(b['point'][0]))
n += 1
if n > 0:
self.size = n
self.mean_speed = sum(speeds) / float(len(speeds))
self.centroid = LatLon(Latitude(sum(lats) / len(lats)),
Longitude(sum(lons) / len(lons)))
else:
self.mean_speed = 0
self.size = 0
self.centroid = None
class Bike(Document):
point = GeoPointField()
destination = GeoPointField(required=True)
speed = FloatField(default=0)
last_update = DateTimeField(default=datetime.datetime.utcnow)
def __init__(self, *args, **kwargs):
super(Document, self).__init__(*args, **kwargs)
self.agent = Agent(point=LatLon(self.point[1],
self.point[0]),
dest=LatLon(self.destination[1],
self.destination[0]),
router=None)
self.db = connection.get_db()
def update(self, lat, lon):
self.point = (lon, lat)
tdelta = datetime.datetime.now() - self.last_update
seconds = tdelta.total_seconds()
new_point = LatLon(Latitude(lat), Longitude(lon))
distance = abs(self.agent.point().distance(new_point)) / 1000.0
self.agent.update(new_point)
self.speed = distance / seconds
self.save()
def find_flock(self, point_altruism=0.1, dest_altruism=0.2):
"""
:return: list of Bike objects
"""
voyage_len = self.agent.distance_to(self.agent.destination())
local_radius = voyage_len * point_altruism
destination_radius = voyage_len * dest_altruism
# these are bikes around me
local = [bike for bike in
self.db.bike.find(
{'point':
{'$near':
{'$geometry': {'type': 'Point',
'coordinates': self.point},
'$maxDistance': local_radius}}})]
local_ids = set([bike['_id'] for bike in local])
# these are going near my destination
remote = [bike for bike in
self.db.bike.find(
{'destination':
{'$near':
{'$geometry': {'type': 'Point',
'coordinates': self.destination},
'$maxDistance': destination_radius}}})]
remote_ids = set([bike['_id'] for bike in remote])
# intersect them!
flock_ids = local_ids.intersection(remote_ids)
return (bike for bike in local if bike['_id'] in flock_ids)
def flock_data(self):
"""
:return: heading from point to flock centroid, in degrees
"""
flock = Flock(self.find_flock())
if flock.size > 1: # no flocking with self!
return {'flock_heading': self.agent.heading_to(flock.centroid),
'flock_distance': self.agent.distance_to(flock.centroid),
'flock_avg_speed': flock.mean_speed,
'flock_size': flock.size}
else:
return {}