Exemplo n.º 1
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