Example #1
0
        def way(self, w):

            # ways that are admin areas
            if 'boundary' in w.tags and w.tags[
                    'boundary'] == 'administrative' and 'name' in w.tags and 'admin_level' in w.tags:
                linestring = []
                for node in w.nodes:
                    linestring.append(
                        [float(node.x) / 10000000,
                         float(node.y) / 10000000])
                if linestring[0][0] == linestring[-1][0] and linestring[0][
                        1] == linestring[-1][1]:
                    admin_level_aux = 0
                    try:
                        admin_level_aux = int(w.tags['admin_level'])
                    except Exception as e:
                        print(f'wrong admin level: {w.tags["admin_level"]}')
                    if admin_level_aux >= ADMIN_LEVEL_MIN and admin_level_aux <= ADMIN_LEVEL_MAX:
                        poly = Polygon(linestring)
                        admin_areas[admin_level_aux].append({
                            'import_timestamp':
                            run_timestamp,
                            'osm_id':
                            w.id,
                            'osm_type':
                            'w',
                            'geometry':
                            maybe_make_valid(poly),
                            'geometry_simple':
                            maybe_make_valid(poly.simplify(0.001, True)),
                            'admin_level':
                            admin_level_aux,
                            'name':
                            w.tags['name'],  # .encode('utf-8').strip(),
                            'tags': {k: v
                                     for k, v in w.tags},
                            'country_code':
                            country_code,
                        })

            # fill relations that are admin areas
            if w.id in admin_relations_ways_ids:
                linestring = []
                for node in w.nodes:
                    linestring.append(
                        [float(node.x) / 10000000,
                         float(node.y) / 10000000])

                for rel_id in admin_relations_ways_ids[w.id]:
                    if rel_id in admin_relations and 'ways' in admin_relations[
                            rel_id]:
                        for i, wid in enumerate(
                                admin_relations[rel_id]['ways']):
                            if wid == w.id:
                                admin_relations[rel_id]['ways'][i] = linestring
 def get_features(self, shp, name, tolerance):
     """
     Return a list of dictionaries that can be serialized into GeoJSON
     features
     """
     features = [] 
     for coords in shp['geometry']['coordinates']:
         poly = Polygon(coords)
         poly = poly.simplify(tolerance)
         geo = json.loads(poly.boundary.geojson)
         features.append({
             'properties': {
                 'name': name,
             },
             'geometry': geo,
             'type': "Feature",
         })
     return features
