def validate_polygon(obj): """ Make sure an input can be returned as a valid polygon. Parameters ------------- obj : shapely.geometry.Polygon, str (wkb), or (n, 2) float Object which might be a polygon Returns ------------ polygon : shapely.geometry.Polygon Valid polygon object Raises ------------- ValueError If a valid finite- area polygon isn't available """ if isinstance(obj, Polygon): polygon = obj elif util.is_shape(obj, (-1, 2)): polygon = Polygon(obj) elif util.is_string(obj): polygon = load_wkb(obj) else: raise ValueError('Input not a polygon!') if (not polygon.is_valid or polygon.area < tol.zero): raise ValueError('Polygon is zero- area or invalid!') return polygon
def test_polygon(self): coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)) # Construct a polygon, exterior ring only polygon = Polygon(coords) self.assertEqual(len(polygon.exterior.coords), 5) # Ring Access self.assertIsInstance(polygon.exterior, LinearRing) ring = polygon.exterior self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], (0., 0.)) self.assertTrue(ring.is_ring) self.assertEqual(len(polygon.interiors), 0) # Create a new polygon from WKB data = polygon.wkb polygon = None ring = None polygon = load_wkb(data) ring = polygon.exterior self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], (0., 0.)) self.assertTrue(ring.is_ring) polygon = None # Interior rings (holes) polygon = Polygon(coords, [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]) self.assertEqual(len(polygon.exterior.coords), 5) self.assertEqual(len(polygon.interiors[0].coords), 5) with self.assertRaises(IndexError): # index out of range polygon.interiors[1] # Test from another Polygon copy = Polygon(polygon) self.assertEqual(len(polygon.exterior.coords), 5) self.assertEqual(len(polygon.interiors[0].coords), 5) with self.assertRaises(IndexError): # index out of range polygon.interiors[1] # Coordinate getters and setters raise exceptions self.assertRaises(NotImplementedError, polygon._get_coords) with self.assertRaises(NotImplementedError): polygon.coords # Geo interface self.assertEqual( polygon.__geo_interface__, {'type': 'Polygon', 'coordinates': (((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)), ((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)))}) # Error handling with self.assertRaises(ValueError): # A LinearRing must have at least 3 coordinate tuples Polygon([[1, 2], [2, 3]])
def _load_geometry(self, wkb_or_wkt): try: return load_wkb(wkb_or_wkt) except: try: return load_wkt(wkb_or_wkt) except: return None
def _load_geometry(self, geometry_spec): if isinstance(geometry_spec, BaseGeometry): return geometry_spec try: return load_wkb(geometry_spec) except: try: return load_wkt(geometry_spec) except: return None
def validate_polygon(obj): if util.is_instance_named(obj, 'Polygon'): polygon = obj elif util.is_shape(obj, (-1, 2)): polygon = Polygon(obj) elif util.is_string(obj): polygon = load_wkb(obj) else: raise ValueError('Input not a polygon!') if (not polygon.is_valid or polygon.area < tol.zero): raise ValueError('Polygon is zero- area or invalid!') return polygon
def validate_polygon(obj): if util.is_instance_named(obj, 'Polygon'): polygon = obj elif util.is_shape(obj, (-1,2)): polygon = Polygon(obj) elif util.is_string(obj): polygon = load_wkb(obj) else: raise ValueError('Input not a polygon!') if (not polygon.is_valid or polygon.area < tol.zero): raise ValueError('Polygon is zero- area or invalid!') return polygon
def test_polygon(self): coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)) # Construct a polygon, exterior ring only polygon = Polygon(coords) assert len(polygon.exterior.coords) == 5 # Ring Access assert isinstance(polygon.exterior, LinearRing) ring = polygon.exterior assert len(ring.coords) == 5 assert ring.coords[0] == ring.coords[4] assert ring.coords[0] == (0.0, 0.0) assert ring.is_ring is True assert len(polygon.interiors) == 0 # Create a new polygon from WKB data = polygon.wkb polygon = None ring = None polygon = load_wkb(data) ring = polygon.exterior assert len(ring.coords) == 5 assert ring.coords[0] == ring.coords[4] assert ring.coords[0] == (0.0, 0.0) assert ring.is_ring is True polygon = None # Interior rings (holes) polygon = Polygon(coords, [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]) assert len(polygon.exterior.coords) == 5 assert len(polygon.interiors[0].coords) == 5 with pytest.raises(IndexError): # index out of range polygon.interiors[1] # Coordinate getter raises exceptions with pytest.raises(NotImplementedError): polygon.coords # Geo interface assert polygon.__geo_interface__ == { "type": "Polygon", "coordinates": ( ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)), ((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)), ), }
def _load_geometry(self, geometry_spec): if isinstance(geometry_spec, BaseGeometry): return geometry_spec if isinstance(geometry_spec, dict): return SimpleShape(geometry_spec['coordinates'], geometry_spec["type"]) try: return load_wkb(geometry_spec) except Exception: try: return load_wkt(geometry_spec) except Exception: return None
def _loadGeometry(self, geometrySpec): """ A private method to convert a (E)WKB or (E)WKT to a Shapely geometry. """ if type(geometrySpec) is str and geometrySpec.startswith('POLYGON Z'): try: geometry = load_wkt(geometrySpec) except Exception: geometry = None else: try: geometry = load_wkb(geometrySpec) except Exception: geometry = None if geometry is None: raise ValueError('Failed to convert WKT or WKB to a Shapely geometry') return geometry
def test_polygon(self): # Initialization # Linear rings won't usually be created by users, but by polygons coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)) ring = LinearRing(coords) self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], ring.coords[-1]) self.assertTrue(ring.is_ring) # Coordinate modification ring.coords = ((0.0, 0.0), (0.0, 2.0), (2.0, 2.0), (2.0, 0.0)) self.assertEqual( ring.__geo_interface__, { 'type': 'LinearRing', 'coordinates': ((0.0, 0.0), (0.0, 2.0), (2.0, 2.0), (2.0, 0.0), (0.0, 0.0)) }) # Test ring adapter coords = [[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]] ra = asLinearRing(coords) self.assertTrue(ra.wkt.upper().startswith('LINEARRING')) self.assertEqual(dump_coords(ra), [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)]) coords[3] = [2.0, -1.0] self.assertEqual(dump_coords(ra), [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0)]) # Construct a polygon, exterior ring only polygon = Polygon(coords) self.assertEqual(len(polygon.exterior.coords), 5) # Ring Access self.assertIsInstance(polygon.exterior, LinearRing) ring = polygon.exterior self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], (0., 0.)) self.assertTrue(ring.is_ring) self.assertEqual(len(polygon.interiors), 0) # Create a new polygon from WKB data = polygon.wkb polygon = None ring = None polygon = load_wkb(data) ring = polygon.exterior self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], (0., 0.)) self.assertTrue(ring.is_ring) polygon = None # Interior rings (holes) polygon = Polygon(coords, [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]) self.assertEqual(len(polygon.exterior.coords), 5) self.assertEqual(len(polygon.interiors[0].coords), 5) with self.assertRaises(IndexError): # index out of range polygon.interiors[1] # Test from another Polygon copy = Polygon(polygon) self.assertEqual(len(polygon.exterior.coords), 5) self.assertEqual(len(polygon.interiors[0].coords), 5) with self.assertRaises(IndexError): # index out of range polygon.interiors[1] # Coordinate getters and setters raise exceptions self.assertRaises(NotImplementedError, polygon._get_coords) with self.assertRaises(NotImplementedError): polygon.coords # Geo interface self.assertEqual( polygon.__geo_interface__, { 'type': 'Polygon', 'coordinates': (((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0)), ((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25))) }) # Adapter hole_coords = [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))] pa = asPolygon(coords, hole_coords) self.assertEqual(len(pa.exterior.coords), 5) self.assertEqual(len(pa.interiors), 1) self.assertEqual(len(pa.interiors[0].coords), 5) # Test Non-operability of Null rings r_null = LinearRing() self.assertEqual(r_null.wkt, 'GEOMETRYCOLLECTION EMPTY') self.assertEqual(r_null.length, 0.0) # Check that we can set coordinates of a null geometry r_null.coords = [(0, 0), (1, 1), (1, 0)] self.assertAlmostEqual(r_null.length, 3.414213562373095) # Error handling with self.assertRaises(ValueError): # A LinearRing must have at least 3 coordinate tuples Polygon([[1, 2], [2, 3]])
def get(self): p = get_parser.parse_args() lon, lat = p['lon'], p['lat'] if current_app.config['LIMITED_ZONE'] and\ not Point(lon, lat).intersects(current_app.config['LIMITED_ZONE']): #It must be 403, but I don't know how our clients will react: return {'data': []} self.zupc_customer = cache_single( """SELECT id, parent_id, max_distance, insee FROM "ZUPC" WHERE ST_INTERSECTS(shape, 'POINT(%s %s)') AND parent_id = id ORDER BY max_distance ASC;""", (lon, lat), "zupc_lon_lat", lambda v: (v['id'], v['parent_id']), get_id=lambda a: (float(a[1].split(",")[0][1:].strip()), float(a[1].split(",")[1][:-1].strip()))) if len(self.zupc_customer) == 0: current_app.logger.debug('No zone found at {}, {}'.format( lat, lon)) return {'data': []} zupc_id = self.zupc_customer[0][0] zupc_insee = self.zupc_customer[0][3] #We can deactivate the max radius for a certain zone inactive_filter_period = current_app.config['INACTIVE_FILTER_PERIOD'] hour = datetime.now().hour if inactive_filter_period[0] > inactive_filter_period[1]: is_inactive = hour >= inactive_filter_period[0] or\ hour <= inactive_filter_period[1] else: is_inactive = inactive_filter_period[ 0] <= hour <= inactive_filter_period[1] if is_inactive: max_distance = current_app.config['DEFAULT_MAX_RADIUS'] else: max_distance = min( filter(lambda v: v > 0, [v[2] for v in self.zupc_customer]) + [current_app.config['DEFAULT_MAX_RADIUS']]) self.check_freshness() g.keys_to_delete = [] name_redis = '{}:{}:{}'.format(lon, lat, time()) g.keys_to_delete.append(name_redis) #It returns a list of all taxis near the given point #For each taxi you have a tuple with: (id, distance, [lat, lon]) nb_positions = redis_store.georadius( current_app.config['REDIS_GEOINDEX_ID'], lat, lon, radius=max_distance / 1000.0, units='km', storedistkey=name_redis) if nb_positions == 0: current_app.logger.debug('No taxi found at {}, {}'.format( lat, lon)) return {'data': []} self.parent_zupc = {r[0]: r[1] for r in self.zupc_customer} self.zupc_customer = { r[0]: r[1] for r in cache_in( 'SELECT id, ST_AsBinary(shape) AS shape FROM "ZUPC" WHERE id in %s', {int(r1[1]) for r1 in self.zupc_customer}, "zupc_parent_shape", lambda v: (v['id'], prep(load_wkb(bytes(v['shape'])))), get_id=lambda v: unicode(v[0])) } taxis = [] offset = 0 count = p['count'] * 4 self.set_not_available(lon, lat, name_redis) while len(taxis) < p['count']: page_ids_distances = [ v for v in redis_store.zrangebyscore(name_redis, 0., '+inf', offset, count, True) if v[0] not in self.not_available ] offset += count if len(page_ids_distances) == 0: break page_ids = [v[0] for v in page_ids_distances] distances = [v[1] for v in page_ids_distances] positions = redis_store.geopos( current_app.config['REDIS_GEOINDEX_ID'], *page_ids) taxis_db = models.RawTaxi.get(page_ids) #We get all timestamps pipe = redis_store.pipeline() map( lambda l_taxis: map( lambda t: pipe.zscore( current_app.config['REDIS_TIMESTAMPS'], t['taxi_id'] + ':' + t['u_email']), l_taxis), taxis_db) timestamps = pipe.execute() #For each member of timestamp_slices we have the first index of the first element #in timestamp, and the index of the last element #If we have taxis_db = [{t_1,}, {,}, {t_21, t_22}, {t_3,}] #Then we want timestamps_slices = [(0, 1), (1, 1), (1, 3), (3, 4)] timestamps_slices = [] map(lambda i: timestamps_slices.append((0, len(i)))\ if not timestamps_slices\ else timestamps_slices.append((timestamps_slices[-1][1], timestamps_slices[-1][1]+len(i))), taxis_db) l = [ models.RawTaxi.generate_dict( t[0], None, None, favorite_operator=p['favorite_operator'], position={ "lon": t[1][1], "lat": t[1][0] }, distance=t[2], timestamps=islice(timestamps, *t[3])) for t in izip( taxis_db, positions, distances, timestamps_slices) if len(t) > 0 if self.filter_zone(t[0], t[1]) ] taxis.extend(filter(None, l)) client = influx_db.get_client(current_app.config['INFLUXDB_TAXIS_DB']) if client: try: client.write_points([{ "measurement": "get_taxis_requests", "tags": { "zupc": zupc_insee, "position": "{:.3f}:{:.3f}".format(float(lon), float(lat)), "moteur": current_user.email, "customer": hashlib.sha224( request.headers.getlist("X-Forwarded-For")[0]. rpartition(' ')[-1] if 'X-Forwarded-For' in request.headers else request.remote_addr or 'untrackable').hexdigest()[:10] }, "time": datetime.utcnow().strftime('%Y%m%dT%H:%M:%SZ'), "fields": { "value": len(taxis) } }]) except Exception as e: current_app.logger.error('Influxdb Error: {}'.format(e)) return { 'data': sorted(taxis, key=lambda t: t['crowfly_distance'])[:p['count']] }
def transform_wkb_to_form_text(data): if data is not None and data is not '': return load_wkb(str(data).decode('hex')).to_wkt() return ''
def get(self): p = get_parser.parse_args() lon, lat = p['lon'], p['lat'] if current_app.config['LIMITED_ZONE'] and\ not Point(lon, lat).intersects(current_app.config['LIMITED_ZONE']): #It must be 403, but I don't know how our clients will react: return {'data': []} self.zupc_customer = db.session.execute( """SELECT id, parent_id, max_distance, insee FROM "ZUPC" WHERE ST_INTERSECTS(shape, 'POINT(:lon :lat)') AND parent_id = id ORDER BY max_distance ASC;""", { "lon": lon, "lat": lat }).fetchall() if len(self.zupc_customer) == 0: current_app.logger.debug('No zone found at {}, {}'.format( lat, lon)) return {'data': []} zupc_insee = self.zupc_customer[0][3] #We can deactivate the max radius for a certain zone inactive_filter_period = current_app.config['INACTIVE_FILTER_PERIOD'] hour = datetime.now().hour if inactive_filter_period[0] > inactive_filter_period[1]: is_inactive = hour >= inactive_filter_period[0] or\ hour <= inactive_filter_period[1] else: is_inactive = inactive_filter_period[ 0] <= hour <= inactive_filter_period[1] if is_inactive: max_distance = current_app.config['DEFAULT_MAX_RADIUS'] else: max_distance = min( [v for v in [v[2] for v in self.zupc_customer] if v and v > 0] + [current_app.config['DEFAULT_MAX_RADIUS']]) self.check_freshness() g.keys_to_delete = [] name_redis = '{}:{}:{}'.format(lon, lat, time()) g.keys_to_delete.append(name_redis) #It returns a list of all taxis near the given point #For each taxi you have a tuple with: (id, distance, [lat, lon]) nb_positions = redis_store.georadius( current_app.config['REDIS_GEOINDEX_ID'], lon, lat, radius=max_distance, unit='m', store_dist=name_redis) if nb_positions == 0: current_app.logger.debug('No taxi found at {}, {}'.format( lat, lon)) return {'data': []} self.parent_zupc = {r[0]: r[1] for r in self.zupc_customer} self.zupc_customer = { r[0]: r[1] for r in [(v[0], prep(load_wkb(bytes(v[1])))) for v in db.session.execute( 'SELECT id, ST_AsBinary(shape) AS shape FROM "ZUPC" WHERE id in :zupc_list', { "zupc_list": tuple((int(r1[1]) for r1 in self.zupc_customer)) }).fetchall()] } taxis = [] offset = 0 count = p['count'] * 4 self.set_not_available(lon, lat, name_redis, max_distance) while len(taxis) < p['count']: page_ids_distances = [ v for v in redis_store.zrangebyscore(name_redis, 0., '+inf', offset, count, True) if v[0].decode() not in self.not_available ] offset += count if len(page_ids_distances) == 0: break page_ids = [v[0].decode() for v in page_ids_distances] distances = [v[1] for v in page_ids_distances] positions = redis_store.geopos( current_app.config['REDIS_GEOINDEX_ID'], *page_ids) taxis_db = models.RawTaxi.get(page_ids) #We get all timestamps pipe = redis_store.pipeline() list( map( lambda l_taxis: [ pipe.zscore(current_app.config['REDIS_TIMESTAMPS'], t[ 'taxi_id'] + ':' + t['u_email']) for t in l_taxis ], taxis_db)) timestamps = pipe.execute() #For each member of timestamp_slices we have the first index of the first element #in timestamp, and the index of the last element #If we have taxis_db = [{t_1,}, {,}, {t_21, t_22}, {t_3,}] #Then we want timestamps_slices = [(0, 1), (1, 1), (1, 3), (3, 4)] timestamps_slices = [] list(map(lambda i: timestamps_slices.append((0, len(i)))\ if not timestamps_slices\ else timestamps_slices.append((timestamps_slices[-1][1], timestamps_slices[-1][1]+len(i))), taxis_db)) l = [ models.RawTaxi.generate_dict( t[0], None, None, favorite_operator=p['favorite_operator'], position={ "lon": t[1][0], "lat": t[1][1] }, distance=t[2], timestamps=islice(timestamps, *t[3])) for t in zip(taxis_db, positions, distances, timestamps_slices) if len(t) > 0 if self.filter_zone(t[0], t[1]) ] taxis.extend([_f for _f in l if _f]) influx_db.write_point( current_app.config['INFLUXDB_TAXIS_DB'], "get_taxis_requests", { "zupc": zupc_insee, "position": "{:.3f}:{:.3f}".format(float(lon), float(lat)), "moteur": current_user.email, "customer": hashlib.sha224( str((request.headers.getlist("X-Forwarded-For") [0].rpartition(' ')[-1] if 'X-Forwarded-For' in request.headers else request.remote_addr) or 'untrackable').encode('utf-8')).hexdigest()[:10] }, value=len(taxis)) return { 'data': sorted(taxis, key=lambda t: t['crowfly_distance'])[:p['count']] }
def test_polygon(self): # Initialization # Linear rings won't usually be created by users, but by polygons coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)) ring = LinearRing(coords) self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], ring.coords[-1]) self.assertTrue(ring.is_ring) # Coordinate modification ring.coords = ((0.0, 0.0), (0.0, 2.0), (2.0, 2.0), (2.0, 0.0)) self.assertEqual( ring.__geo_interface__, {'type': 'LinearRing', 'coordinates': ((0.0, 0.0), (0.0, 2.0), (2.0, 2.0), (2.0, 0.0), (0.0, 0.0))}) # Test ring adapter coords = [[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]] ra = asLinearRing(coords) self.assertTrue(ra.wkt.upper().startswith('LINEARRING')) self.assertEqual(dump_coords(ra), [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)]) coords[3] = [2.0, -1.0] self.assertEqual(dump_coords(ra), [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0)]) # Construct a polygon, exterior ring only polygon = Polygon(coords) self.assertEqual(len(polygon.exterior.coords), 5) # Ring Access self.assertIsInstance(polygon.exterior, LinearRing) ring = polygon.exterior self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], (0., 0.)) self.assertTrue(ring.is_ring) self.assertEqual(len(polygon.interiors), 0) # Create a new polygon from WKB data = polygon.wkb polygon = None ring = None polygon = load_wkb(data) ring = polygon.exterior self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], (0., 0.)) self.assertTrue(ring.is_ring) polygon = None # Interior rings (holes) polygon = Polygon(coords, [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]) self.assertEqual(len(polygon.exterior.coords), 5) self.assertEqual(len(polygon.interiors[0].coords), 5) with self.assertRaises(IndexError): # index out of range polygon.interiors[1] # Test from another Polygon copy = Polygon(polygon) self.assertEqual(len(polygon.exterior.coords), 5) self.assertEqual(len(polygon.interiors[0].coords), 5) with self.assertRaises(IndexError): # index out of range polygon.interiors[1] # Coordinate getters and setters raise exceptions self.assertRaises(NotImplementedError, polygon._get_coords) with self.assertRaises(NotImplementedError): polygon.coords # Geo interface self.assertEqual( polygon.__geo_interface__, {'type': 'Polygon', 'coordinates': (((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0)), ((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)))}) # Adapter hole_coords = [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))] pa = asPolygon(coords, hole_coords) self.assertEqual(len(pa.exterior.coords), 5) self.assertEqual(len(pa.interiors), 1) self.assertEqual(len(pa.interiors[0].coords), 5) # Test Non-operability of Null rings r_null = LinearRing() self.assertEqual(r_null.wkt, 'GEOMETRYCOLLECTION EMPTY') self.assertEqual(r_null.length, 0.0) # Check that we can set coordinates of a null geometry r_null.coords = [(0, 0), (1, 1), (1, 0)] self.assertAlmostEqual(r_null.length, 3.414213562373095) # Error handling with self.assertRaises(ValueError): # A LinearRing must have at least 3 coordinate tuples Polygon([[1, 2], [2, 3]])
def get(self): p = get_parser.parse_args() lon, lat = p['lon'], p['lat'] if current_app.config['LIMITED_ZONE'] and\ not Point(lon, lat).intersects(current_app.config['LIMITED_ZONE']): #It must be 403, but I don't know how our clients will react: return {'data': []} self.zupc_customer = cache_single("""SELECT id, parent_id FROM "ZUPC" WHERE ST_INTERSECTS(shape, 'POINT(%s %s)');""", (lon, lat), "zupc_lon_lat", lambda v: (v['id'], v['parent_id']), get_id=lambda a:(float(a[1].split(",")[0][1:].strip()), float(a[1].split(",")[1][:-1].strip()))) if len(self.zupc_customer) == 0: current_app.logger.debug('No zone found at {}, {}'.format(lat, lon)) return {'data': []} self.check_freshness() g.keys_to_delete = [] name_redis = '{}:{}:{}'.format(lon, lat, time()) g.keys_to_delete.append(name_redis) #It returns a list of all taxis near the given point #For each taxi you have a tuple with: (id, distance, [lat, lon]) nb_positions = redis_store.georadius(current_app.config['REDIS_GEOINDEX_ID'], lat, lon, storedistkey=name_redis) if nb_positions == 0: current_app.logger.debug('No taxi found at {}, {}'.format(lat, lon)) return {'data': []} self.parent_zupc = {r[0]: r[1] for r in self.zupc_customer} self.zupc_customer = {r[0]: r[1] for r in cache_in( 'SELECT id, ST_AsBinary(shape) AS shape FROM "ZUPC" WHERE id in %s', {int(r1[1]) for r1 in self.zupc_customer}, "zupc_parent_shape", lambda v: (v['id'], prep(load_wkb(bytes(v['shape'])))), get_id=lambda v:unicode(v[0]))} taxis = [] offset = 0 count = p['count'] * 4 self.set_not_available(lon, lat, name_redis) while len(taxis) < p['count']: page_ids_distances = [v for v in redis_store.zrangebyscore(name_redis, 0., '+inf', offset, count, True) if v[0] not in self.not_available] offset += count if len(page_ids_distances) == 0: break page_ids = [v[0] for v in page_ids_distances] distances = [v[1] for v in page_ids_distances] positions = redis_store.geopos(current_app.config['REDIS_GEOINDEX_ID'] ,*page_ids) taxis_db = taxis_models.RawTaxi.get(page_ids) #We get all timestamps pipe = redis_store.pipeline() map(lambda l_taxis:map( lambda t: pipe.zscore(current_app.config['REDIS_TIMESTAMPS'], t['taxi_id']+':'+t['u_email']),l_taxis) , taxis_db) timestamps = pipe.execute() #If we have taxis_db = [{t_1}, {}, {t_21, t_22}, {t_3}] #Then we want timestamps_slices = [(0, 1), (1, 1), (1, 3), (3, 4)] timestamps_slices = [] map(lambda i: timestamps_slices.append((0, len(i)))\ if not timestamps_slices\ else timestamps_slices.append((timestamps_slices[-1][1], timestamps_slices[-1][1]+len(i))), taxis_db) l = [taxis_models.RawTaxi.generate_dict(t[0], None, None, favorite_operator=p['favorite_operator'], position={"lon": t[1][1], "lat": t[1][0]}, distance=t[2], timestamps=islice(timestamps, *t[3])) for t in izip(taxis_db, positions, distances, timestamps_slices) if len(t) > 0 if self.filter_zone(t[0], t[1])] taxis.extend(filter(None, l)) return {'data': sorted(taxis, key=lambda t: t['crowfly_distance'])[:p['count']]}