Skip to content

Commit 624127b

Browse files
authored
Merge branch 'dev' into feat/manager-dashboard/randomize-order-street
2 parents b8b2c14 + 2d41751 commit 624127b

File tree

7 files changed

+81
-51
lines changed

7 files changed

+81
-51
lines changed

manager-dashboard/app/views/NewProject/index.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ const defaultProjectFormValue: PartialProjectFormType = {
108108
// maxTasksPerUser: -1,
109109
inputType: PROJECT_INPUT_TYPE_UPLOAD,
110110
filter: FILTER_BUILDINGS,
111-
isPano: false,
112111
randomizeOrder: false,
112+
panoOnly: false,
113113
};
114114

115115
interface Props {
@@ -321,6 +321,7 @@ function NewProject(props: Props) {
321321

322322
valuesToCopy.startTimestamp = valuesToCopy.dateRange?.startDate ?? null;
323323
valuesToCopy.endTimestamp = valuesToCopy.dateRange?.endDate ?? null;
324+
valuesToCopy.isPano = valuesToCopy.panoOnly ? true : null;
324325

325326
const storage = getStorage();
326327
const timestamp = (new Date()).getTime();
@@ -757,8 +758,8 @@ function NewProject(props: Props) {
757758
disabled={submissionPending || projectTypeEmpty}
758759
/>
759760
<Checkbox
760-
name={'isPano' as const}
761-
value={value?.isPano}
761+
name={'panoOnly' as const}
762+
value={value?.panoOnly}
762763
label="Only use 360 degree panorama images."
763764
onChange={setFieldValue}
764765
disabled={submissionPending || projectTypeEmpty}

manager-dashboard/app/views/NewProject/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ export interface ProjectFormType {
8383
endTimestamp?: string | null;
8484
organizationId?: number;
8585
creatorId?: number;
86-
isPano?: boolean;
8786
randomizeOrder?: boolean;
87+
panoOnly?: boolean;
88+
isPano?: boolean | null;
8889
samplingThreshold?: number;
8990
}
9091

@@ -306,6 +307,9 @@ export const projectFormSchema: ProjectFormSchema = {
306307
greaterThanCondition(0),
307308
],
308309
},
310+
panoOnly: {
311+
required: false,
312+
},
309313
isPano: {
310314
required: false,
311315
},

mapswipe_workers/mapswipe_workers/project_types/street/project.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def __init__(self, project_draft):
5151
start_time=project_draft.get("startTimestamp", None),
5252
end_time=project_draft.get("endTimestamp", None),
5353
organization_id=project_draft.get("organizationId", None),
54+
randomize_order=project_draft.get("randomizeOrder", None),
5455
sampling_threshold=project_draft.get("samplingThreshold", None),
5556
)
5657

mapswipe_workers/mapswipe_workers/utils/process_mapillary.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ def create_tiles(polygon, level):
2626
if isinstance(polygon, Polygon):
2727
polygon = MultiPolygon([polygon])
2828

29-
tiles = []
29+
tiles = set()
3030
for i, poly in enumerate(polygon.geoms):
31-
tiles.extend(list(mercantile.tiles(*poly.bounds, level)))
31+
tiles.update(list(mercantile.tiles(*poly.bounds, level)))
3232

3333
bbox_list = [mercantile.bounds(tile.x, tile.y, tile.z) for tile in tiles]
3434
bbox_polygons = [box(*bbox) for bbox in bbox_list]
@@ -233,6 +233,7 @@ def get_image_metadata(
233233
organization_id: str = None,
234234
start_time: str = None,
235235
end_time: str = None,
236+
randomize_order=False,
236237
sampling_threshold=None,
237238
):
238239
aoi_polygon = geojson_to_polygon(aoi_geojson)
@@ -245,27 +246,34 @@ def get_image_metadata(
245246
downloaded_metadata["geometry"].apply(lambda geom: isinstance(geom, Point))
246247
]
247248

248-
filtered_metadata = filter_results(
249-
downloaded_metadata, creator_id, is_pano, organization_id, start_time, end_time
249+
downloaded_metadata = filter_results(
250+
downloaded_metadata,
251+
creator_id,
252+
is_pano,
253+
organization_id,
254+
start_time,
255+
end_time,
250256
)
251257

252258
if (
253-
filtered_metadata is None
254-
or filtered_metadata.empty
255-
or filtered_metadata.isna().all().all()
259+
downloaded_metadata is None
260+
or downloaded_metadata.empty
261+
or downloaded_metadata.isna().all().all()
256262
):
257263
raise ValueError("No Mapillary Features in the AoI match the filter criteria.")
258264

259-
if sampling_threshold is not None:
260-
filtered_metadata = spatial_sampling(filtered_metadata, sampling_threshold)
265+
downloaded_metadata = spatial_sampling(downloaded_metadata, sampling_threshold)
261266

262-
total_images = len(filtered_metadata)
267+
if randomize_order is True:
268+
downloaded_metadata = downloaded_metadata.sample(frac=1).reset_index(drop=True)
269+
270+
total_images = len(downloaded_metadata)
263271
if total_images > 100000:
264272
raise ValueError(
265273
f"Too many Images with selected filter options for the AoI: {total_images}"
266274
)
267275

268276
return {
269-
"ids": filtered_metadata["id"].tolist(),
270-
"geometries": filtered_metadata["geometry"].tolist(),
277+
"ids": downloaded_metadata["id"].tolist(),
278+
"geometries": downloaded_metadata["geometry"].tolist(),
271279
}

mapswipe_workers/mapswipe_workers/utils/spatial_sampling.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,11 @@ def spatial_sampling(df, interval_length):
141141
for sequence in sorted_df["sequence_id"].unique():
142142
sequence_df = sorted_df[sorted_df["sequence_id"] == sequence]
143143

144-
filtered_sorted_sub_df = filter_points(sequence_df, interval_length)
145-
sampled_sequence_df = pd.concat(
146-
[sampled_sequence_df, filtered_sorted_sub_df], axis=0
147-
)
144+
if interval_length:
145+
sequence_df = filter_points(sequence_df, interval_length)
146+
sampled_sequence_df = pd.concat([sampled_sequence_df, sequence_df], axis=0)
147+
148+
# reverse order such that sequence are in direction of travel
149+
sampled_sequence_df = sampled_sequence_df.iloc[::-1]
148150

149151
return sampled_sequence_df

mapswipe_workers/tests/unittests/test_process_mapillary.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ def setUpClass(cls):
4848
def setUp(self):
4949
self.level = 14
5050
self.test_polygon = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
51-
self.test_multipolygon = MultiPolygon(
52-
[self.test_polygon, Polygon([(2, 2), (3, 2), (3, 3), (2, 3)])]
53-
)
5451
self.empty_polygon = Polygon()
5552
self.empty_geometry = GeometryCollection()
5653

@@ -60,9 +57,19 @@ def test_create_tiles_with_valid_polygon(self):
6057
self.assertFalse(tiles.empty)
6158

6259
def test_create_tiles_with_multipolygon(self):
63-
tiles = create_tiles(self.test_multipolygon, self.level)
60+
polygon = Polygon(
61+
[
62+
(0.00000000, 0.00000000),
63+
(0.000000001, 0.00000000),
64+
(0.00000000, 0.000000001),
65+
(0.00000000, 0.000000001),
66+
]
67+
)
68+
multipolygon = MultiPolygon([polygon, polygon])
69+
tiles = create_tiles(multipolygon, self.level)
6470
self.assertIsInstance(tiles, pd.DataFrame)
6571
self.assertFalse(tiles.empty)
72+
self.assertEqual(len(tiles), 1)
6673

6774
def test_create_tiles_with_empty_polygon(self):
6875
tiles = create_tiles(self.empty_polygon, self.level)
@@ -343,7 +350,11 @@ def test_get_image_metadata_empty_response(self, mock_coordinate_download):
343350
def test_get_image_metadata_size_restriction(
344351
self, mock_coordinate_download, mock_filter_results
345352
):
346-
mock_filter_results.return_value = pd.DataFrame({"ID": range(1, 100002)})
353+
mock_df = pd.DataFrame({"ID": range(1, 100002)})
354+
mock_df["geometry"] = self.test_polygon
355+
mock_df["captured_at"] = range(1, 100002)
356+
mock_df["sequence_id"] = 1
357+
mock_filter_results.return_value = mock_df
347358
mock_coordinate_download.return_value = self.fixture_df
348359

349360
with self.assertRaises(ValueError):
Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,32 @@
11
import os
2-
32
import unittest
3+
44
import numpy as np
55
import pandas as pd
66
from shapely import wkt
77
from shapely.geometry import Point
88

9-
from mapswipe_workers.utils.spatial_sampling import distance_on_sphere, filter_points, spatial_sampling
9+
from mapswipe_workers.utils.spatial_sampling import (
10+
distance_on_sphere,
11+
filter_points,
12+
spatial_sampling,
13+
)
1014

1115

1216
class TestDistanceCalculations(unittest.TestCase):
13-
1417
@classmethod
1518
def setUpClass(cls):
1619
with open(
17-
os.path.join(
18-
os.path.dirname(os.path.abspath(__file__)),
19-
"..",
20-
"fixtures",
21-
"mapillary_sequence.csv",
22-
),
23-
"r",
20+
os.path.join(
21+
os.path.dirname(os.path.abspath(__file__)),
22+
"..",
23+
"fixtures",
24+
"mapillary_sequence.csv",
25+
),
26+
"r",
2427
) as file:
2528
df = pd.read_csv(file)
26-
df['geometry'] = df['geometry'].apply(wkt.loads)
29+
df["geometry"] = df["geometry"].apply(wkt.loads)
2730

2831
cls.fixture_df = df
2932

@@ -42,41 +45,43 @@ def test_filter_points(self):
4245
"POINT (-74.006 40.7128)",
4346
"POINT (-75.006 41.7128)",
4447
"POINT (-76.006 42.7128)",
45-
"POINT (-77.006 43.7128)"
48+
"POINT (-77.006 43.7128)",
4649
]
4750
}
4851
df = pd.DataFrame(data)
4952

