def point_elevation(geometry, format_out, dataset): """ Performs PostGIS query to enrich a point geometry. :param geometry: Input point to be enriched with elevation :type geometry: shapely.geometry.Point :param format_out: Specifies output format. One of ['geojson', 'point'] :type format_out: string :param dataset: Elevation dataset to use for querying :type dataset: string :raises InvalidUsage: internal HTTP 500 error with more detailed description. :returns: 3D Point as GeoJSON or WKT :rtype: string """ Model = _getModel(dataset) input_crs = _get_crs(dataset) if geometry.geom_type == "Point": query_point2d = db.session \ .query(ST_Transform(func.ST_SetSRID(func.St_PointFromText(geometry.wkt), 4326), input_crs).label('geom')) \ .subquery() \ .alias('points2d') query_getelev = db.session \ .query(ST_Transform(query_point2d.c.geom, 4326).label('geom'), ST_Value(Model.rast, query_point2d.c.geom, False).label('z')) \ .filter(ST_Intersects(Model.rast, query_point2d.c.geom)) \ .subquery().alias('getelevation') if format_out == 'geojson': query_final = db.session \ .query(func.ST_AsGeoJSON(ST_SnapToGrid(func.ST_MakePoint(ST_X(query_getelev.c.geom), ST_Y(query_getelev.c.geom), query_getelev.c.z.cast(Integer)), coord_precision))) else: query_final = db.session \ .query(func.ST_AsText(ST_SnapToGrid(func.ST_MakePoint(ST_X(query_getelev.c.geom), ST_Y(query_getelev.c.geom), query_getelev.c.z.cast(Integer)), coord_precision))) else: raise InvalidUsage( 400, 4002, "Needs to be a Point, not {}!".format(geometry.geom_type)) try: result = query_final.one() return result[0] except NoResultFound: raise InvalidUsage( 404, 4002, f'{tuple(geometry.coords)[0]} has no elevation value in {dataset}')
def auto_fill(self, zoom): self.zoom = zoom geom_3857 = DBSession.execute(ST_Transform(self.area.geometry, 3857)) \ .scalar() geom_3857 = shape.to_shape(geom_3857) tasks = [] for i in get_tiles_in_geom(geom_3857, zoom): multi = MultiPolygon([i[2]]) geometry = ST_Transform(shape.from_shape(multi, 3857), 4326) tasks.append(Task(i[0], i[1], zoom, geometry)) self.tasks = tasks
def _write_segment(self, way, relations): # get the node geometries and the countries countries = {} prevpoints = (0, 0) points = self.src.osmtables.get_points(way.nodes) # ignore ways where the node geometries are missing if len(points) > 1: line = from_shape(sgeom.LineString(points), self.src_srid) if self.needs_transform: line = ST_Transform(line, self.src.data.c.geom.type.srid) self.thread.conn.execute( self.src.data.insert({ 'nodes': way.nodes, 'ways': way.ways, 'rels': relations, 'geom': line })) #self.db.commit() else: log.warning("empty way: %s", way)
def _load_sources(self): public_wmts = db.session.query( WMTS, ST_Transform(WMTS.view_coverage, 3857)).filter_by(is_public=True).group_by(WMTS).all() for wmts, view_coverage in public_wmts: self.sources['%s_source' % wmts.name] = { 'type': 'tile', 'url': wmts.url, 'grid': 'GoogleMapsCompatible', 'coverage': { 'srs': 'EPSG:3857', 'bbox': list(to_shape(view_coverage).bounds) } } self.caches['%s_cache' % wmts.name] = { 'sources': ['%s_source' % wmts.name], 'grids': ['GoogleMapsCompatible'], 'disable_storage': True } self.layers.append({ 'name': '%s_layer' % wmts.name, 'title': wmts.title, 'sources': ['%s_cache' % wmts.name], 'min_res': self.grid.resolution(wmts.view_level_start), # increase max_res to allow a bit of oversampling 'max_res': self.grid.resolution(wmts.view_level_end) / 2, })
def search_communes(bbox): coords = map(float, bbox.split(",")) bbox_wkb = from_shape(box(*coords), 4326) table = db.table('communes', db.column('insee_com'), db.column('nom_comm'), db.column('x_min'), db.column('y_min'), db.column('x_max'), db.column('y_max')) table.schema = 'geofla' base = db.select( [ table ]) \ .where(ST_Intersects(db.column('geom'), ST_Transform(bbox_wkb, 2154))) \ .order_by(db.desc(db.column("population"))) features = [] for row in db.engine.execute(base): features.append({ "code": row['insee_com'], "name": row['nom_comm'], "text": row['insee_com'] + ' ' + row['nom_comm'], "south_west": { "lon" : round(row['x_min'], 6), "lat": round(row['y_min'], 6) }, "north_east": { "lon": round(row['x_max'], 6), "lat": round(row['y_max'], 6) } }) return features
def __init__(self, x, y, zoom, geometry=None): self.x = x self.y = y self.zoom = zoom if (geometry is None): geometry = self.to_polygon() self.geometry = ST_Transform(elements.WKTElement(geometry.wkt, 3857), 4326)
def __init__(self, x, y, zoom, geometry=None): self.x = x self.y = y self.zoom = zoom if geometry is None: geometry = self.to_polygon() geometry = ST_Transform(shape.from_shape(geometry, 3857), 4326) self.geometry = geometry
def auto_fill(self, zoom): self.zoom = zoom geom_3857 = DBSession.execute(ST_Transform(self.area.geometry, 3857)).scalar() geom_3857 = shape.to_shape(geom_3857) tasks = [] for i in get_tiles_in_geom(geom_3857, zoom): tasks.append(Task(i[0], i[1], zoom, i[2])) self.tasks = tasks
def __init__(self, x, y, zoom, geometry=None): self.x = x self.y = y self.zoom = zoom if geometry is None: geometry = self.to_polygon() multipolygon = MultiPolygon([geometry]) geometry = ST_Transform(shape.from_shape(multipolygon, 3857), 4326) self.geometry = geometry self.states.append(TaskState()) self.locks.append(TaskLock())
def project_grid_simulate(request): ''' Returns collection of polygons representing the grid cells to be created. Helpful when creating a new project ''' geometry = request.params['geometry'] tile_size = int(request.params['tile_size']) geoms = parse_geojson(geometry) multipolygon = convert_to_multipolygon(geoms) geometry = shape.from_shape(multipolygon, 4326) geom_3857 = DBSession.execute(ST_Transform(geometry, 3857)).scalar() geom_3857 = shape.to_shape(geom_3857) zoom = get_zoom_for_tile_size(geom_3857, tile_size) found = get_tiles_in_geom(geom_3857, zoom) polygons = [i[2] for i in found] multi = MultiPolygon(polygons) geometry = DBSession.execute( ST_Transform(shape.from_shape(multi, 3857), 4326)).scalar() return FeatureCollection([Feature(geometry=shape.to_shape(geometry))])
def __init__(self, x, y, zoom, geometry=None, properties=None): self.x = x self.y = y self.zoom = zoom if properties is not None: self.extra_properties = unicode(_dumps(properties)) if geometry is None: geometry = self.to_polygon() multipolygon = MultiPolygon([geometry]) geometry = ST_Transform(shape.from_shape(multipolygon, 3857), 4326) self.geometry = geometry self.states.append(TaskState()) self.locks.append(TaskLock())
def wfs_edit_layer(layer=None): form = WFSSearchForm() user = current_user wfs_session = WFSSession.by_active_user_layer(layer, user) if wfs_session: flash(_('external edit in progress')) return redirect(url_for('.wfs_session', layer=layer)) couch = CouchDBBox(current_app.config.get('COUCH_DB_URL'), '%s_%s' % (SystemConfig.AREA_BOX_NAME, user.id)) try: wfs_layers, wfs_layer_token = create_wfs(user, editable_layers=[layer]) except MissingSchemaError: flash(_('layer unknown or without schema')) abort(404) features = [feature for feature in couch.iter_layer_features(current_app.config.get('USER_READONLY_LAYER')) if isinstance(feature['geometry'], dict)] data_extent = couch.layer_extent(layer) if not data_extent: data_extent = couch.layer_extent(current_app.config.get('USER_READONLY_LAYER')) if not data_extent: result = db.session.query(WMTS, ST_Transform(WMTS.view_coverage, 3857)).order_by(desc(WMTS.is_background_layer)).first() if result: data_extent = to_shape(result[1]) titles = dict(couch.get_layer_names()) return render_template( 'maps/wfs.html', form=form, wfs=wfs_layers, layers=WMTS.query.all(), read_only_features=features, read_only_schema=couch.layer_schema(layer)['properties'], read_only_layer_name=current_app.config.get('AREA_BOX_TITLE'), editable_layer=layer, editable_layer_title=titles[layer], data_extent=data_extent.bounds if data_extent else None, user=current_user )
def search_communes(): query = request.args.get('q') if not query: return abort(401) query = query.upper() table = db.table('communes', db.column('insee_com'), db.column('nom_comm'), db.column('x_min'), db.column('y_min'), db.column('x_max'), db.column('y_max')) table.schema = 'geofla' base = db.select( [ table ]) \ .where(db.column('nom_comm').contains(query)) \ .order_by( db.desc(db.column('nom_comm').startswith(query)), db.desc(db.column("population"))) \ .limit(GEOTAGS_GAZETTEER_MAX_RESULTS) # Add BBOX support # http://localhost:5000/v1/search/communes?q=BO&bbox=-1.4845,44.5004,0.3021,45.1539 bbox = request.args.get('bbox') if bbox: coords = map(float, bbox.split(",")) bbox_wkb = from_shape(box(*coords), 4326) base = base.where( ST_Intersects(db.column('geom'), ST_Transform(bbox_wkb, 2154))) features = [] # TODO Order by distance to query location for row in db.engine.execute(base): features.append({ "code": row['insee_com'], "text": row['insee_com'] + ' ' + row['nom_comm'], "south_west": { "lon": round(row['x_min'], 6), "lat": round(row['y_min'], 6) }, "north_east": { "lon": round(row['x_max'], 6), "lat": round(row['y_max'], 6) } }) return jsonify({ "max_results": GEOTAGS_GAZETTEER_MAX_RESULTS, "results": features })
def __init__(self, meta, name, osmtables, subset=None, change=None, column_geom='geom', geom_change=None): super().__init__(meta, name, osmtables.node, subset=subset, change=change) # need a geometry column if isinstance(column_geom, Column): self.column_geom = column_geom srid = column_geom.type.srid else: srid = meta.info.get('srid', self.src.data.c.geom.type.srid) self.column_geom = Column(column_geom, Geometry('POINT', srid=srid)) self.data.append_column(self.column_geom) # add an additional transform to the insert statement if the srid changes params = {} for c in self.data.c: if c == self.column_geom: # XXX This ugly from_shape hack is here to be able to inject # the geometry into the compiled expression later. This can't # be the right way to go about this. Better ideas welcome. if self.src.data.c.geom.type.srid != srid: params[c.name] = ST_Transform( from_shape(Point(0, 0), srid=0), self.column_geom.type.srid) else: params[c.name] = from_shape(Point(0, 0), srid=0) else: params[c.name] = bindparam(c.name) self.stm_insert = self.stm_insert.values(params) # the table to remember geometry changes self.geom_change = geom_change
def project_new_grid(request): _ = request.translate user_id = authenticated_userid(request) user = DBSession.query(User).get(user_id) try: project = Project( _(u'Untitled project'), user ) DBSession.add(project) DBSession.flush() tile_size = int(request.params['tile_size']) geometry = request.params['geometry'] geoms = parse_geojson(geometry) multipolygon = convert_to_multipolygon(geoms) geometry = shape.from_shape(multipolygon, 4326) geom_3857 = DBSession.execute(ST_Transform(geometry, 3857)).scalar() geom_3857 = shape.to_shape(geom_3857) zoom = get_zoom_for_tile_size(geom_3857, tile_size) project.area = Area(geometry) project.auto_fill(zoom) request.session.flash(_("Project #${project_id} created successfully", mapping={'project_id': project.id}), 'success') return HTTPFound(location=route_path('project_edit', request, project=project.id)) except Exception, e: msg = _("Sorry, could not create the project. <br />%s") % e.message request.session.flash(msg, 'alert') raise HTTPFound(location=route_path('project_new', request))
def create(self, user_token, layer): from gbi_server.model import User from gbi_server.model import WMTS from gbi_server.extensions import db user = User.by_authproxy_token(user_token) if not user: raise InvalidUserToken() result = db.session.query(WMTS, ST_Transform( WMTS.view_coverage, 3857)).filter_by(name=layer).first() if result: wmts, view_coverage = result if wmts and wmts.is_public: return to_shape(view_coverage) if user.is_customer: couch_url = self.couchdb_url couchdb = CouchDBBox( couch_url, '%s_%s' % (SystemConfig.AREA_BOX_NAME, user.id)) geom = couchdb.layer_extent(self.geometry_layer) return optimize_geometry(geom) if geom else None elif user.is_service_provider: couch_url = self.couchdb_url couchdb = CouchDBBox( couch_url, '%s_%s' % (SystemConfig.AREA_BOX_NAME, user.id)) geom = couchdb.layer_extent() return optimize_geometry(geom) if geom else None elif user.is_admin or user.is_consultant: # permit access to everything return box(-20037508.3428, -20037508.3428, 20037508.3428, 20037508.3428) return None
def __init__(self, meta, name, osmtables, subset=None, change=None, column_geom='geom', geom_change=None): super().__init__(meta, name, osmtables.node, subset=subset, change=change) # need a geometry column if isinstance(column_geom, Column): self.column_geom = column_geom srid = column_geom.type.srid else: srid = meta.info.get('srid', self.src.data.c.geom.type.srid) self.column_geom = Column(column_geom, Geometry('POINT', srid=srid)) self.data.append_column(self.column_geom) # add an additional transform to the insert statement if the srid changes params = {} for c in self.data.c: if c == self.column_geom and self.src.data.c.geom.type.srid != srid: geomparam = bindparam(c.name, type_=self.column_geom.type) params[c.name] = ST_Transform(geomparam, self.column_geom.type.srid) else: params[c.name] = bindparam(c.name) self.stm_insert = self.stm_insert.values(params) # the table to remember geometry changes self.geom_change = geom_change
def transform_point(point, target_projection): return ST_Transform(point, int(target_projection))
license = License() license.id = l.id license.name = l.name license.description = l.description license.plain_text = l.plain_text session_v2.add(license) success("License %s - \"%s\" successfully imported" % (l.id, l.name)) session_v2.flush() header("Importing jobs and tasks") for job in session_v1.query(jobs): with transaction.manager: geometry = shapely.wkt.loads(job.geometry) geometry = ST_Transform(shape.from_shape(geometry, 3857), 4326) area = Area(geometry) session_v2.add(area) project = Project(job.title) project.id = job.id project.area = area project.zoom = job.zoom project.last_update = job.last_update project.description = job.description project.short_description = job.short_description project.private = job.is_private project.instructions = job.workflow project.per_task_instructions = job.task_extra project.imagery = job.imagery if job.imagery != 'None' else None project.license_id = job.license_id
if user.email != log_record['user']: json_abort(401, 'user token does not match user email') time = log_record['time'] action = log_record['action'] except KeyError, ex: json_abort(400, 'missing %s in log record' % ex) log = Log(user=user, time=time, action=action) if 'geometry' in log_record: if log_record['geometry']['type'] != 'MultiPolygon': json_abort(400, "geometry not a MultiPolygon") geom = asShape(log_record['geometry']) wkb = from_shape(geom, srid=3857) log.geometry = ST_Transform(wkb, 4326) log.source = log_record.get('source') log.layer = log_record.get('layer') log.zoom_level_start = log_record.get('zoom_level_start') log.zoom_level_end = log_record.get('zoom_level_end') log.refreshed = log_record.get('refreshed') log.mapping = log_record.get('mapping') log.format = log_record.get('format') log.srs = log_record.get('srs') try: db.session.add(log) db.session.commit() except DataError, ex: # invalid datatype, e.g. string instead of integer
def line_elevation(geometry, format_out, dataset): """ Performs PostGIS query to enrich a line geometry. :param geometry: Input 2D line to be enriched with elevation :type geometry: Shapely geometry :param format_out: Specifies output format. One of ['geojson', 'polyline', 'encodedpolyline'] :type format_out: string :param dataset: Elevation dataset to use for querying :type dataset: string :raises InvalidUsage: internal HTTP 500 error with more detailed description. :returns: 3D line as GeoJSON or WKT :rtype: string """ Model = _getModel(dataset) input_crs = _get_crs(dataset) if geometry.geom_type == 'LineString': query_points2d = db.session\ .query(ST_Transform(func.ST_SetSRID(ST_DumpPoints(geometry.wkt).geom, 4326), input_crs) \ .label('geom')) \ .subquery().alias('points2d') query_getelev = db.session \ .query(ST_Transform(query_points2d.c.geom, 4326).label('geom'), ST_Value(Model.rast, query_points2d.c.geom, False).label('z')) \ .filter(ST_Intersects(Model.rast, query_points2d.c.geom)) \ .subquery().alias('getelevation') query_points3d = db.session \ .query(func.ST_MakePoint(ST_X(query_getelev.c.geom), ST_Y(query_getelev.c.geom), query_getelev.c.z.cast(Integer) ).label('geom')) \ .subquery().alias('points3d') if format_out == 'geojson': # Return GeoJSON directly in PostGIS query_final = db.session \ .query(func.ST_AsGeoJson(func.ST_MakeLine(ST_SnapToGrid(query_points3d.c.geom, coord_precision)))) else: # Else return the WKT of the geometry query_final = db.session \ .query(func.ST_AsText(func.ST_MakeLine(ST_SnapToGrid(query_points3d.c.geom, coord_precision)))) else: raise InvalidUsage( 400, 4002, "Needs to be a LineString, not a {}!".format(geometry.geom_type)) try: result = query_final.one() except NoResultFound: raise InvalidUsage( 404, 4002, f'{tuple(geometry.coords)[0]} has no elevation value in {dataset}') return result[0]
def get_context_document(): init_user_boxes(g.user, current_app.config.get('COUCH_DB_URL')) wmts_sources = db.session.query( WMTS, ST_AsGeoJSON(ST_Transform(WMTS.view_coverage, 3857))).order_by( desc(WMTS.is_background_layer)).all() wms_sources = db.session.query( WMS, ST_AsGeoJSON(ST_Transform(WMS.view_coverage, 3857))).order_by( desc(WMS.is_background_layer)).all() wfs_sources = db.session.query(WFS).all() response = { "version": "0.2", "portal": { "prefix": current_app.config['PORTAL_PREFIX'], "title": current_app.config['PORTAL_TITLE'], }, "wmts_sources": [], "wms_sources": [], "wfs_sources": [], "couchdb_sources": [], } couchdb = CouchDBBox(current_app.config['COUCH_DB_URL'], '%s_%s' % (SystemConfig.AREA_BOX_NAME, g.user.id)) for source in wmts_sources: wmts, view_coverage = source geom = json.loads(view_coverage) response['wmts_sources'].append({ "name": wmts.name, "title": wmts.title, "url": wmts.client_url(external=True), "format": wmts.format, "overlay": wmts.is_overlay, "username": wmts.username, "password": wmts.password, "is_public": wmts.is_public, "is_protected": wmts.is_protected, "is_background_layer": wmts.is_background_layer, "max_tiles": wmts.max_tiles, "view_restriction": { "zoom_level_start": wmts.view_level_start, "zoom_level_end": wmts.view_level_end, "geometry": geom }, "download_restriction": { "zoom_level_start": wmts.view_level_start, "zoom_level_end": wmts.view_level_end, } }) for source in wms_sources: wms, view_coverage = source geom = json.loads(view_coverage) response['wms_sources'].append({ "name": wms.name, "title": wms.title, "url": wms.url, "layer": wms.layer, "format": wms.format, "overlay": wms.is_overlay, "username": wms.username, "password": wms.password, "is_public": wms.is_public, "is_protected": wms.is_protected, "srs": wms.srs, "wms_version": wms.version, "view_restriction": { "zoom_level_start": wms.view_level_start, "zoom_level_end": wms.view_level_end, "geometry": geom }, "download_restriction": { "zoom_level_start": wms.view_level_start, "zoom_level_end": wms.view_level_end, } }) for wfs in wfs_sources: response['wfs_sources'].append({ 'id': wfs.id, 'name': wfs.name, 'layer': wfs.layer, 'host': wfs.host, 'url': wfs.url, 'srs': wfs.srs, 'geometry_field': wfs.geometry, 'feature_ns': wfs.ns_uri, 'typename': wfs.ns_prefix, 'search_property': wfs.search_property, 'username': wfs.username, 'password': wfs.password, 'is_protected': wfs.is_protected, }) if current_app.config['FEATURE_AREA_BOXES']: response['couchdb_sources'].append({ "name": _('area box'), "url": current_app.config['COUCH_DB_URL'], "dbname": '%s_%s' % (SystemConfig.AREA_BOX_NAME, g.user.id), "username": '******' % g.user.id, "password": g.user.authproxy_token, "writable": True, "dbname_user": SystemConfig.AREA_BOX_NAME_LOCAL, }) if current_app.config['FEATURE_DOC_BOXES']: if g.user.is_consultant: response['couchdb_sources'].append({ "name": _('file box'), "url": current_app.config['COUCH_DB_URL'], "dbname": '%s_%s' % (SystemConfig.FILE_BOX_NAME, g.user.id), "username": '******' % g.user.id, "password": g.user.authproxy_token, "writable": True, "dbname_user": SystemConfig.FILE_BOX_NAME_LOCAL, }) else: response['couchdb_sources'].append({ "name": _('consultant box'), "url": current_app.config['COUCH_DB_URL'], "dbname": '%s_%s' % (SystemConfig.DOWNLOAD_BOX_NAME, g.user.id), "username": '******' % g.user.id, "password": g.user.authproxy_token, "writable": False, "dbname_user": SystemConfig.DOWNLOAD_BOX_NAME_LOCAL, }) response['couchdb_sources'].append({ "name": _('uploadbox'), "url": current_app.config['COUCH_DB_URL'], "dbname": '%s_%s' % (SystemConfig.UPLOAD_BOX_NAME, g.user.id), "username": '******' % g.user.id, "password": g.user.authproxy_token, "writable": True, "dbname_user": SystemConfig.UPLOAD_BOX_NAME_LOCAL, }) if current_app.config['PARCEL_SEARCH_DATABASE_URI']: response['parcel_search_url'] = url_for('search.query', token=g.user.authproxy_token, _external=True) response['logging'] = { 'url': url_for('logserv.log', user_token=g.user.authproxy_token, _external=True), } response['update_coverage'] = { 'url': url_for('authproxy.update_download_coverage', user_token=g.user.authproxy_token, _external=True), } response['user'] = { 'email': g.user.email, 'type': g.user.type, 'type_name': g.user.type_name, } return json.dumps(response)
def sanitize_geom(val): return ST_RemoveRepeatedPoints(ST_Force2D(ST_Transform(val, 2056)), 0.002)