예제 #1
0
 def decode_event_path(self, event_path):
     """ decodes an event path, with
         chrono_path tiles as the first
         two characters of each level, with
         the geo tile as the last character
     """
     chrono_prefix = ''
     if self.CHRONO_PREFIX_EVENT_SEP in event_path:
         event_ex = event_path.split(self.CHRONO_PREFIX_EVENT_SEP)
         chrono_prefix = event_ex[0]
         event_path = event_ex[1]
     event_path_list = event_path.split(self.LEVEL_DELIM)
     chrono_path = ''
     geo_path = ''
     for event_tile in event_path_list:
         chrono_path = self.add_to_path(event_tile[0], chrono_path,
                                        self.CHRONO_TILE_DEPTH)
         chrono_path = self.add_to_path(event_tile[1], chrono_path,
                                        self.CHRONO_TILE_DEPTH)
         geo_path = self.add_to_path(event_tile[2], geo_path,
                                     self.GEO_TILE_DEPTH)
     chrono_path = chrono_prefix + chrono_path
     ch = ChronoTile()
     gm = GlobalMercator()
     output = {
         'chrono_path': chrono_path,
         'chrono': ch.decode_path_dates(chrono_path),
         'geo_path': geo_path,
         'geo': gm.quadtree_to_lat_lon(geo_path)
     }
     return output
예제 #2
0
def make_geotile_filter_label(raw_geotile):
    """Parses a raw bbox parameter value to make a filter label
    """
    if configs.REQUEST_OR_OPERATOR in raw_geotile:
        tile_list = raw_geotile.split(configs.REQUEST_OR_OPERATOR)
    else:
        tile_list = [raw_geotile]

    output_list = []
    for tile in tile_list:
        geotile = GlobalMercator()
        coordinates = geotile.quadtree_to_lat_lon(tile)
        if not coordinates:
            label = '[Ignored invalid geospatial tile]'
        else:
            round_level = utilities.estimate_good_coordinate_rounding(
                lon_a=coordinates[0],
                lat_a=coordinates[1],
                lon_b=coordinates[2],
                lat_b=coordinates[3],
            )
            label = 'In the region bounded by: {}, {} (SW) and {}, {} (NE)'.format(
                round(coordinates[0], round_level),
                round(coordinates[1], round_level),
                round(coordinates[2], round_level),
                round(coordinates[3], round_level),
            )
        output_list.append(label)
    output = '; or '.join(output_list)
    return output
예제 #3
0
 def decode_event_path(self, event_path):
     """ decodes an event path, with
         chrono_path tiles as the first
         two characters of each level, with
         the geo tile as the last character
     """
     chrono_prefix = ''
     if self.CHRONO_PREFIX_EVENT_SEP in event_path:
         event_ex = event_path.split(self.CHRONO_PREFIX_EVENT_SEP)
         chrono_prefix = event_ex[0]
         event_path = event_ex[1]
     event_path_list = event_path.split(self.LEVEL_DELIM)
     chrono_path = ''
     geo_path = ''
     for event_tile in event_path_list:
         chrono_path = self.add_to_path(event_tile[0],
                                        chrono_path,
                                        self.CHRONO_TILE_DEPTH)
         chrono_path = self.add_to_path(event_tile[1],
                                        chrono_path,
                                        self.CHRONO_TILE_DEPTH)
         geo_path = self.add_to_path(event_tile[2],
                                     geo_path,
                                     self.GEO_TILE_DEPTH)
     chrono_path = chrono_prefix + chrono_path
     ch = ChronoTile()
     gm = GlobalMercator()
     output = {'chrono_path': chrono_path,
               'chrono': ch.decode_path_dates(chrono_path),
               'geo_path': geo_path,
               'geo': gm.quadtree_to_lat_lon(geo_path)}
     return output
