示例#1
0
    def get_bounds(content, content_pois, content_areas):
        """ gets map bounds. first try to get content bounds,
            last will get content_pois extent """
        points = [c.main_location for c in content_pois if c.has_location()]

        areas = []
        for c in content_areas:
            if hasattr(c, 'location'):
                if getattr(c.location, 'borders', None):
                    areas.append(c.location.borders)
            elif getattr(c, 'borders', None):
                areas.append(c.borders)
        if points and areas:
            mp = MultiPoint(points)
            ap = MultiPolygon(areas)
            return ap.simplify().union(mp).extent
        elif len(points) > 1:
            mp = MultiPoint(points)
            return mp.extent
        elif points:
            # if we have just one point expand the borders
            # to avoid to much zoom
            content = content_pois[0]
        elif areas:
            ap = MultiPolygon(areas)
            return ap.extent
        elif content and content.main_location:
            return (content.main_location.x - 0.002,
                    content.main_location.y - 0.002,
                    content.main_location.x + 0.002,
                    content.main_location.y + 0.002)
        else:
            # default bounding box to avoid google maps failures
            return (settings.DEFAULT_LONGITUDE - 1.0,
                    settings.DEFAULT_LATITUDE - 1.0,
                    settings.DEFAULT_LONGITUDE + 1.0,
                    settings.DEFAULT_LATITUDE + 1.0)
示例#2
0
    def get_bounds(content, content_pois, content_areas):
        """ gets map bounds. first try to get content bounds,
            last will get content_pois extent """
        points = [c.main_location for c in content_pois if c.has_location()]

        areas = []
        for c in content_areas:
            if hasattr(c, 'location'):
                if getattr(c.location, 'borders', None):
                    areas.append(c.location.borders)
            elif getattr(c, 'borders', None):
                areas.append(c.borders)
        if points and areas:
            mp = MultiPoint(points)
            ap = MultiPolygon(areas)
            return ap.simplify().union(mp).extent
        elif len(points) > 1:
            mp = MultiPoint(points)
            return mp.extent
        elif points:
            # if we have just one point expand the borders
            # to avoid to much zoom
            content = content_pois[0]
        elif areas:
            ap = MultiPolygon(areas)
            return ap.extent
        elif content and content.main_location:
            return (content.main_location.x - 0.002,
                    content.main_location.y - 0.002,
                    content.main_location.x + 0.002,
                    content.main_location.y + 0.002)
        else:
            # default bounding box to avoid google maps failures
            return (settings.DEFAULT_LONGITUDE - 1.0,
                    settings.DEFAULT_LATITUDE - 1.0,
                    settings.DEFAULT_LONGITUDE + 1.0,
                    settings.DEFAULT_LATITUDE + 1.0)
