""" 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 {}