예제 #4
0
def quadtree_to_lat_lon(request):
    """ Converts a quadtree tile to WGS-84 lat / lon coordinates in different formats """
    lat_lon = None
    gm = GlobalMercator()
    if request.GET.get('tile') is not None:
        tile = request.GET['tile']
        try:
            lat_lon = gm.quadtree_to_lat_lon(tile)
        except:
            lat_lon = None
    if lat_lon is not None:
        # default to json format with lat, lon dictionary object
        lat_lon_dict = LastUpdatedOrderedDict()
        lat_lon_dict['lat'] = lat_lon[0]
        lat_lon_dict['lon'] = lat_lon[1]
        output = json.dumps(lat_lon_dict,
                            ensure_ascii=False,
                            indent=4)
        content_type='application/json; charset=utf8'
        if request.GET.get('format') is not None:
            # client requested another format, give it if recognized
            if request.GET['format'] == 'geojson':
                # geojson format, with longitude then latitude
                output = json.dumps(([lat_lon[1], lat_lon[0]]),
                                    ensure_ascii=False,
                                    indent=4)
                content_type='application/json; charset=utf8'
            elif request.GET['format'] == 'lat,lon':
                # text format, with lat, comma lon coordinates
                output = str(lat_lon[0]) + ',' + str(lat_lon[1])
                content_type='text/plain; charset=utf8'
        return HttpResponse(output,
                            content_type=content_type)
    else:
        message = 'ERROR: "tile" must be a valid quadtree geospatial tile (string composed of digits ranging from 0-3)'
        return HttpResponse(message,
                            content_type='text/plain; charset=utf8',
                            status=406)
예제 #5
0
 def make_geotile_filter_label(self, raw_geotile):
     """ parses a raw bbox parameter value to make
         a filter label
     """
     output_list = []
     if '||' in raw_geotile:
         tile_list = raw_geotile.split('||')
     else:
         tile_list = [raw_geotile]
     for tile in tile_list:
         geotile = GlobalMercator()
         coordinates = geotile.quadtree_to_lat_lon(tile)
         if coordinates is not False:
             label = 'In the region bounded by: '
             label += str(round(coordinates[0], 3))
             label += ', ' + str(round(coordinates[1], 3))
             label += ' (SW) and ' + str(round(coordinates[2], 3))
             label += ', ' + str(round(coordinates[3], 3))
             label += ' (NE)'
             output_list.append(label)
         else:
             output_list.append('[Ignored invalid geospatial tile]')
     output = '; or '.join(output_list)
     return output
예제 #6
0
 def process_geo(self):
     """ processes the solr_json 
         discovery geo tiles,
         aggregating to a certain
         depth
     """
     if isinstance(self.geo_pivot, list):
         i = 0
         for proj in self.geo_pivot:
             i += 1
             add_feature = True
             project_key = proj['value']
             proj_ex = project_key.split('___')
             slug = proj_ex[0]
             uri = self.make_url_from_val_string(proj_ex[2])
             href = self.make_url_from_val_string(proj_ex[2], False)
             label = proj_ex[3]
             fl = FilterLinks()
             fl.base_request_json = self.filter_request_dict_json
             fl.spatial_context = self.spatial_context
             new_rparams = fl.add_to_request('proj',
                                             slug)
             if 'response' in new_rparams:
                 new_rparams.pop('response', None)
             record = LastUpdatedOrderedDict()
             record['id'] = fl.make_request_url(new_rparams)
             record['json'] = fl.make_request_url(new_rparams, '.json')
             record['count'] = proj['count']
             record['type'] = 'Feature'
             record['category'] = 'oc-api:geo-project'
             min_date = False
             max_date = False
             if project_key in self.projects:
                 min_date = self.projects[project_key]['min_date']
                 max_date = self.projects[project_key]['max_date']
             if min_date is not False \
                and max_date is not False:
                 when = LastUpdatedOrderedDict()
                 when['id'] = '#event-' + slug
                 when['type'] = 'oc-gen:formation-use-life'
                 # convert numeric to GeoJSON-LD ISO 8601
                 when['start'] = ISOyears().make_iso_from_float(self.projects[project_key]['min_date'])
                 when['stop'] = ISOyears().make_iso_from_float(self.projects[project_key]['max_date'])
                 record['when'] = when
             if 'pivot' not in proj:
                 add_feature = False
             else:
                 geometry = LastUpdatedOrderedDict()
                 geometry['id'] = '#geo-geom-' + slug
                 geometry['type'] = 'Point'
                 pivot_count_total = 0
                 total_lon = 0
                 total_lat = 0
                 for geo_data in proj['pivot']:
                     pivot_count_total += geo_data['count']
                     gm = GlobalMercator()
                     bounds = gm.quadtree_to_lat_lon(geo_data['value'])
                     mean_lon = (bounds[1] + bounds[3]) / 2
                     mean_lat = (bounds[0] + bounds[2]) / 2
                     total_lon += mean_lon * geo_data['count']
                     total_lat += mean_lat * geo_data['count']
                 weighted_mean_lon = total_lon / pivot_count_total
                 weighted_mean_lat = total_lat / pivot_count_total
                 geometry['coordinates'] = [weighted_mean_lon,
                                            weighted_mean_lat]
                 record['geometry'] = geometry
             # now make a link to search records for this project
             fl = FilterLinks()
             fl.spatial_context = self.spatial_context
             new_rparams = fl.add_to_request('proj',
                                             slug)
             search_link = fl.make_request_url(new_rparams)
             properties = LastUpdatedOrderedDict()
             properties['id'] = '#geo-proj-' + slug
             properties['uri'] = uri
             properties['href'] = href
             properties['search'] = search_link
             properties['label'] = label
             properties['feature-type'] = 'project '
             properties['count'] = proj['count']
             properties['early bce/ce'] = min_date
             properties['late bce/ce'] = max_date
             record['properties'] = properties
             if add_feature:
                 self.geojson_projects.append(record)