示例#3
0
    def import_shape(self, store, config, updatefield):
        """
        Import a shapefile, based on a config.

        Parameters:
            config -- A dictionary with 'shapepath', 'geolevel', 'name_field', 'region_filters' and 'subject_fields' keys.
        """
        def get_shape_tree(shapefile, feature):
            shpfields = shapefile.xpath('Fields/Field')
            builtid = ''
            for idx in range(0, len(shpfields)):
                idpart = shapefile.xpath(
                    'Fields/Field[@type="tree" and @pos=%d]' % idx)
                if len(idpart) > 0:
                    idpart = idpart[0]
                    part = feature.get(idpart.get('name'))
                    # strip any spaces in the treecode
                    if not (isinstance(part, types.StringTypes)):
                        part = '%d' % part
                    part = part.strip(' ')
                    width = int(idpart.get('width'))
                    builtid = '%s%s' % (builtid, part.zfill(width))
            return builtid

        def get_shape_portable(shapefile, feature):
            field = shapefile.xpath('Fields/Field[@type="portable"]')[0]
            portable = feature.get(field.get('name'))
            if not (isinstance(portable, types.StringTypes)):
                portable = '%d' % portable
            return portable

        def get_shape_name(shapefile, feature):
            field = shapefile.xpath('Fields/Field[@type="name"]')[0]
            strname = feature.get(field.get('name'))
            if type(strname) == str:
                return strname.decode('latin-1')
            else:
                return str(strname)

        for h, shapefile in enumerate(config['shapefiles']):
            if not exists(shapefile.get('path')):
                logger.info(
                    """
ERROR:

    The filename specified by the configuration:

    %s

    Could not be found. Please check the configuration and try again.
""", shapefile.get('path'))
                raise IOError('Cannot find the file "%s"' %
                              shapefile.get('path'))

            ds = DataSource(shapefile.get('path'))

            logger.info('Importing from %s, %d of %d shapefiles...', ds, h + 1,
                        len(config['shapefiles']))

            lyr = ds[0]
            logger.info('%d objects in shapefile', len(lyr))

            level = Geolevel.objects.get(name=config['geolevel'].lower()[:50])
            # Create the subjects we need
            subject_objects = {}
            for sconfig in config['subject_fields']:
                attr_name = sconfig.get('field')
                foundalias = False
                for elem in sconfig.getchildren():
                    if elem.tag == 'Subject':
                        foundalias = True
                        sub = Subject.objects.get(
                            name=elem.get('id').lower()[:50])
                if not foundalias:
                    sub = Subject.objects.get(
                        name=sconfig.get('id').lower()[:50])
                subject_objects[attr_name] = sub
                subject_objects['%s_by_id' % sub.name] = attr_name

            progress = 0.0
            logger.info('0% .. ')
            for i, feat in enumerate(lyr):
                if (float(i) / len(lyr)) > (progress + 0.1):
                    progress += 0.1
                    logger.info('%2.0f%% .. ', progress * 100)

                levels = [level]
                for region, filter_list in config['region_filters'].iteritems(
                ):
                    # Check for applicability of the function by examining the config
                    geolevel_xpath = '/DistrictBuilder/GeoLevels/GeoLevel[@name="%s"]' % config[
                        'geolevel']
                    geolevel_config = store.data.xpath(geolevel_xpath)
                    geolevel_region_xpath = '/DistrictBuilder/Regions/Region[@name="%s"]/GeoLevels//GeoLevel[@ref="%s"]' % (
                        region, geolevel_config[0].get('id'))
                    if len(store.data.xpath(geolevel_region_xpath)) > 0:
                        # If the geolevel is in the region, check the filters
                        for f in filter_list:
                            if f(feat) is True:
                                levels.append(
                                    Geolevel.objects.get(name='%s_%s' %
                                                         (region, level.name)))
                shape_name = get_shape_name(shapefile, feat)
                shape_portable_id = get_shape_portable(shapefile, feat)
                shape_tree_code = get_shape_tree(shapefile, feat)
                prefetch = Geounit.objects.filter(
                    name=shape_name,
                    geolevel__in=levels,
                    portable_id=shape_portable_id,
                    tree_code=shape_tree_code)
                should_create = prefetch.count() == 0
                if should_create:
                    try:
                        # Store the geos geometry
                        # Buffer by 0 to get rid of any self-intersections which may make this geometry invalid.
                        geos = feat.geom.geos.buffer(0)
                        # Coerce the geometry into a MultiPolygon
                        if geos.geom_type == 'MultiPolygon':
                            my_geom = geos
                        elif geos.geom_type == 'Polygon':
                            my_geom = MultiPolygon(geos)
                        simple = my_geom.simplify(tolerance=Decimal(
                            config['tolerance']),
                                                  preserve_topology=True)
                        if simple.geom_type != 'MultiPolygon':
                            simple = MultiPolygon(simple)
                        center = my_geom.centroid

                        geos = None

                        # Ensure the centroid is within the geometry
                        if not center.within(my_geom):
                            # Get the first polygon in the multipolygon
                            first_poly = my_geom[0]
                            # Get the extent of the first poly
                            first_poly_extent = first_poly.extent
                            min_x = first_poly_extent[0]
                            max_x = first_poly_extent[2]
                            # Create a line through the bbox and the poly center
                            my_y = first_poly.centroid.y
                            centerline = LineString((min_x, my_y),
                                                    (max_x, my_y))
                            # Get the intersection of that line and the poly
                            intersection = centerline.intersection(first_poly)
                            if type(intersection) is MultiLineString:
                                intersection = intersection[0]
                            # the center of that line is my within-the-poly centroid.
                            center = intersection.centroid
                            first_poly = first_poly_extent = min_x = max_x = my_y = centerline = intersection = None
                        g = Geounit(geom=my_geom,
                                    name=shape_name,
                                    simple=simple,
                                    center=center,
                                    portable_id=shape_portable_id,
                                    tree_code=shape_tree_code)
                        g.save()
                        g.geolevel = levels
                        g.save()

                    except:
                        logger.info('Failed to import geometry for feature %d',
                                    feat.fid)
                        logger.info(traceback.format_exc())
                        continue
                else:
                    g = prefetch[0]
                    g.geolevel = levels
                    g.save()

                if not config['attributes']:
                    # If we created a new Geounit, we can let this function know that it doesn't
                    # need to check for existing Characteristics, which will speed things up
                    # significantly.
                    self.set_geounit_characteristic(g, subject_objects, feat,
                                                    not should_create,
                                                    updatefield)

            logger.info('100%')

        if config['attributes']:
            progress = 0
            logger.info("Assigning subject values to imported geography...")
            logger.info('0% .. ')
            for h, attrconfig in enumerate(config['attributes']):
                if not exists(attrconfig.get('path')):
                    logger.info(
                        """
ERROR:

    The filename specified by the configuration:

    %s

    Could not be found. Please check the configuration and try again.
""", attrconfig.get('path'))
                    raise IOError('Cannot find the file "%s"' %
                                  attrconfig.get('path'))

                lyr = DataSource(attrconfig.get('path'))[0]

                for i, feat in enumerate(lyr):
                    if (float(i) / len(lyr)) > (progress + 0.1):
                        progress += 0.1
                        logger.info('%2.0f%% .. ', progress * 100)

                    gid = get_shape_tree(attrconfig, feat)
                    g = Geounit.objects.filter(tree_code=gid)

                    if g.count() > 0:
                        self.set_geounit_characteristic(
                            g[0], subject_objects, feat, True, updatefield)

            logger.info('100%')