def setGeospatial(self, item, geospatial, params): for k, v in six.viewitems(geospatial): if '.' in k or k[0] == '$': raise RestException('Geospatial key name %s must not contain a' ' period or begin with a dollar sign.' % k) if v: try: GeoJSON.to_instance(v, strict=True) except ValueError: raise RestException('Geospatial field with key %s does not' ' contain valid GeoJSON: %s' % (k, v)) if GEOSPATIAL_FIELD not in item: item[GEOSPATIAL_FIELD] = dict() item[GEOSPATIAL_FIELD].update(six.viewitems(geospatial)) keys = [ k for k, v in six.viewitems(item[GEOSPATIAL_FIELD]) if v is None ] for key in keys: del item[GEOSPATIAL_FIELD][key] item = self.model('item').updateItem(item) return self._filter(item)
def intersects(self, params): """ Search for items that intersects with a GeoJSON object. :param params: parameters to the API call, including 'field' and 'geometry'. :type params: dict[str, unknown] :returns: filtered fields of the matching items with geospatial data appended to the 'geo' field of each item. :rtype: list[dict[str, unknown]] :raise RestException: on malformed API call. """ self.requireParams(('field', 'geometry'), params) try: geometry = bson.json_util.loads(params['geometry']) GeoJSON.to_instance(geometry, strict=True) except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'geometry'" " parameter.") if params['field'][:3] == '%s.' % GEOSPATIAL_FIELD: field = params['field'].strip() else: field = '%s.%s' % (GEOSPATIAL_FIELD, params['field'].strip()) query = {field: {'$geoIntersects': {'$geometry': geometry}}} limit, offset, sort = self.getPagingParameters(params, 'lowerName') return self._find(query, limit, offset, sort)
def create(self, folder, geoJSON): try: GeoJSON.to_instance(geoJSON, strict=True) except ValueError: raise RestException('Invalid GeoJSON passed in request body.') if geoJSON['type'] == 'Feature': features = [geoJSON] elif geoJSON['type'] == 'FeatureCollection': features = geoJSON['features'] else: raise RestException('GeoJSON feature or feature collection must be ' 'passed in request body.') data = [] for feature in features: properties = feature['properties'] if 'name' not in properties: raise RestException("All GeoJSON features must contain a" " property named 'name'.") name = properties['name'] del properties['name'] if 'description' in properties: description = properties['description'] del properties['description'] else: description = '' for key in properties: if not len(key): raise RestException('Property names must be at least one' ' character long.') if '.' in key or key[0] == '$': raise RestException('The property name %s must not contain' ' a period or begin with a dollar sign.' % key) data.append({'name': name, 'description': description, 'metadata': properties, 'geometry': feature['geometry']}) user = self.getCurrentUser() items = [] for datum in data: newItem = Item().createItem( folder=folder, name=datum['name'], creator=user, description=datum['description']) Item().setMetadata(newItem, datum['metadata']) newItem[GEOSPATIAL_FIELD] = {'geometry': datum['geometry']} newItem = Item().updateItem(newItem) items.append(newItem) return items
def create(self, folder, geoJSON): try: GeoJSON.to_instance(geoJSON, strict=True) except ValueError: raise RestException('Invalid GeoJSON passed in request body.') if geoJSON['type'] == 'Feature': features = [geoJSON] elif geoJSON['type'] == 'FeatureCollection': features = geoJSON['features'] else: raise RestException('GeoJSON feature or feature collection must be ' 'passed in request body.') data = [] for feature in features: properties = feature['properties'] if 'name' not in properties: raise RestException("All GeoJSON features must contain a" " property named 'name'.") name = properties['name'] del properties['name'] if 'description' in properties: description = properties['description'] del properties['description'] else: description = '' for key in properties: if not len(key): raise RestException('Property names must be at least one' ' character long.') if '.' in key or key[0] == '$': raise RestException('The property name %s must not contain' ' a period or begin with a dollar sign.' % key) data.append({'name': name, 'description': description, 'metadata': properties, 'geometry': feature['geometry']}) user = self.getCurrentUser() items = [] for datum in data: newItem = self.model('item').createItem( folder=folder, name=datum['name'], creator=user, description=datum['description']) self.model('item').setMetadata(newItem, datum['metadata']) newItem[GEOSPATIAL_FIELD] = {'geometry': datum['geometry']} newItem = self.model('item').updateItem(newItem) items.append(newItem) return [self._filter(item) for item in items]
def _getGeometry(self, geometry): try: GeoJSON.to_instance(geometry, strict=True) if geometry['type'] != 'Point': raise ValueError return geometry except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'geometry' parameter.")
def load_svg(self, path): with open(path) as file: svg = SVG(file.read()) self.svg = svg self.geojson = GeoJSON(self.svg) self.layer_output = list(self.svg.get_layers()) self.update_result() self.ui.load_preview(path) layers = self.svg.get_layers() self.ui.load_layers(layers)
def _getGeometry(self, params): try: geometry = bson.json_util.loads(params['geometry']) GeoJSON.to_instance(geometry, strict=True) if geometry['type'] != 'Point': raise ValueError return geometry except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'geometry'" " parameter.")
def intersects(self, field, geometry, limit, offset, sort): try: GeoJSON.to_instance(geometry, strict=True) except (TypeError, ValueError): raise RestException( "Invalid GeoJSON passed as 'geometry' parameter.") if field[:3] != '%s.' % GEOSPATIAL_FIELD: field = '%s.%s' % (GEOSPATIAL_FIELD, field) query = {field: {'$geoIntersects': {'$geometry': geometry}}} return self._find(query, limit, offset, sort)
def create_route(data): path = data.get('points', []) geo = GeoJSON() for i, _ in enumerate(path[:-1]): if path[i + 1] is None: path[i + 1] = path[i] elif path[i] is not None: route, _ = router.find_route(path[i], path[i + 1]) if route: start, end = route[0], route[-1] geo.add_point(lon=start[0], lat=start[1], props={ 'title': path[i]['tags'].get('name', path[i]['id']) }) geo.add_point(lon=end[0], lat=end[1], props={ 'title': path[i + 1]['tags'].get( 'name', path[i + 1]['id']) }) geo.add_line_string(route, {"style": {"color": next(color)}}) return geo.data
def within(self, field, geometry, center, radius, limit, offset, sort): if geometry is not None: try: GeoJSON.to_instance(geometry, strict=True) if geometry['type'] != 'Polygon': raise ValueError except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'geometry' parameter.") condition = { '$geometry': geometry } elif center is not None and radius is not None: try: radius /= self._RADIUS_OF_EARTH if radius < 0.0: raise ValueError except ValueError: raise RestException("Parameter 'radius' must be a number.") try: GeoJSON.to_instance(center, strict=True) if center['type'] != 'Point': raise ValueError except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'center' parameter.") condition = { '$centerSphere': [center['coordinates'], radius] } else: raise RestException("Either parameter 'geometry' or both parameters" " 'center' and 'radius' are required.") if field[:3] != '%s.' % GEOSPATIAL_FIELD: field = '%s.%s' % (GEOSPATIAL_FIELD, field) query = { field: { '$geoWithin': condition } } return self._find(query, limit, offset, sort)
def update_features( self, features: GeoJSON, # must be a feature collection add_tags: Optional[List[str]] = None, remove_tags: Optional[List[str]] = None, ) -> GeoJSON: """ Update GeoJSON features in this space. :param features: A JSON object describing one or more features to modify. :param add_tags: A list of strings describing tags to be added to the features. :param remove_tags: A list of strings describing tags to be removed from the features. :return: A GeoJSON representing a feature collection. """ space_id = self.info["id"] res = self.api.post_space_features( space_id=space_id, data=features, addTags=add_tags, removeTags=remove_tags, ) return GeoJSON(res)
def update_feature( self, feature_id: str, data: dict, add_tags: Optional[List[str]] = None, remove_tags: Optional[List[str]] = None, ) -> GeoJSON: """ Update one GeoJSON feature with given ID in this space. :param feature_id: A string with the ID of the feature to be modified. :param data: A JSON object describing the feature to be changed. :param add_tags: A list of strings describing tags to be added to the feature. :param remove_tags: A list of strings describing tags to be removed from the feature. :return: A GeoJSON representing a feature. """ res = self.api.patch_space_feature( space_id=self.info["id"], feature_id=feature_id, data=data, addTags=add_tags, removeTags=remove_tags, ) return GeoJSON(res)
def update(self, request, response, id): """ Read the GeoJSON feature from the request body and update the corresponding object in the database. """ if self.readonly: abort(403) obj = self.Session.query(self.mapped_class).get(id) if obj is None: abort(404) content = request.environ['wsgi.input'].read( int(request.environ['CONTENT_LENGTH'])) factory = lambda ob: GeoJSON.to_instance(ob) feature = loads(content, object_hook=factory) if not isinstance(feature, Feature): abort(400) if self.before_update is not None: self.before_update(request, feature, obj) self.__copy_attributes(feature, obj) # We call flush, create the feature, and then commit. Commit expires # the session, so we create the feature before commit to avoid SELECT # queries in toFeature. self.Session.flush() feature = obj.toFeature() self.Session.commit() response.status = 201 return feature
def create(self, request, response): """ Read the GeoJSON feature collection from the request body and create new objects in the database. """ if self.readonly: response.status_code = 403 return content = request.environ['wsgi.input'].read(int(request.environ['CONTENT_LENGTH'])) factory = lambda ob: GeoJSON.to_instance(ob) collection = loads(content, object_hook=factory) if not isinstance(collection, FeatureCollection): response.status_code = 400 return objects = [] for feature in collection.features: create = False obj = None if self.before_create is not None: self.before_create(request, feature) if isinstance(feature.id, int): obj = self.Session.query(self.mapped_class).get(feature.id) if obj is None: obj = self.mapped_class() obj.geometry = asShape(feature.geometry) create = True for key in feature.properties: obj[key] = feature.properties[key] if create: self.Session.save(obj) objects.append(obj) self.Session.commit() response.status_code = 201 if len(objects) > 0: return dumps(FeatureCollection([o.toFeature() for o in objects])) return
def extract_geojson_obj(self, json_dict): """Extract geojson from a defined json key""" try: if isinstance(json_dict, dict): val_inst = GeoJSON.to_instance(json_dict) return val_inst except KeyError as e: raise Exception(e)
def intersects(self, field, geometry, limit, offset, sort): try: GeoJSON.to_instance(geometry, strict=True) except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'geometry' parameter.") if field[:3] != '%s.' % GEOSPATIAL_FIELD: field = '%s.%s' % (GEOSPATIAL_FIELD, field) query = { field: { '$geoIntersects': { '$geometry': geometry } } } return self._find(query, limit, offset, sort)
def setGeospatial(self, item, params): """ Set geospatial data on an item. :param item: item on which to set geospatial data. :type item: dict[str, unknown] :param params: parameters to the API call, unused. :type params: dict[str, unknown] :return: filtered fields of the item with geospatial data appended to its 'geo' field. :rtype : dict[str, unknown] :raise RestException: on malformed, forbidden, or unauthorized API call. """ try: geospatial = json.load(cherrypy.request.body) except ValueError: raise RestException('Invalid JSON passed in request body.') for k, v in geospatial.items(): if '.' in k or k[0] == '$': raise RestException('Geospatial key name {} must not contain a' ' period or begin with a dollar sign.' .format(k)) if v: try: GeoJSON.to_instance(v, strict=True) except ValueError: raise RestException('Geospatial field with key {} does not' ' contain valid GeoJSON: {}' .format(k, v)) if GEOSPATIAL_FIELD not in item: item[GEOSPATIAL_FIELD] = dict() item[GEOSPATIAL_FIELD].update(geospatial.items()) keys = [k for k, v in item[GEOSPATIAL_FIELD].iteritems() if v is None] for key in keys: del item[GEOSPATIAL_FIELD][key] item = self.model('item').updateItem(item) return self._filter(item)
def setGeospatial(self, item, params): """ Set geospatial data on an item. :param item: item on which to set geospatial data. :type item: dict[str, unknown] :param params: parameters to the API call, unused. :type params: dict[str, unknown] :return: filtered fields of the item with geospatial data appended to its 'geo' field. :rtype : dict[str, unknown] :raise RestException: on malformed, forbidden, or unauthorized API call. """ try: geospatial = json.load(cherrypy.request.body) except ValueError: raise RestException('Invalid JSON passed in request body.') for k, v in geospatial.items(): if '.' in k or k[0] == '$': raise RestException( 'Geospatial key name {} must not contain a' ' period or begin with a dollar sign.'.format(k)) if v: try: GeoJSON.to_instance(v, strict=True) except ValueError: raise RestException('Geospatial field with key {} does not' ' contain valid GeoJSON: {}'.format( k, v)) if GEOSPATIAL_FIELD not in item: item[GEOSPATIAL_FIELD] = dict() item[GEOSPATIAL_FIELD].update(geospatial.items()) keys = [k for k, v in item[GEOSPATIAL_FIELD].iteritems() if v is None] for key in keys: del item[GEOSPATIAL_FIELD][key] item = self.model('item').updateItem(item) return self._filter(item)
def add_features_csv( self, path: str, lon_col: str, lat_col: str, id_col: str, alt_col: str = "", delimiter: str = ",", ): """ Add features in space from a csv file. :param path: Path to csv file. :param lon_col: Name of the column for longitude coordinates. :param lat_col: Name of the column for latitude coordinates. :param id_col: Name of the column for feature id's. :param alt_col: Name of the column for altitude, if not provided altitudes with default value 0.0 will be added. :param delimiter: delimiter which should be used to process the csv file. :raises Exception: If values of params `lat_col`, `lon_col`, `id_col` do not match with column names in csv file. """ feature: dict = { "type": "Feature", "geometry": { "type": "Point", "coordinates": [0, 0, 0] }, "properties": {}, } with open(path) as f: input_file = csv.DictReader(f, delimiter=delimiter) columns = input_file.fieldnames if (lon_col not in columns # type: ignore or lat_col not in columns # type: ignore or id_col not in columns # type: ignore or (alt_col not in columns if alt_col else False) # type: ignore ): raise Exception( "The longitude, latitude coordinates and id column name " "should match with `lon_col`, `lat_col`," " `id_col` and `alt_col` parameter value") for row in input_file: feature["geometry"]["coordinates"] = [ row[lon_col], row[lat_col], row[alt_col] if alt_col else 0.0, ] for field in columns: # type: ignore if (field != lon_col and field != lat_col and field != id_col): feature["properties"][field] = row[field] self.add_feature(feature_id=row[id_col], data=GeoJSON(feature))
def get_feature(self, feature_id: str) -> GeoJSON: """ Retrieve one GeoJSON feature with given ID from this space. :param feature_id: Feature id which is to fetched. :return: A GeoJSON representing a feature with the specified feature ID inside the space. """ res = self.api.get_space_feature(space_id=self.info["id"], feature_id=feature_id) return GeoJSON(res)
def get_features(self, feature_ids: List[str]) -> GeoJSON: """ Retrieve one GeoJSON feature with given ID from this space. :param feature_ids: A list of feature_ids. :return: A feature collection with all features inside the specified space. """ res = self.api.get_space_features(space_id=self.info["id"], feature_ids=feature_ids) return GeoJSON(res)
def setGeospatial(self, item, params): """ Set geospatial data on an item. :param item: item on which to set geospatial data. :type item: dict[str, unknown] :param params: parameters to the API call, unused. :type params: dict[str, unknown] :returns: filtered fields of the item with geospatial data appended to its 'geo' field. :rtype : dict[str, unknown] :raise RestException: on malformed, forbidden, or unauthorized API call. """ geospatial = self.getBodyJson() for k, v in six.viewitems(geospatial): if '.' in k or k[0] == '$': raise RestException('Geospatial key name %s must not contain a' ' period or begin with a dollar sign.' % k) if v: try: GeoJSON.to_instance(v, strict=True) except ValueError: raise RestException('Geospatial field with key %s does not' ' contain valid GeoJSON: %s' % (k, v)) if GEOSPATIAL_FIELD not in item: item[GEOSPATIAL_FIELD] = dict() item[GEOSPATIAL_FIELD].update(six.viewitems(geospatial)) keys = [ k for k, v in six.viewitems(item[GEOSPATIAL_FIELD]) if v is None ] for key in keys: del item[GEOSPATIAL_FIELD][key] item = self.model('item').updateItem(item) return self._filter(item)
def setGeospatial(self, item, params): """ Set geospatial data on an item. :param item: item on which to set geospatial data. :type item: dict[str, unknown] :param params: parameters to the API call, unused. :type params: dict[str, unknown] :returns: filtered fields of the item with geospatial data appended to its 'geo' field. :rtype : dict[str, unknown] :raise RestException: on malformed, forbidden, or unauthorized API call. """ geospatial = self.getBodyJson() for k, v in six.viewitems(geospatial): if '.' in k or k[0] == '$': raise RestException('Geospatial key name %s must not contain a' ' period or begin with a dollar sign.' % k) if v: try: GeoJSON.to_instance(v, strict=True) except ValueError: raise RestException('Geospatial field with key %s does not' ' contain valid GeoJSON: %s' % (k, v)) if GEOSPATIAL_FIELD not in item: item[GEOSPATIAL_FIELD] = dict() item[GEOSPATIAL_FIELD].update(six.viewitems(geospatial)) keys = [k for k, v in six.viewitems(item[GEOSPATIAL_FIELD]) if v is None] for key in keys: del item[GEOSPATIAL_FIELD][key] item = self.model('item').updateItem(item) return self._filter(item)
def setGeospatial(self, item, geospatial): for k, v in six.viewitems(geospatial): if '.' in k or k[0] == '$': raise RestException('Geospatial key name %s must not contain a' ' period or begin with a dollar sign.' % k) if v: try: GeoJSON.to_instance(v, strict=True) except (ValueError, TypeError): raise RestException('Geospatial field with key %s does not' ' contain valid GeoJSON: %s' % (k, v)) if GEOSPATIAL_FIELD not in item: item[GEOSPATIAL_FIELD] = {} item[GEOSPATIAL_FIELD].update(six.viewitems(geospatial)) keys = [k for k, v in six.viewitems(item[GEOSPATIAL_FIELD]) if v is None] for key in keys: del item[GEOSPATIAL_FIELD][key] return Item().updateItem(item)
def _as_geojson_instance(cls, geojson_dict): try: geojson = GeoJSON.to_instance(geojson_dict, strict=True) except (TypeError, KeyError, UnicodeEncodeError) as ex: raise ValueError( "geometry not recognized as valid GeoJSON ({}): {}".format( str(ex), geojson_dict)) # Shapely cannot handle GeoJSON Features or FeatureCollections if isinstance(geojson, Feature): geojson = geojson.geometry elif isinstance(geojson, FeatureCollection): features = [] for feature in geojson.features: try: features.append( GeoJSON.to_instance(feature, strict=True).geometry) except (TypeError, KeyError, UnicodeEncodeError) as ex: raise ValueError( "feature in FeatureCollection not recognized as valid ({}): {}" .format(str(ex), feature)) geojson = GeometryCollection(features) return geojson
def add_features( self, features: GeoJSON, add_tags: Optional[List[str]] = None, remove_tags: Optional[List[str]] = None, features_size: int = 2000, chunk_size: int = 1, ) -> GeoJSON: """ Add GeoJSON features to this space. As API has a limitation on the size of features, features are divided into chunks, and multiple processes will process those chunks. Each chunk has a number of features based on the value of ``features_size``. Each process handles chunks based on the value of ``chunk_size``. :param features: A JSON object describing one or more features to add. :param add_tags: A list of strings describing tags to be added to the features. :param remove_tags: A list of strings describing tags to be removed from the features. :param features_size: An int representing a number of features to upload at a time. :param chunk_size: Number of chunks each process to handle. The default value is 1, for a large number of features please use `chunk_size` greater than 1 to get better results in terms of performance. :return: A GeoJSON representing a feature collection. """ space_id = self.info["id"] total = 0 if len(features["features"]) > features_size: groups = grouper(features_size, features["features"]) part_func = partial( self._upload_features, add_tags=add_tags, remove_tags=remove_tags, ) with concurrent.futures.ProcessPoolExecutor() as executor: for ft in executor.map(part_func, groups, chunksize=chunk_size): logger.info(f"features processed: {ft}") total += ft logger.info(f"{total} features are uploaded on space: {space_id}") else: res = self.api.put_space_features( space_id=space_id, data=features, addTags=add_tags, removeTags=remove_tags, ) return GeoJSON(res)
def main(start, end, coords, coorde): router = Router('./map.osm') print('Would you like to search by name or by coordinates?') print('(1) Name') print('(2) Coordinates') index = click.prompt('', type=int) start_point, end_point = None, None if index == 1: if not start: start = click.prompt('What is your starting point?') start_point = router.find_point_by_name_cli(start) if not start_point: return print('Starting point not set') if not end: end = click.prompt('What is your destination?') end_point = router.find_point_by_name_cli(end) if not end_point: return print('Destination not set') elif index == 2: if not coords: coords = get_float_tuple('What is your starting point? [format="lat lon"]') start_point = router.find_point_by_coords(dict(lat=coords[0], lon=coords[1])) if not coorde: coorde = get_float_tuple('What is your destination? [format="lat lon"]').split(' ') end_point = router.find_point_by_coords(dict(lat=coorde[1], lon=coorde[1])) else: print('Invalid input') return route, _ = router.find_route(start_point, end_point) if route: print("Route found") geo = GeoJSON() geo.add_line_string(route) geo.add_point(lon=route[0][0], lat=route[0][1], props={ "title": "Start" }) geo.add_point(lon=route[-1][0], lat=route[-1][1], props={ "title": "End" }) js_file = '' with open('./map.template.js',encoding='utf-8') as f: js_file = Template(f.read()).safe_substitute(geojson=geo.data) f.close() with open('./map_client/index.js', 'w', encoding='utf-8') as f: f.write(js_file) f.close() webbrowser.open_new_tab(Path('./map_client/index.html').resolve().as_uri())
def intersects(self, params): """ Search for items that intersects with a GeoJSON object. :param params: parameters to the API call, including 'field' and 'geometry'. :type params: dict[str, unknown] :returns: filtered fields of the matching items with geospatial data appended to the 'geo' field of each item. :rtype: list[dict[str, unknown]] :raise RestException: on malformed API call. """ self.requireParams(('field', 'geometry'), params) try: geometry = bson.json_util.loads(params['geometry']) GeoJSON.to_instance(geometry, strict=True) except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'geometry'" " parameter.") if params['field'][:3] == '{}.'.format(GEOSPATIAL_FIELD): field = params['field'].strip() else: field = '{}.{}'.format(GEOSPATIAL_FIELD, params['field'].strip()) query = { field: { '$geoIntersects': { '$geometry': geometry } } } limit, offset, sort = self.getPagingParameters(params, 'lowerName') return self._find(query, limit, offset, sort)
def create_geom_filter(request, mapped_class, **kwargs): """Create MapFish geometry filter based on the request params. Either a box or within or geometry filter, depending on the request params. Additional named arguments are passed to the spatial filter.""" tolerance = 0 if 'tolerance' in request.params: tolerance = float(request.params['tolerance']) epsg = None if 'epsg' in request.params: epsg = int(request.params['epsg']) box = None if 'bbox' in request.params: box = request.params['bbox'] geometry = None if box is not None: box = map(float, box.split(',')) geometry = Polygon(((box[0], box[1]), (box[0], box[3]), (box[2], box[3]), (box[2], box[1]), (box[0], box[1]))) elif 'lon' and 'lat' in request.params: geometry = Point(float(request.params['lon']), float(request.params['lat'])) elif 'geometry' in request.params: factory = lambda ob: GeoJSON.to_instance(ob) geometry = loads(request.params['geometry'], object_hook=factory) geometry = asShape(geometry) if geometry is None: return None geom_column = mapped_class.geometry_column() epsg = geom_column.type.srid if epsg is None else epsg if epsg != geom_column.type.srid: geom_column = functions.transform(geom_column, epsg) wkb_geometry = WKBSpatialElement(buffer(geometry.wkb), epsg) if 'additional_params' in kwargs: return functions._within_distance(geom_column, wkb_geometry, tolerance, kwargs['additional_params']) else: return functions._within_distance(geom_column, wkb_geometry, tolerance)
def create_geom_filter(request, mapped_class, **kwargs): """Create MapFish geometry filter based on the request params. Either a box or within or geometry filter, depending on the request params. Additional named arguments are passed to the spatial filter.""" tolerance = 0 if 'tolerance' in request.params: tolerance = float(request.params['tolerance']) epsg = None if 'epsg' in request.params: epsg = int(request.params['epsg']) box = None if 'bbox' in request.params: box = request.params['bbox'] geometry = None if box is not None: box = map(float, box.split(',')) geometry = Polygon( ((box[0], box[1]), (box[0], box[3]), (box[2], box[3]), (box[2], box[1]), (box[0], box[1]))) elif 'lon' and 'lat' in request.params: geometry = Point(float(request.params['lon']), float(request.params['lat'])) elif 'geometry' in request.params: factory = lambda ob: GeoJSON.to_instance(ob) geometry = loads(request.params['geometry'], object_hook=factory) geometry = asShape(geometry) if geometry is None: return None geom_column = mapped_class.geometry_column() epsg = geom_column.type.srid if epsg is None else epsg if epsg != geom_column.type.srid: geom_column = functions.transform(geom_column, epsg) wkb_geometry = WKBSpatialElement(buffer(geometry.wkb), epsg) if 'additional_params' in kwargs: return functions._within_distance(geom_column, wkb_geometry, tolerance, kwargs['additional_params']) else: return functions._within_distance(geom_column, wkb_geometry, tolerance)
def to_sql_expr(self): if self.type == self.BOX: geometry = self.__box_to_geometry() if self.type == self.WITHIN: geometry = Point(self.values['lon'], self.values['lat']) if self.type == self.GEOMETRY: factory = lambda ob: GeoJSON.to_instance(ob) geometry = loads(self.values['geometry'], object_hook=factory) geometry = asShape(geometry) if self.epsg != self.geom_column.type.srid: geom_column = func.transform(self.geom_column, self.epsg) else: geom_column = self.geom_column tolerance = self.values['tolerance'] pg_geometry = func.geomfromtext(geometry.wkt, self.epsg) return and_(func.expand(pg_geometry, tolerance).op('&&')(geom_column), func.distance(geom_column, pg_geometry) <= tolerance)
def create(self, request, response, execute=True): """ Read the GeoJSON feature collection from the request body and create new objects in the database. """ if self.readonly: abort(403) content = request.environ['wsgi.input'].read( int(request.environ['CONTENT_LENGTH'])) factory = lambda ob: GeoJSON.to_instance(ob) collection = loads(content, object_hook=factory) if not isinstance(collection, FeatureCollection): abort(400) objects = [] for feature in collection.features: create = False obj = None if feature.id is not None: obj = self.Session.query(self.mapped_class).get(feature.id) if self.before_create is not None: self.before_create(request, feature, obj) if obj is None: obj = self.mapped_class() create = True self.__copy_attributes(feature, obj) if create: self.Session.add(obj) objects.append(obj) # We call flush, create the feature collection, and then commit. Commit # expires the session, so we create the feature collection before # commit to avoid SELECT queries in toFeature. if execute: self.Session.flush() collection = None if len(objects) > 0: collection = FeatureCollection([o.toFeature() for o in objects]) if execute: self.Session.commit() response.status = 201 return collection
def create(self, request, response, execute=True): """ Read the GeoJSON feature collection from the request body and create new objects in the database. """ if self.readonly: abort(403) content = request.environ['wsgi.input'].read(int(request.environ['CONTENT_LENGTH'])) factory = lambda ob: GeoJSON.to_instance(ob) collection = loads(content, object_hook=factory) if not isinstance(collection, FeatureCollection): abort(400) objects = [] for feature in collection.features: create = False obj = None if feature.id is not None: obj = self.Session.query(self.mapped_class).get(feature.id) if self.before_create is not None: self.before_create(request, feature, obj) if obj is None: obj = self.mapped_class() create = True self.__copy_attributes(feature, obj) if create: self.Session.add(obj) objects.append(obj) # We call flush, create the feature collection, and then commit. Commit # expires the session, so we create the feature collection before # commit to avoid SELECT queries in toFeature. if execute: self.Session.flush() collection = None if len(objects) > 0: collection = FeatureCollection([o.toFeature() for o in objects]) if execute: self.Session.commit() response.status = 201 return collection
def update(self, request, response, id): """ Read the GeoJSON feature from the request body and update the corresponding object in the database. """ if self.readonly: abort(403) obj = self.Session.query(self.mapped_class).get(id) if obj is None: abort(404) content = request.environ['wsgi.input'].read(int(request.environ['CONTENT_LENGTH'])) factory = lambda ob: GeoJSON.to_instance(ob) feature = loads(content, object_hook=factory) if not isinstance(feature, Feature): abort(400) if self.before_update is not None: self.before_update(request, feature, obj) self.__copy_attributes(feature, obj) # We call flush, create the feature, and then commit. Commit expires # the session, so we create the feature before commit to avoid SELECT # queries in toFeature. self.Session.flush() feature = obj.toFeature() self.Session.commit() response.status = 201 return feature
def update(self, request, response, id): """ Read the GeoJSON feature from the request body and update the corresponding object in the database. """ if self.readonly: response.status_code = 403 return obj = self.Session.query(self.mapped_class).get(id) if obj is None: response.status_code = 404 return content = request.environ['wsgi.input'].read(int(request.environ['CONTENT_LENGTH'])) factory = lambda ob: GeoJSON.to_instance(ob) feature = loads(content, object_hook=factory) if not isinstance(feature, Feature): response.status_code = 400 return response if self.before_update is not None: self.before_update(request, feature) obj.geometry = asShape(feature.geometry) for key in feature.properties: obj[key] = feature.properties[key] self.Session.commit() response.status_code = 201 return dumps(obj.toFeature())
def create(self, params): """ Create new items from a GeoJSON feature or feature collection. All GeoJSON features must contain a property named 'name' from which the name of each created item is taken. :param params: parameters to the API call, including 'folderId' and 'geoJSON'. :type params: dict[str, unknown] :returns: filtered fields of the created items with properties appended to the 'meta' field and geospatial data appended to the 'geo' field of each item. :rtype: list[dict[str, unknown]] :raise RestException: on malformed, forbidden, or unauthorized API call. """ self.requireParams(('folderId', 'geoJSON'), params) try: geospatial = bson.json_util.loads(params['geoJSON']) GeoJSON.to_instance(geospatial, strict=True) except ValueError: raise RestException('Invalid GeoJSON passed in request body.') if geospatial['type'] == 'Feature': features = [geospatial] elif geospatial['type'] == 'FeatureCollection': features = geospatial['features'] else: raise RestException('GeoJSON feature or feature collection must be ' 'passed in request body.') data = [] for feature in features: properties = feature['properties'] if 'name' not in properties: raise RestException("All GeoJSON features must contain a" " property named 'name'.") name = properties['name'] del properties['name'] if 'description' in properties: description = properties['description'] del properties['description'] else: description = '' for key in properties: if not len(key): raise RestException('Property names must be at least one' ' character long.') if '.' in key or key[0] == '$': raise RestException('The property name {} must not contain' ' a period or begin with a dollar sign.' .format(key)) data.append({'name': name, 'description': description, 'metadata': properties, 'geometry': feature['geometry']}) user = self.getCurrentUser() folder = self.model('folder').load( id=params['folderId'], user=user, level=AccessType.WRITE, exc=True) items = [] for datum in data: newItem = self.model('item').createItem( folder=folder, name=datum['name'], creator=user, description=datum['description']) self.model('item').setMetadata(newItem, datum['metadata']) newItem[GEOSPATIAL_FIELD] = {'geometry': datum['geometry']} newItem = self.model('item').updateItem(newItem) items.append(newItem) return [self._filter(item) for item in items]
def within(self, params): """ Search for items that are entirely within either a GeoJSON polygon or a circular region. Either parameter 'geometry' or both parameters 'center' and 'radius' are required. :param params: parameters to the API call, including 'field' and either 'geometry' or both 'center' and 'radius'. :type params: dict[str, unknown] :returns: filtered fields of the matching items with geospatial data appended to the 'geo' field of each item. :rtype: list[dict[str, unknown]] :raise RestException: on malformed API call. """ self.requireParams(('field',), params) if 'geometry' in params: try: geometry = bson.json_util.loads(params['geometry']) GeoJSON.to_instance(geometry, strict=True) if geometry['type'] != 'Polygon': raise ValueError except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'geometry'" " parameter.") condition = { '$geometry': geometry } elif 'center' in params and 'radius' in params: try: radius = float(params['radius']) / self._RADIUS_OF_EARTH if radius < 0.0: raise ValueError except ValueError: raise RestException("Parameter 'radius' must be a number.") try: center = bson.json_util.loads(params['center']) GeoJSON.to_instance(center, strict=True) if center['type'] != 'Point': raise ValueError except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'center'" " parameter.") condition = { '$centerSphere': [center['coordinates'], radius] } else: raise RestException("Either parameter 'geometry' or both parameters" " 'center' and 'radius' are required.") if params['field'][:3] == '{}.'.format(GEOSPATIAL_FIELD): field = params['field'].strip() else: field = '{}.{}'.format(GEOSPATIAL_FIELD, params['field'].strip()) limit, offset, sort = self.getPagingParameters(params, 'lowerName') query = { field: { '$geoWithin': condition } } return self._find(query, limit, offset, sort)
def bbdb2geo(db, geocoder=None): return GeoJSON(FeatureCollection(list(features(db, geocoder))))
input_text = "" input_path = "json/" + input_file_2 + ".json" file_size = os.path.getsize(input_path) progress = Progress(file_size) progress.progressBar("File2 Loading") with open(input_path, 'r') as f: line = f.readline() while line: progress.tick( len(line) ) input_text += line line = f.readline() dataset_2 = json.loads(input_text) geojson = GeoJSON() output = geojson.getFormat() progress = Progress( len(dataset_1) ) progress.progressBar("Conversioning") for i in range( len(dataset_1) ): if dataset_1[i][5] > threshold_1 and dataset_2[i][5] > threshold_2: red = int( ( log(dataset_1[i][5]) / log(max_1) ) * 255 ) blue = int( ( log(dataset_2[i][5]) / log(max_2) ) * 255 ) color = "rgba(" + str(red) + ", 0, " + str(blue) + ", 0.5)" output["features"].append( geojson.getFeature("Polygon", [[ [dataset_1[i][2], dataset_1[i][1]], [dataset_1[i][2], dataset_1[i][3]], [dataset_1[i][4], dataset_1[i][3]], [dataset_1[i][4], dataset_1[i][1]] ]], { "color": color,
data_source = input() input_text = "" input_path = 'json/' + input_file + '.json' file_size = os.path.getsize(input_path) progress = Progress(file_size) progress.progressBar("File Loading") with open(input_path, 'r') as f: line = f.readline() while line: progress.tick( len(line) ) input_text += line line = f.readline() geojson = GeoJSON() output = geojson.getFormat() dataset = json.loads(input_text) progress = Progress( len(dataset) ) progress.progressBar("Conversioning") for data in dataset: if data[5] > threshold: alpha = log(data[5]) / log(max_value) if (data_source == "twitter"): color = "rgba(255, 0, 0, " + str(alpha) + ")" elif (data_source == "flickr"): color = "rgba(0, 0, 255, " + str(alpha) + ")" output["features"].append( geojson.getFeature("Polygon", [[ [data[2], data[1]], [data[2], data[3]],
def within(self, params): """ Search for items that are entirely within either a GeoJSON polygon or a circular region. Either parameter 'geometry' or both parameters 'center' and 'radius' are required. :param params: parameters to the API call, including 'field' and either 'geometry' or both 'center' and 'radius'. :type params: dict[str, unknown] :returns: filtered fields of the matching items with geospatial data appended to the 'geo' field of each item. :rtype: list[dict[str, unknown]] :raise RestException: on malformed API call. """ self.requireParams(('field', ), params) if 'geometry' in params: try: geometry = bson.json_util.loads(params['geometry']) GeoJSON.to_instance(geometry, strict=True) if geometry['type'] != 'Polygon': raise ValueError except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'geometry'" " parameter.") condition = {'$geometry': geometry} elif 'center' in params and 'radius' in params: try: radius = float(params['radius']) / self._RADIUS_OF_EARTH if radius < 0.0: raise ValueError except ValueError: raise RestException("Parameter 'radius' must be a number.") try: center = bson.json_util.loads(params['center']) GeoJSON.to_instance(center, strict=True) if center['type'] != 'Point': raise ValueError except (TypeError, ValueError): raise RestException("Invalid GeoJSON passed as 'center'" " parameter.") condition = {'$centerSphere': [center['coordinates'], radius]} else: raise RestException( "Either parameter 'geometry' or both parameters" " 'center' and 'radius' are required.") if params['field'][:3] == '%s.' % GEOSPATIAL_FIELD: field = params['field'].strip() else: field = '%s.%s' % (GEOSPATIAL_FIELD, params['field'].strip()) limit, offset, sort = self.getPagingParameters(params, 'lowerName') query = {field: {'$geoWithin': condition}} return self._find(query, limit, offset, sort)
def create(self, params): """ Create new items from a GeoJSON feature or feature collection. All GeoJSON features must contain a property named 'name' from which the name of each created item is taken. :param params: parameters to the API call, including 'folderId' and 'geoJSON'. :type params: dict[str, unknown] :returns: filtered fields of the created items with properties appended to the 'meta' field and geospatial data appended to the 'geo' field of each item. :rtype: list[dict[str, unknown]] :raise RestException: on malformed, forbidden, or unauthorized API call. """ self.requireParams(('folderId', 'geoJSON'), params) try: geospatial = bson.json_util.loads(params['geoJSON']) GeoJSON.to_instance(geospatial, strict=True) except ValueError: raise RestException('Invalid GeoJSON passed in request body.') if geospatial['type'] == 'Feature': features = [geospatial] elif geospatial['type'] == 'FeatureCollection': features = geospatial['features'] else: raise RestException( 'GeoJSON feature or feature collection must be ' 'passed in request body.') data = [] for feature in features: properties = feature['properties'] if 'name' not in properties: raise RestException("All GeoJSON features must contain a" " property named 'name'.") name = properties['name'] del properties['name'] if 'description' in properties: description = properties['description'] del properties['description'] else: description = '' for key in properties: if not len(key): raise RestException('Property names must be at least one' ' character long.') if '.' in key or key[0] == '$': raise RestException('The property name %s must not contain' ' a period or begin with a dollar' ' sign.' % key) data.append({ 'name': name, 'description': description, 'metadata': properties, 'geometry': feature['geometry'] }) user = self.getCurrentUser() folder = self.model('folder').load(id=params['folderId'], user=user, level=AccessType.WRITE, exc=True) items = [] for datum in data: newItem = self.model('item').createItem( folder=folder, name=datum['name'], creator=user, description=datum['description']) self.model('item').setMetadata(newItem, datum['metadata']) newItem[GEOSPATIAL_FIELD] = {'geometry': datum['geometry']} newItem = self.model('item').updateItem(newItem) items.append(newItem) return [self._filter(item) for item in items]
class Controller: def __init__(self): self.ui = UserInterface(self) self.svg = None self.geojson = None self.layer_output = [] self.bounds = [0.0, 0.0, 0.0, 0.0] self.rotation = 0.0 self.last_click = None self.ui.run() def load_svg(self, path): with open(path) as file: svg = SVG(file.read()) self.svg = svg self.geojson = GeoJSON(self.svg) self.layer_output = list(self.svg.get_layers()) self.update_result() self.ui.load_preview(path) layers = self.svg.get_layers() self.ui.load_layers(layers) def set_layer_output(self, layer: str, enable: bool): if enable: self.layer_output.append(layer) else: self.layer_output.remove(layer) def update_boundaries(self, direction: chr, value, update_ui=True): if direction == 'N': self.bounds[0] = value elif direction == 'S': self.bounds[1] = value elif direction == 'E': self.bounds[2] = value elif direction == 'W': self.bounds[3] = value if update_ui: self.ui.set_boundaries(self.bounds) self.update_result() def update_rotation(self, rotation): self.rotation = rotation self.update_result() def update_result(self): print( f'Updating to match the bounds {self.bounds} with {self.rotation}º of rotation.' ) geojson = self.geojson.calculate(self.layer_output, self.bounds, self.rotation) self.ui.set_output(geojson) self.ui.draw_polygons(self.geojson.polygons) def record_click(self, lon: float, lat: float): self.last_click = lon, lat self.ui.set_last_click(lon, lat) def replace_lim(self, direction: chr): if direction in ('N', 'S'): self.update_boundaries(direction, self.last_click[1]) else: self.update_boundaries(direction, self.last_click[0])