def app(environ, start_response): stderr = environ['wsgi.errors'] cursor, response_headers = dbopen(environ, "openaddresses.sqlite") if cursor is None: start_response("304 Not Modified", response_headers) return [] query_string = unquote_plus(environ['QUERY_STRING']) house_number, apartment_number, street, city, state, postal_code = json.loads(query_string) # Build the query template query_template = "SELECT longitude, latitude FROM addresses where {house} and street=? and city=? and region=?" address_base = [ street, city, state ] if postal_code is not None and postal_code != "": query_template += " and (postal_code=? or postal_code is null)" address_base.append(postal_code) # Result of SQL queries go here. row = None # If the apartment number is specified in the address, try a search with the exact house number and apartment number. if apartment_number: cursor.execute(query_template.replace("{house}", "apartment_number=? and house_number=?"), [apartment_number, house_number] + address_base) row = cursor.fetchone() # If the previous search was not performed or did not produce anything, try without the apartment number. if row is None: # Try for an exact match #start_time = time.time() cursor.execute(query_template.replace("{house}", "house_number=?"), [house_number] + address_base) #stderr.write("elapsed: %f\n" % (time.time() - start_time)) row = cursor.fetchone() # If nothing found, look for an entry which gives a range of house numbers which includes this one. if row is None and re.match(r'^\d+$', house_number): house_number = int(house_number) cursor.execute(query_template.replace("{house}", "house_number_start <= ? and house_number_end >= ?"), [house_number, house_number] + address_base) row = cursor.fetchone() # If we got a match, insert the latitude and longitude into a GeoJSON point object. if row: feature = { 'type':'Feature', 'geometry':{'type':'Point', 'coordinates':[row[0], row[1]]}, 'properties':{'precision':'ROOF'} } else: feature = None start_response("200 OK", response_headers + [ ('Content-Type', 'application/json') ]) #stderr.write("Result: %s\n" % str(feature)) return [json.dumps(feature).encode("utf-8")]
def application(environ, start_response): stderr = environ['wsgi.errors'] cursor, response_headers = dbopen(environ, "openaddresses.sqlite") if cursor is None: start_response("304 Not Modified", response_headers) return [] query_string = unquote_plus(environ['QUERY_STRING']) house_number, apartment_number, street, city, state, postal_code = json.loads(query_string) # Build the query template query_template = "SELECT longitude, latitude FROM addresses where {house} and street=? and city=? and region=?" address_base = [ street, city, state ] if postal_code is not None and postal_code != "": query_template += " and (postal_code=? or postal_code is null)" address_base.append(postal_code) # Result of SQL queries go here. row = None # If the apartment number is specified in the address, try a search with the exact house number and apartment number. if apartment_number: cursor.execute(query_template.replace("{house}", "apartment_number=? and house_number=?"), [apartment_number, house_number] + address_base) row = cursor.fetchone() # If the previous search was not performed or did not produce anything, try without the apartment number. if row is None: # Try for an exact match #start_time = time.time() cursor.execute(query_template.replace("{house}", "house_number=?"), [house_number] + address_base) #stderr.write("elapsed: %f\n" % (time.time() - start_time)) row = cursor.fetchone() # If nothing found, look for an entry which gives a range of house numbers which includes this one. if row is None and re.match(r'^\d+$', house_number): house_number = int(house_number) cursor.execute(query_template.replace("{house}", "house_number_start <= ? and house_number_end >= ?"), [house_number, house_number] + address_base) row = cursor.fetchone() # If we got a match, insert the latitude and longitude into a GeoJSON point object. if row: feature = { 'type':'Feature', 'geometry':{'type':'Point', 'coordinates':[row[0], row[1]]}, 'properties':{'precision':'ROOF'} } else: feature = None start_response("200 OK", response_headers + [ ('Content-Type', 'application/json') ]) #stderr.write("Result: %s\n" % str(feature)) return [json.dumps(feature).encode("utf-8")]
def application(environ, start_response): stderr = environ['wsgi.errors'] cursor, response_headers = dbopen(environ, "parcels.sqlite") if cursor is None: start_response("304 Not Modified", response_headers) return [] query_string = urllib.unquote_plus(environ['QUERY_STRING']) #stderr.write("QUERY_STRING: %s\n" % query_string) house_number, apartment_number, street, town, state, postal_code = json.loads(query_string) # Build the query and the list of address elements to be inserted into it query = "SELECT centroid FROM parcel_addresses where house_number=? and street=? and city=? and state=?" address = [ house_number, street, town, state ] if postal_code != "": query += " and (zip=? OR zip='' OR zip IS NULL)" address.append(postal_code) # Try for an exact match start_time = time.time() cursor.execute(query, address) #stderr.write("elapsed: %f\n" % (time.time() - start_time)) row = cursor.fetchone() # If nothing found, try a house number two lower on the chance that # this is the second apartment in a duplex. The assessor's map # supposedly lists only the lowest number in such cases. if row is None: try: address[0] = str(int(address[0]) - 2) cursor.execute(query, address) row = cursor.fetchone() except ValueError: pass # If one or the other matched, if row: geometry = json.loads(row[0]) feature = { 'type':'Feature', 'geometry':geometry, 'properties':{'precision':'LOT'} } else: feature = None start_response("200 OK", response_headers + [ ('Content-Type', 'application/json') ]) #stderr.write("Result: %s\n" % str(feature)) return [json.dumps(feature).encode("utf-8")]
def app(environ, start_response): stderr = environ['wsgi.errors'] cursor, response_headers = dbopen(environ, "parcels.sqlite") if cursor is None: start_response("304 Not Modified", response_headers) return [] query_string = unquote_plus(environ['QUERY_STRING']) #stderr.write("QUERY_STRING: %s\n" % query_string) house_number, apartment_number, street, town, state, postal_code = json.loads( query_string) # Build the query and the list of address elements to be inserted into it query = "SELECT centroid FROM parcel_addresses where house_number=? and street=? and city=? and state=?" address = [house_number, street, town, state] if postal_code != "": query += " and (zip=? OR zip='' OR zip IS NULL)" address.append(postal_code) # Try for an exact match start_time = time.time() cursor.execute(query, address) #stderr.write("elapsed: %f\n" % (time.time() - start_time)) row = cursor.fetchone() # If nothing found, try a house number two lower on the chance that # this is the second apartment in a duplex. The assessor's map # supposedly lists only the lowest number in such cases. if row is None: try: address[0] = str(int(address[0]) - 2) cursor.execute(query, address) row = cursor.fetchone() except ValueError: pass # If one or the other matched, if row: geometry = json.loads(row[0]) feature = { 'type': 'Feature', 'geometry': geometry, 'properties': { 'precision': 'LOT' } } else: feature = None start_response("200 OK", response_headers + [('Content-Type', 'application/json')]) #stderr.write("Result: %s\n" % str(feature)) return [json.dumps(feature).encode("utf-8")]
def application(environ, start_response): stderr = environ['wsgi.errors'] m = re.match(r'^/([^/]+)/(\d+)/(\d+)/(\d+)\.geojson$', environ['PATH_INFO']) assert m, environ['PATH_INFO'] layer_name = m.group(1) zoom = int(m.group(2)) x = int(m.group(3)) y = int(m.group(4)) stderr.write("%s tile (%d, %d) at zoom %d...\n" % (layer_name, x, y, zoom)) assert zoom <= 16 cursor, response_headers = dbopen(environ, "osm_map.sqlite") if cursor is None: start_response("304 Not Modified", response_headers) return [] p1 = unproject_from_tilespace(x, y, zoom) p2 = unproject_from_tilespace(x + 1.0, y + 1.0, zoom) small_bbox = 'BuildMBR(%f,%f,%f,%f,4326)' % (p1[1], p1[0], p2[1], p2[0]) p1 = unproject_from_tilespace(x - 0.05, y - 0.05, zoom) p2 = unproject_from_tilespace(x + 1.05, y + 1.05, zoom) large_bbox = 'BuildMBR(%f,%f,%f,%f,4326)' % (p1[1], p1[0], p2[1], p2[0]) if layer_name in map_layer_sets: layer_names = map_layer_sets[layer_name] geojson = {} for layer_name in layer_names: tile_geojson = get_tile(stderr, cursor, layer_name, small_bbox, large_bbox, zoom) if tile_geojson is not None: geojson[layer_name.replace("osm-vector-","")] = tile_geojson else: geojson = get_tile(stderr, cursor, layer_name, small_bbox, large_bbox, zoom) # Convert Python objects to JSON and compress out = io.BytesIO() with gzip.GzipFile(fileobj=out, mode='w') as fo: json.dump(geojson, fo) geojson = out.getvalue() start_response("200 OK", response_headers + [ ('Content-Type', 'application/json'), ('Content-Encoding', 'gzip'), ]) return [geojson]
def application(environ, start_response): stderr = environ['wsgi.errors'] m = re.match(r'^/(\d+)/(\d+)/(\d+)\.geojson$', environ['PATH_INFO']) assert m, environ['PATH_INFO'] zoom = int(m.group(1)) x = int(m.group(2)) y = int(m.group(3)) stderr.write("Parcel tile (%d, %d) at zoom %d...\n" % (x, y, zoom)) assert zoom <= 16 cursor, response_headers = dbopen(environ, "parcels.sqlite") if cursor is None: start_response("304 Not Modified", response_headers) return [] p1 = unproject_from_tilespace(x - 0.05, y - 0.05, zoom) p2 = unproject_from_tilespace(x + 1.05, y + 1.05, zoom) bbox = 'BuildMBR(%f,%f,%f,%f,4326)' % (p1[1], p1[0], p2[1], p2[0]) geometry = "Intersection(Geometry,{bbox})".format(bbox=bbox) if zoom < 16: geometry = "SimplifyPreserveTopology({geometry},{simplification})".format( geometry=geometry, simplification = 360.0 / (2.0 ** zoom) / 256.0 # one pixel ) else: stderr.write("Not simplified\n") query = """SELECT rowid as __id__, AsGeoJSON({geometry}) as __geometry__, house_number, street, centroid FROM parcels WHERE MBRIntersects({bbox}, Geometry) AND ROWID IN ( SELECT ROWID FROM SpatialIndex WHERE f_table_name = 'parcels' AND search_frame = {bbox} ) """.format(geometry=geometry, bbox=bbox) cursor.execute(query) features = [] for row in cursor: if row['__geometry__'] is None: continue row = dict(row) feature = { 'type': 'Feature', 'id': row.pop("__id__"), 'geometry': json.loads(row.pop("__geometry__")), 'properties': row, } features.append(feature) stderr.write("Found %d feature(s)\n" % len(features)) geojson = { 'type': 'FeatureCollection', 'features': features, } # Convert to JSON and compress out = io.BytesIO() with gzip.GzipFile(fileobj=out, mode='w') as fo: json.dump(geojson, fo) geojson = out.getvalue() start_response("200 OK", response_headers + [ ('Content-Type', 'application/json'), ('Content-Encoding', 'gzip'), ]) return [geojson]
def application(environ, start_response): stderr = environ['wsgi.errors'] m = re.match(r'^/(\d+)/(\d+)/(\d+)\.geojson$', environ['PATH_INFO']) assert m, environ['PATH_INFO'] zoom = int(m.group(1)) x = int(m.group(2)) y = int(m.group(3)) stderr.write("Parcel tile (%d, %d) at zoom %d...\n" % (x, y, zoom)) assert zoom <= 16 cursor, response_headers = dbopen(environ, "parcels.sqlite") if cursor is None: start_response("304 Not Modified", response_headers) return [] p1 = unproject_from_tilespace(x - 0.05, y - 0.05, zoom) p2 = unproject_from_tilespace(x + 1.05, y + 1.05, zoom) bbox = 'BuildMBR(%f,%f,%f,%f,4326)' % (p1[1], p1[0], p2[1], p2[0]) geometry = "Intersection(Geometry,{bbox})".format(bbox=bbox) if zoom < 16: geometry = "SimplifyPreserveTopology({geometry},{simplification})".format( geometry=geometry, simplification=360.0 / (2.0**zoom) / 256.0 # one pixel ) else: stderr.write("Not simplified\n") query = """SELECT rowid as __id__, AsGeoJSON({geometry}) as __geometry__, house_number, street, centroid FROM parcels WHERE MBRIntersects({bbox}, Geometry) AND ROWID IN ( SELECT ROWID FROM SpatialIndex WHERE f_table_name = 'parcels' AND search_frame = {bbox} ) """.format(geometry=geometry, bbox=bbox) cursor.execute(query) features = [] for row in cursor: if row['__geometry__'] is None: continue row = dict(row) feature = { 'type': 'Feature', 'id': row.pop("__id__"), 'geometry': json.loads(row.pop("__geometry__")), 'properties': row, } features.append(feature) stderr.write("Found %d feature(s)\n" % len(features)) geojson = { 'type': 'FeatureCollection', 'features': features, } # Convert to JSON and compress out = io.BytesIO() with gzip.GzipFile(fileobj=out, mode='w') as fo: json.dump(geojson, fo) geojson = out.getvalue() start_response( "200 OK", response_headers + [ ('Content-Type', 'application/json'), ('Content-Encoding', 'gzip'), ]) return [geojson]