예제 #7
0
    def add_geojson(self, json_ld):
        """
        adds geospatial and event data that links time and space information
        """
        uuid = self.manifest.uuid
        item_type = self.manifest.item_type
        geo_meta = self.geo_meta
        event_meta = self.event_meta
        features_dict = False  # dict of all features to be added
        feature_events = False  # mappings between features and time periods
        if geo_meta is not False:
            # print('here!' + str(geo_meta))
            features_dict = LastUpdatedOrderedDict()
            feature_events = LastUpdatedOrderedDict()
            for geo in geo_meta:
                geo_id = geo.feature_id
                geo_node = '#geo-' + str(
                    geo_id)  # the node id for database rec of the feature
                geo_node_geom = '#geo-geom-' + str(geo_id)
                geo_node_props = '#geo-props-' + str(geo_id)
                geo_node_derived = '#geo-derived-' + str(
                    geo_id)  # node id for a derived feature
                geo_node_derived_geom = '#geo-derived-geom-' + str(geo_id)
                geo_node_derived_props = '#geo-derived-props-' + str(geo_id)
                feature_events[geo_node] = []
                geo_props = LastUpdatedOrderedDict()
                geo_props['href'] = URImanagement.make_oc_uri(
                    uuid, item_type, self.cannonical_uris)
                geo_props['type'] = geo.meta_type
                if len(geo.note) > 0:
                    geo_props['note'] = geo.note
                if uuid != geo.uuid:
                    geo_props['reference-type'] = 'inferred'
                    geo_props['reference-uri'] = URImanagement.make_oc_uri(
                        geo.uuid, 'subjects', self.cannonical_uris)

                    rel_meta = self.item_gen_cache.get_entity(geo.uuid)
                    if rel_meta is not False:
                        geo_props['reference-label'] = rel_meta.label
                        geo_props['reference-slug'] = rel_meta.slug
                else:
                    geo_props['reference-label'] = self.manifest.label
                    geo_props['reference-type'] = 'specified'
                    if self.assertion_hashes:
                        geo_props['hash_id'] = geo.hash_id
                        geo_props['feature_id'] = geo.feature_id
                if geo.specificity < 0 and self.manifest.item_type != 'projects':
                    # case where we've got reduced precision geospatial data
                    # geotile = quadtree.encode(geo.latitude, geo.longitude, abs(geo.specificity))
                    geo_props['location-precision'] = abs(geo.specificity)
                    geo_props[
                        'location-precision-note'] = 'Location data approximated as a security precaution.'
                    gmt = GlobalMercator()
                    geotile = gmt.lat_lon_to_quadtree(geo.latitude,
                                                      geo.longitude,
                                                      abs(geo.specificity))
                    tile_bounds = gmt.quadtree_to_lat_lon(geotile)
                    item_polygon = Polygon([[(tile_bounds[1], tile_bounds[0]),
                                             (tile_bounds[1], tile_bounds[2]),
                                             (tile_bounds[3], tile_bounds[2]),
                                             (tile_bounds[3], tile_bounds[0]),
                                             (tile_bounds[1], tile_bounds[0])]
                                            ])
                    item_f_poly = Feature(geometry=item_polygon)
                    item_f_poly.id = geo_node_derived
                    item_f_poly.geometry.id = geo_node_derived_geom
                    item_f_poly.properties.update(geo_props)
                    item_f_poly.properties['location-note'] = 'This region defines the '\
                                                              'approximate location for this item.'
                    item_f_poly.properties['id'] = geo_node_derived_props
                    features_dict[geo_node_derived] = item_f_poly
                    item_point = Point(
                        (float(geo.longitude), float(geo.latitude)))
                    item_f_point = Feature(geometry=item_point)
                    item_f_point.id = geo_node
                    item_f_point.geometry.id = geo_node_geom
                    item_f_point.properties.update(geo_props)
                    item_f_point.properties['location-note'] = 'This point defines the center of the '\
                                                               'region approximating the location for this item.'
                    item_f_point.properties['id'] = geo_node_props
                    features_dict[geo_node] = item_f_point
                elif len(geo.coordinates) > 1:
                    # here we have geo_json expressed features and geometries to use
                    if geo.specificity < 0:
                        geo_props[
                            'location-precision-note'] = 'Location data approximated as a security precaution.'
                    elif geo.specificity > 0:
                        geo_props[
                            'location-precision-note'] = 'Location data has uncertainty.'
                    else:
                        geo_props['location-precision-note'] = 'Location data available with no '\
                                                               'intentional reduction in precision.'
                    item_point = Point(
                        (float(geo.longitude), float(geo.latitude)))
                    item_f_point = Feature(geometry=item_point)
                    item_f_point.properties.update(geo_props)
                    if uuid == geo.uuid:
                        #the item itself has the polygon as it's feature
                        item_db = Point(
                            (float(geo.longitude), float(geo.latitude)))
                        if geo.ftype == 'Polygon':
                            coord_obj = json.loads(geo.coordinates)
                            item_db = Polygon(coord_obj)
                        elif (geo.ftype == 'MultiPolygon'):
                            coord_obj = json.loads(geo.coordinates)
                            item_db = MultiPolygon(coord_obj)
                        elif (geo.ftype == 'MultiLineString'):
                            coord_obj = json.loads(geo.coordinates)
                            item_db = MultiLineString(coord_obj)
                        item_f_db = Feature(geometry=item_db)
                        item_f_db.id = geo_node
                        item_f_db.geometry.id = geo_node_geom
                        item_f_db.properties.update(geo_props)
                        item_f_db.properties['id'] = geo_node_props
                        features_dict[geo_node] = item_f_db
                        item_f_point.id = geo_node_derived
                        item_f_point.geometry.id = geo_node_derived_geom
                        item_f_point.properties['location-region-note'] = 'This point represents the center of the '\
                                                                          'region defining the location of this item.'
                        item_f_point.properties['id'] = geo_node_derived_props
                        features_dict[geo_node_derived] = item_f_point
                    else:
                        #the item is contained within another item with a polygon or multipolygon feature
                        item_f_point.id = geo_node
                        item_f_point.geometry.id = geo_node_geom
                        item_f_point.properties['id'] = geo_node_props
                        item_f_point.properties['contained-in-region'] = True
                        item_f_point.properties['location-region-note'] = 'This point represents the center of the '\
                                                                          'region containing this item.'
                        features_dict[geo_node] = item_f_point
                else:
                    # case where the item only has a point for geo-spatial reference
                    geo_props[
                        'location-note'] = 'Location data available with no intentional reduction in precision.'
                    item_point = Point(
                        (float(geo.longitude), float(geo.latitude)))
                    item_f_point = Feature(geometry=item_point)
                    item_f_point.id = geo_node
                    item_f_point.geometry.id = geo_node_geom
                    item_f_point.properties.update(geo_props)
                    item_f_point.properties['id'] = geo_node_props
                    features_dict[geo_node] = item_f_point
            if event_meta is not False:
                # events provide chrological information, tied to geo features
                # sometimes there are more than 1 time period for each geo feature
                # in such cases, we duplicate geo features and add the different time event
                # information to the new features
                for event in event_meta:
                    rel_feature_num = 1  # default to the first geospatial feature for where the event happened
                    rel_feature_node = False
                    if event.feature_id > 0:
                        rel_feature_num = event.feature_id
                    if rel_feature_num >= 1:
                        rel_feature_node = '#geo-' + str(rel_feature_num)
                    act_event_obj = LastUpdatedOrderedDict()
                    act_event_obj = self.add_when_json(act_event_obj, uuid,
                                                       item_type, event)
                    if rel_feature_node is not False and feature_events is not False:
                        feature_events[rel_feature_node].append(act_event_obj)
            if features_dict is not False:
                if feature_events is not False:
                    for node_key, event_list in feature_events.items():
                        # update the feature with the first event "when" information
                        if len(event_list) > 0:
                            features_dict[node_key].update(event_list[0])
                            event_i = 1
                            for event in event_list:
                                if event_i <= 1:
                                    # add the time info to the feature
                                    old_feature = features_dict[node_key]
                                    old_geo_id = old_feature.geometry['id']
                                    old_prop_id = old_feature.properties['id']
                                    features_dict[node_key].update(event)
                                else:
                                    act_feature = copy.deepcopy(old_feature)
                                    # now add new node ids for the new features created to for the event
                                    new_node = node_key + '-event-' + str(
                                        event_i)
                                    act_feature.id = new_node
                                    act_feature.geometry[
                                        'id'] = old_geo_id + '-event-' + str(
                                            event_i)
                                    act_feature.properties[
                                        'id'] = old_prop_id + '-event-' + str(
                                            event_i)
                                    act_feature.update(
                                        event
                                    )  # add the time info to the new feature
                                    features_dict[new_node] = act_feature
                                    del (act_feature)
                                event_i += 1
                feature_keys = list(features_dict.keys())
                if len(feature_keys) < 1:
                    del features_dict[feature_keys[0]][
                        'id']  # remove the conflicting id
                    # only 1 feature, so item is not a feature collection
                    json_ld.update(features_dict[feature_keys[0]])
                else:
                    feature_list = [
                    ]  # multiple features, so item has a feature collection
                    for node_key, feature in features_dict.items():
                        feature_list.append(feature)
                    item_fc = FeatureCollection(feature_list)
                    json_ld.update(item_fc)
        return json_ld
