File size: 3,324 Bytes
760889f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aea4fce
760889f
 
 
 
aea4fce
 
760889f
 
 
 
aea4fce
 
 
760889f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aea4fce
 
c424639
aea4fce
 
760889f
 
 
 
aea4fce
760889f
 
aea4fce
 
760889f
 
 
 
 
 
 
 
 
 
 
 
 
aea4fce
760889f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import cv2
import fiona
from pyproj import Transformer

import numpy as np
from tqdm import tqdm

from grid_optim import get_optimal_grid


def shapefile_to_latlong(file_path: str):
    c = fiona.open(file_path)
    contours = []

    transformer = Transformer.from_crs(c.crs, 4326, always_xy=True)

    for poly in c:
        coords = poly["geometry"].coordinates
        for coord_set in coords:
            contours.append(
                np.array(
                    list(
                        transformer.itransform(
                            coord_set[0] if len(coord_set) == 1 else coord_set
                        )
                    )
                )
            )

    return contours


def mask_shapefile_to_grid_indices(
    file_path: str, side_len_m: float = 100, meters_per_px: float = 10
):
    c = fiona.open(file_path, "r")
    all_indices = []
    all_labels = []
    city_counts = {}
    side_len = side_len_m / meters_per_px

    for poly in c:
        coords = poly["geometry"].coordinates
        city = poly["properties"]["City"]
        if city not in city_counts:
            city_counts[city] = 0
        for coord_set in tqdm(coords):
            contour = np.array(coord_set[0] if len(coord_set) == 1 else coord_set)

            cmin = contour.min(axis=0)
            contour -= cmin
            cmax = int(contour.max() / meters_per_px)
            contour = contour // meters_per_px

            if cmax < side_len:
                continue

            mask = np.zeros((cmax, cmax), dtype="uint8")
            mask = cv2.drawContours(
                mask,
                [contour.reshape((-1, 1, 2)).astype(np.int32)],
                -1,
                (255),
                thickness=cv2.FILLED,
            )

            indices = np.array(get_optimal_grid(mask, side_len=side_len)[0])
            indices = indices * meters_per_px + cmin

            all_indices += sorted(indices.tolist(), key=lambda x: x[1])
            all_labels += [
                f"{city[0]}-{city_counts[city] + i}" for i in range(len(indices))
            ]
            city_counts[city] += len(indices)

    transformer = Transformer.from_crs(c.crs, 4326, always_xy=True)
    all_indices = list(transformer.itransform(all_indices))

    return np.array(all_indices), all_labels


def points_to_shapefile(points: np.ndarray, labels: list, file_path: str):
    schema = {"geometry": "Point", "properties": [("ID", "int"), ("Name", "str")]}

    # open a fiona object
    pointShp = fiona.open(
        file_path,
        mode="w",
        driver="ESRI Shapefile",
        schema=schema,
        crs="EPSG:4326",
    )
    # iterate over each row in the dataframe and save record
    for i, (x, y) in enumerate(points):
        rowDict = {
            "geometry": {"type": "Point", "coordinates": (x, y)},
            "properties": {"ID": i, "Name": labels[i]},
        }
        pointShp.write(rowDict)
    # close fiona object
    pointShp.close()


def get_cached_grid_indices(file_path: str):
    c = fiona.open(file_path, "r")
    all_indices = []
    all_labels = []

    for poly in c:
        all_indices.append(poly["geometry"].coordinates)
        if "Name" in poly["properties"]:
            all_labels.append(poly["properties"]["Name"])

    return np.array(all_indices), all_labels