50-
df['geometry'] = df['geometry'].apply(wkt.loads)
53+
df["geometry"] = df["geometry"].apply(wkt.loads)
5154

52-
df['long'] = df['geometry'].apply(lambda geom: geom.x if geom.geom_type == 'Point' else None)
53-
df['lat'] = df['geometry'].apply(lambda geom: geom.y if geom.geom_type == 'Point' else None)
55+
df["long"] = df["geometry"].apply(
56+
lambda geom: geom.x if geom.geom_type == "Point" else None
57+
)
58+
df["lat"] = df["geometry"].apply(
59+
lambda geom: geom.y if geom.geom_type == "Point" else None
60+
)
5461
threshold_distance = 100
5562
filtered_df = filter_points(df, threshold_distance)
5663

5764
self.assertIsInstance(filtered_df, pd.DataFrame)
5865
self.assertLessEqual(len(filtered_df), len(df))
5966

60-
6167
def test_spatial_sampling_ordering(self):
6268
data = {
6369
"geometry": [
6470
"POINT (-74.006 40.7128)",
6571
"POINT (-75.006 41.7128)",
6672
"POINT (-76.006 42.7128)",
67-
"POINT (-77.006 43.7128)"
73+
"POINT (-77.006 43.7128)",
6874
],
69-
'captured_at': [1, 2, 3, 4],
70-
'sequence_id': ['1', '1', '1', '1']
75+
"captured_at": [1, 2, 3, 4],
76+
"sequence_id": ["1", "1", "1", "1"],
7177
}
7278
df = pd.DataFrame(data)
73-
df['geometry'] = df['geometry'].apply(wkt.loads)
79+
df["geometry"] = df["geometry"].apply(wkt.loads)
7480

7581
interval_length = 0.1
7682
filtered_gdf = spatial_sampling(df, interval_length)
7783

78-
self.assertTrue(filtered_gdf['captured_at'].is_monotonic_increasing)
79-
84+
self.assertTrue(filtered_gdf["captured_at"].is_monotonic_decreasing)
8085

8186
def test_spatial_sampling_with_sequence(self):
8287
threshold_distance = 0.01
@@ -86,15 +91,13 @@ def test_spatial_sampling_with_sequence(self):
8691

8792
filtered_df.reset_index(drop=True, inplace=True)
8893
for i in range(len(filtered_df) - 1):
89-
geom1 = filtered_df.loc[i, 'geometry']
90-
geom2 = filtered_df.loc[i + 1, 'geometry']
94+
geom1 = filtered_df.loc[i, "geometry"]
95+
geom2 = filtered_df.loc[i + 1, "geometry"]
9196

9297
distance = geom1.distance(geom2)
9398

9499
self.assertLess(distance, threshold_distance)
95100

96101

97-
98-
99102
if __name__ == "__main__":
100103
unittest.main()

0 commit comments

Comments
 (0)