예제 #8
0
 def process_geo(self):
     """ processes the solr_json 
         discovery geo tiles,
         aggregating to a certain
         depth
     """
     if isinstance(self.geo_pivot, list):
         i = 0
         for proj in self.geo_pivot:
             i += 1
             add_feature = True
             project_key = proj['value']
             proj_ex = project_key.split('___')
             slug = proj_ex[0]
             uri = self.make_url_from_val_string(proj_ex[2])
             href = self.make_url_from_val_string(proj_ex[2], False)
             label = proj_ex[3]
             fl = FilterLinks()
             fl.base_request_json = self.filter_request_dict_json
             fl.spatial_context = self.spatial_context
             new_rparams = fl.add_to_request('proj', slug)
             if 'response' in new_rparams:
                 new_rparams.pop('response', None)
             record = LastUpdatedOrderedDict()
             record['id'] = fl.make_request_url(new_rparams)
             record['json'] = fl.make_request_url(new_rparams, '.json')
             record['count'] = proj['count']
             record['type'] = 'Feature'
             record['category'] = 'oc-api:geo-project'
             min_date = False
             max_date = False
             if project_key in self.projects:
                 min_date = self.projects[project_key]['min_date']
                 max_date = self.projects[project_key]['max_date']
             if min_date is not False \
                and max_date is not False:
                 when = LastUpdatedOrderedDict()
                 when['id'] = '#event-' + slug
                 when['type'] = 'oc-gen:formation-use-life'
                 # convert numeric to GeoJSON-LD ISO 8601
                 when['start'] = ISOyears().make_iso_from_float(
                     self.projects[project_key]['min_date'])
                 when['stop'] = ISOyears().make_iso_from_float(
                     self.projects[project_key]['max_date'])
                 record['when'] = when
             if 'pivot' not in proj:
                 add_feature = False
             else:
                 geometry = LastUpdatedOrderedDict()
                 geometry['id'] = '#geo-geom-' + slug
                 geometry['type'] = 'Point'
                 pivot_count_total = 0
                 total_lon = 0
                 total_lat = 0
                 for geo_data in proj['pivot']:
                     pivot_count_total += geo_data['count']
                     gm = GlobalMercator()
                     bounds = gm.quadtree_to_lat_lon(geo_data['value'])
                     mean_lon = (bounds[1] + bounds[3]) / 2
                     mean_lat = (bounds[0] + bounds[2]) / 2
                     total_lon += mean_lon * geo_data['count']
                     total_lat += mean_lat * geo_data['count']
                 weighted_mean_lon = total_lon / pivot_count_total
                 weighted_mean_lat = total_lat / pivot_count_total
                 geometry['coordinates'] = [
                     weighted_mean_lon, weighted_mean_lat
                 ]
                 record['geometry'] = geometry
             # now make a link to search records for this project
             fl = FilterLinks()
             fl.spatial_context = self.spatial_context
             new_rparams = fl.add_to_request('proj', slug)
             search_link = fl.make_request_url(new_rparams)
             properties = LastUpdatedOrderedDict()
             properties['id'] = '#geo-proj-' + slug
             properties['uri'] = uri
             properties['href'] = href
             properties['search'] = search_link
             properties['label'] = label
             properties['feature-type'] = 'project '
             properties['count'] = proj['count']
             properties['early bce/ce'] = min_date
             properties['late bce/ce'] = max_date
             record['properties'] = properties
             if add_feature:
                 self.geojson_projects.append(record)