Example #3
0
def get_admin_areas(run_timestamp,
                    inputfile,
                    country_code,
                    KING_ID,
                    printfn=printfn,
                    get_only_king=False):

    ADMIN_LEVEL_MIN = 1
    ADMIN_LEVEL_MAX = 8

    KING = None

    admin_areas = [[] for i in range(12)]  # index: admin_level, value
    admin_relations = {}  # index: admin_level, value
    admin_relations_ways_ids = {}

    # this = self

    class RelsHandler(osmium.SimpleHandler):
        def relation(self, r):
            if 'boundary' in r.tags and r.tags[
                    'boundary'] == 'administrative' and 'name' in r.tags and 'admin_level' in r.tags and (
                        not get_only_king or r.id == KING_ID):
                ways = []
                for m in r.members:
                    # outer (parts and exclaves) / inner (hole)
                    if m.type == 'w' and m.role in ['outer']:
                        ways.append(m.ref)
                        admin_relations_ways_ids.setdefault(m.ref,
                                                            []).append(r.id)
                try:
                    admin_level = int(r.tags['admin_level'])
                except ValueError:
                    return
                admin_relations[r.id] = {
                    'import_timestamp': run_timestamp,
                    'osm_id': r.id,
                    'osm_type': 'r',
                    'ways': ways,
                    'admin_level': admin_level,
                    'name': r.tags['name'],  # .encode('utf-8').strip(),
                    'tags': {k: v
                             for k, v in r.tags},
                    'country_code': country_code,
                }
                # this.out2(f"REL {r.id} {r.tags['name'].encode('utf-8').strip()}")

    def make_valid(geom):
        cursor = connection._cursor()
        try:
            try:
                cursor.execute('SELECT ST_MakeValid(%s)',
                               (PostGISAdapter(geom), ))
                row = cursor.fetchone()
            except:
                # Responsibility of callers to perform error handling.
                raise
        finally:
            # Close out the connection.  See #9437.
            connection.close()
        return GEOSGeometry(row[0])

    def maybe_make_valid(geom):
        if not geom.valid:
            return make_valid(geom)
        else:
            return geom

    class WaysHandler(osmium.SimpleHandler):
        def way(self, w):

            # ways that are admin areas
            if 'boundary' in w.tags and w.tags[
                    'boundary'] == 'administrative' and 'name' in w.tags and 'admin_level' in w.tags:
                linestring = []
                for node in w.nodes:
                    linestring.append(
                        [float(node.x) / 10000000,
                         float(node.y) / 10000000])
                if linestring[0][0] == linestring[-1][0] and linestring[0][
                        1] == linestring[-1][1]:
                    admin_level_aux = 0
                    try:
                        admin_level_aux = int(w.tags['admin_level'])
                    except Exception as e:
                        print(f'wrong admin level: {w.tags["admin_level"]}')
                    if admin_level_aux >= ADMIN_LEVEL_MIN and admin_level_aux <= ADMIN_LEVEL_MAX:
                        poly = Polygon(linestring)
                        admin_areas[admin_level_aux].append({
                            'import_timestamp':
                            run_timestamp,
                            'osm_id':
                            w.id,
                            'osm_type':
                            'w',
                            'geometry':
                            maybe_make_valid(poly),
                            'geometry_simple':
                            maybe_make_valid(poly.simplify(0.001, True)),
                            'admin_level':
                            admin_level_aux,
                            'name':
                            w.tags['name'],  # .encode('utf-8').strip(),
                            'tags': {k: v
                                     for k, v in w.tags},
                            'country_code':
                            country_code,
                        })

            # fill relations that are admin areas
            if w.id in admin_relations_ways_ids:
                linestring = []
                for node in w.nodes:
                    linestring.append(
                        [float(node.x) / 10000000,
                         float(node.y) / 10000000])

                for rel_id in admin_relations_ways_ids[w.id]:
                    if rel_id in admin_relations and 'ways' in admin_relations[
                            rel_id]:
                        for i, wid in enumerate(
                                admin_relations[rel_id]['ways']):
                            if wid == w.id:
                                admin_relations[rel_id]['ways'][i] = linestring

    printfn(f'Collecting rels, using {inputfile}')
    h = RelsHandler()
    h.apply_file(inputfile)
    printfn('Collecting ways & nodes')
    h = WaysHandler()
    h.apply_file(inputfile, locations=True)

    admin_count_ok = 0
    admin_count_all = 0
    admin_count = 0
    printfn('Joining ways')
    for (k, v) in admin_relations.items():
        admin_count_all = admin_count_all + 1
        dbadminarea = AdministrativeArea.objects.filter(osm_id=v['osm_id'],
                                                        osm_type=v['osm_type'])
        if dbadminarea:
            dbadminarea = dbadminarea[0]
            v['img_panorama'] = dbadminarea.img_panorama
            v['img_cuadrada'] = dbadminarea.img_cuadrada

        if v['admin_level'] >= ADMIN_LEVEL_MIN and v[
                'admin_level'] <= ADMIN_LEVEL_MAX:
            printfn(f"osmid={k} level={v['admin_level']} name={v['name']}",
                    end="")
            wfull = [w for w in v['ways'] if not isinstance(w, int)]
            if len(wfull) == 0 or float(len(wfull)) / float(len(
                    v['ways'])) < 0.8:
                printfn(f" NOK skipping adminarea, less than 80% of fragments")
                continue
            way, status = fix_polygon(wfull, 1000)
            if way is None:
                # si esta roto, buscar en la base de datos si hay uno con ese id y usar ese way
                printfn(f' ERROR: {status}')
                if dbadminarea:
                    way = dbadminarea.geometry
            else:
                admin_count = admin_count + 1
                printfn(f" OK -> {len(way)}")
                # last point equals first
                admin_count_ok = admin_count_ok + 1
                try:
                    poly = Polygon(way)
                    v['geometry'] = maybe_make_valid(poly)
                    v['geometry_simple'] = maybe_make_valid(
                        poly.simplify(0.01, True))
                    if v['osm_id'] != KING_ID:
                        admin_areas[v['admin_level']].append(v)
                except Exception as e:
                    try:
                        printfn(f" {e}, retrying as multipolygon")
                        mp = []
                        for p in way:
                            p_fixed, status = fix_polygon(p, 1000)
                            if p_fixed:
                                try:
                                    mp.append(Polygon(p_fixed + [p_fixed[0]]))
                                except Exception as e3:
                                    printfn(
                                        f" {e3} {status}, skipping fragment. ({len(p_fixed)} nodes) [{status}]"
                                    )
                        poly = MultiPolygon(mp)
                        v['geometry'] = maybe_make_valid(poly)
                        v['geometry_simple'] = maybe_make_valid(
                            poly.simplify(0.01, True))
                        if v['osm_id'] != KING_ID:
                            admin_areas[v['admin_level']].append(v)
                        printfn('-> ok')
                    except Exception as e2:
                        traceback.print_exc()
                        printfn(f" {e2}, error")
                if v['osm_id'] == KING_ID:
                    KING = v
    printfn(
        f"TOTALS: all({admin_count_all}) tried({admin_count}) ok({admin_count_ok}), really_ok({len(admin_areas)})"
    )

    return admin_areas, KING