예제 #9
0
 def get_geotile_scope(self, solr_tiles):
     """ find the most specific tile shared by the whole dataset """
     geo_tiles = []
     bound_list = []
     max_distance = 0
     lat_lon_min_max = [{
         'min': None,
         'max': None
     }, {
         'min': None,
         'max': None
     }]
     for tile_key in solr_tiles[::2]:
         if tile_key[:6] != '211111':
             # a bit of a hack to exclude display of
             # erroroneous data without spatial reference
             geo_tiles.append(tile_key)
             gm = GlobalMercator()
             bounds = gm.quadtree_to_lat_lon(tile_key)
             lat_lon_min_max = self.get_min_max(lat_lon_min_max, bounds)
             bound_list.append(bounds)
     if len(geo_tiles) > 0:
         test_tile = geo_tiles[0]  # we compare against the first tile
         tile_len = len(test_tile)  # size of the tile
         in_all_geotiles = True
         i = 0
         while (i < tile_len and in_all_geotiles):
             if i > 0:
                 test_val = str(test_tile[0:i])
             else:
                 test_val = str(test_tile[0])
             for geo_tile in geo_tiles:
                 if i > len(geo_tile):
                     in_all_geotiles = False
                 else:
                     if i > 0:
                         geo_tile_part = geo_tile[0:i]
                     else:
                         geo_tile_part = geo_tile[0]
                     if test_val != geo_tile_part:
                         in_all_geotiles = False
             if in_all_geotiles:
                 # ok! we have somthing that is still in all tiles
                 self.geotile_scope = test_val
                 i += 1
     if isinstance(self.geotile_scope, str):
         self.aggregation_depth += round(len(self.geotile_scope) * 1, 0)
         self.aggregation_depth = int(self.aggregation_depth)
         if self.aggregation_depth < 6:
             self.aggregation_depth = 6
     if self.aggregation_depth >= 6 and len(bound_list) >= 2:
         gm = GlobalMercator()
         max_distance = gm.distance_on_unit_sphere(
             lat_lon_min_max[0]['min'], lat_lon_min_max[1]['min'],
             lat_lon_min_max[0]['max'], lat_lon_min_max[1]['max'])
         if max_distance == 0:
             self.aggregation_depth = 10
         else:
             # converts the maximum distance between points into a zoom level
             # appropriate for tile aggregation. seems to work well.
             self.aggregation_depth = gm.ZoomForPixelSize(max_distance) + 3
             # print('now: ' + str(self.aggregation_depth) + ' for ' + str(max_distance))
             if self.aggregation_depth > self.max_depth:
                 self.aggregation_depth = self.max_depth
             if self.aggregation_depth < 6:
                 self.aggregation_depth = 6
     return self.geotile_scope