Skip to content

Commit 84aeb92

Browse files
committed
merge multiPolygons into dev
2 parents 3146806 + f401e03 commit 84aeb92

28 files changed

+707
-118
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ mapswipe_workers/config/configuration.json
120120
# don´t upload data dir
121121
data/
122122

123+
mapswipe-data/
124+
123125
# don't upload app config for project managers dashboard
124126
app.js
125127

manager_dashboard/manager_dashboard/js/forms.js

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -161,35 +161,42 @@ function openFile(event) {
161161
try {
162162
var text = reader.result;
163163
var geojsonData = JSON.parse(text)
164-
165164
// check number of features
166165
numberOfFeatures = geojsonData['features'].length
166+
167167
console.log('number of features: ' + numberOfFeatures)
168-
if (numberOfFeatures > 1) {
168+
if (numberOfFeatures > 10) {
169169
throw 'too many features: ' + numberOfFeatures
170170
}
171171
info_output.innerHTML += 'Number of Features: ' + numberOfFeatures + '<br>';
172172
info_output.style.display = 'block'
173173

174+
sumArea = 0
174175
// check input geometry type
175-
feature = geojsonData['features'][0]
176-
type = turf.getType(feature)
177-
console.log('geometry type: ' + type)
178-
if (type !== 'Polygon' & type !== 'MultiPolygon') {
179-
throw 'wrong geometry type: ' + type
180-
}
181-
info_output.innerHTML += 'Feature Type: ' + type + '<br>';
182-
info_output.style.display = 'block'
176+
for (var i =0; i < geojsonData.features.length; i++) {
177+
feature = geojsonData.features[i]
178+
type = turf.getType(feature)
179+
console.log('geometry type: ' + type)
180+
181+
if (type !== 'Polygon' & type !== 'MultiPolygon') {
182+
throw 'GeoJson contains one or more wrong geometry type(s): ' + type
183+
}
184+
185+
info_output.innerHTML += 'Feature Type: ' + type + '<br>';
186+
info_output.style.display = 'block'
187+
sumArea += turf.area(feature)/1000000 // area in square kilometers
188+
}
183189

184190
// check project size, based on zoom level
185191
var zoomLevel = parseInt(document.getElementById('zoomLevel').value);
186-
area = turf.area(feature)/1000000 // area in square kilometers
187192
maxArea = (23 - zoomLevel) * (23 - zoomLevel) * 200
188-
console.log('project size: ' + area + ' sqkm')
189-
if (area > maxArea) {
190-
throw 'project is to large: ' + area + ' sqkm; ' + 'max allowed size for this zoom level: ' + maxArea + ' sqkm'
193+
console.log('project size: ' + sumArea + ' sqkm')
194+
195+
if (sumArea > maxArea) {
196+
throw 'project is to large: ' + sumArea + ' sqkm; ' + 'max allowed size for this zoom level: ' + maxArea + ' sqkm'
191197
}
192-
info_output.innerHTML += 'Project Size: ' + area + ' sqkm<br>';
198+
199+
info_output.innerHTML += 'Project Size: ' + sumArea + ' sqkm<br>';
193200
info_output.style.display = 'block'
194201

195202
// add feature to map

mapswipe_workers/mapswipe_workers/definitions.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
os.makedirs(DATA_PATH)
1313
LOGGING_FILE_PATH = os.path.join(DATA_PATH, "mapswipe_workers.log")
1414

15+
# number of geometries for project geometries
16+
MAX_INPUT_GEOMETRIES = 10
17+
1518
LOGGING_CONFIG = {
1619
"version": 1,
1720
"disable_existing_loggers": True,
@@ -147,7 +150,7 @@ def tutorial(self):
147150
)
148151

149152
# TODO: implement for arbitrary geometries
150-
# from mapswipe_workers.project_types.arbitrary_geometries.arbitrary_geometries_tutorial import (
153+
# from mapswipe_workers.project_types.arbitrary_geometries.arbitrary_geometries_tutorial import ( # noqa E501
151154
# ArbitraryGeometriesTutorial,
152155
# )
153156

mapswipe_workers/mapswipe_workers/mapswipe_workers.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ def run_create_projects():
7575
try:
7676
# Create a project object using appropriate class (project type).
7777
project = ProjectType(project_type).constructor(project_draft)
78+
# TODO: here the project.geometry attribute is overwritten
79+
# this is super confusing since it's not a geojson anymore
80+
# but this is what we set initially,
81+
# e.g. in tile_map_service_grid/project.py
82+
# project.geometry is set to a list of wkt geometries now
83+
# this can't be handled in postgres,
84+
# postgres expects just a string not an array
85+
# validated_geometries should be called during init already
86+
# for the respective project types
7887
project.geometry = project.validate_geometries()
7988
project.create_groups()
8089
project.calc_required_results()

mapswipe_workers/mapswipe_workers/project_types/base/project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def save_to_postgres(self, project, groups, groupsOfTasks):
230230
VALUES (
231231
%s -- created
232232
,%s -- createdBy
233-
,ST_Force2D(ST_Multi(ST_GeomFromText(%s, 4326))) -- geometry
233+
,ST_Force2D(ST_GeomFromText(%s, 4326)) -- geometry
234234
,%s -- image
235235
,%s -- isFeatured
236236
,%s -- lookFor

mapswipe_workers/mapswipe_workers/project_types/tile_map_service_grid/project.py

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
import os
33

44
from mapswipe_workers.project_types.base.project import BaseProject
5-
from mapswipe_workers.definitions import DATA_PATH, CustomError, logger
5+
from mapswipe_workers.definitions import (
6+
DATA_PATH,
7+
CustomError,
8+
logger,
9+
MAX_INPUT_GEOMETRIES,
10+
)
611
from mapswipe_workers.project_types.tile_map_service_grid.group import Group
712
from mapswipe_workers.utils import tile_grouping_functions as grouping_functions
813
from mapswipe_workers.project_types.base.tile_server import BaseTileServer
@@ -14,6 +19,7 @@ def __init__(self, project_draft: dict):
1419
super().__init__(project_draft)
1520
self.project_type = project_draft["projectType"]
1621
self.groupSize = project_draft["groupSize"]
22+
# Note: this will be overwritten by validate_geometry in mapswipe_workers.py
1723
self.geometry = project_draft["geometry"]
1824
self.zoomLevel = int(project_draft.get("zoomLevel", 18))
1925
self.tileServer = vars(BaseTileServer(project_draft["tileServer"]))
@@ -58,19 +64,29 @@ def validate_geometries(self):
5864
raise CustomError(f"Empty file. ")
5965

6066
# check if more than 1 geometry is provided
61-
elif layer.GetFeatureCount() > 1:
67+
elif layer.GetFeatureCount() > MAX_INPUT_GEOMETRIES:
6268
logger.warning(
6369
f"{self.projectId}"
6470
f" - validate geometry - "
65-
f"Input file contains more than one geometry. "
66-
f"Make sure to provide exact one input geometry."
71+
f"Input file contains more than {MAX_INPUT_GEOMETRIES} geometries. "
72+
f"Make sure to provide less than {MAX_INPUT_GEOMETRIES} geometries."
73+
)
74+
raise CustomError(
75+
f"Input file contains more than {MAX_INPUT_GEOMETRIES} geometries. "
6776
)
68-
raise CustomError(f"Input file contains more than one geometry. ")
6977

78+
project_area = 0
79+
geometry_collection = ogr.Geometry(ogr.wkbMultiPolygon)
7080
# check if the input geometry is a valid polygon
7181
for feature in layer:
7282
feat_geom = feature.GetGeometryRef()
7383
geom_name = feat_geom.GetGeometryName()
84+
# add geometry to geometry collection
85+
if geom_name == "MULTIPOLYGON":
86+
for singlepart_polygon in feat_geom:
87+
geometry_collection.AddGeometry(singlepart_polygon)
88+
if geom_name == "POLYGON":
89+
geometry_collection.AddGeometry(feat_geom)
7490
if not feat_geom.IsValid():
7591
logger.warning(
7692
f"{self.projectId}"
@@ -91,9 +107,6 @@ def validate_geometries(self):
91107
)
92108
raise CustomError(f"Invalid geometry type: {geom_name}. ")
93109

94-
# get geometry as wkt
95-
wkt_geometry = feat_geom.ExportToWkt()
96-
97110
# check size of project make sure its smaller than 5,000 sqkm
98111
# for doing this we transform the geometry
99112
# into Mollweide projection (EPSG Code 54009)
@@ -105,47 +118,47 @@ def validate_geometries(self):
105118

106119
transform = osr.CoordinateTransformation(source, target)
107120
feat_geom.Transform(transform)
108-
project_area = feat_geom.GetArea() / 1000000
109-
110-
# calculate max area based on zoom level
111-
# for zoom level 18 this will be 5000 square kilometers
112-
# max zoom level is 22
113-
if self.zoomLevel > 22:
114-
raise CustomError(
115-
f"zoom level is to large (max: 22): {self.zoomLevel}."
116-
)
121+
project_area = +feat_geom.GetArea() / 1000000
117122

118-
max_area = (23 - int(self.zoomLevel)) * (23 - int(self.zoomLevel)) * 200
123+
# calculate max area based on zoom level
124+
# for zoom level 18 this will be 5000 square kilometers
125+
# max zoom level is 22
126+
if self.zoomLevel > 22:
127+
raise CustomError(f"zoom level is to large (max: 22): {self.zoomLevel}.")
119128

120-
if project_area > max_area:
121-
logger.warning(
122-
f"{self.projectId}"
123-
f" - validate geometry - "
124-
f"Project is to large: {project_area} sqkm. "
125-
f"Please split your projects into smaller sub-projects and resubmit"
126-
)
127-
raise CustomError(
128-
f"Project is to large: {project_area} sqkm. "
129-
f"Max area for zoom level {self.zoomLevel} = {max_area} sqkm"
130-
)
129+
max_area = (23 - int(self.zoomLevel)) * (23 - int(self.zoomLevel)) * 200
130+
131+
if project_area > max_area:
132+
logger.warning(
133+
f"{self.projectId}"
134+
f" - validate geometry - "
135+
f"Project is to large: {project_area} sqkm. "
136+
f"Please split your projects into smaller sub-projects and resubmit"
137+
)
138+
raise CustomError(
139+
f"Project is to large: {project_area} sqkm. "
140+
f"Max area for zoom level {self.zoomLevel} = {max_area} sqkm"
141+
)
131142

132143
del datasource
133144
del layer
134145

135146
self.validInputGeometries = raw_input_file
136-
137147
logger.info(
138148
f"{self.projectId}" f" - validate geometry - " f"input geometry is correct."
139149
)
140150

141-
return wkt_geometry
151+
dissolved_geometry = geometry_collection.UnionCascaded()
152+
wkt_geometry_collection = dissolved_geometry.ExportToWkt()
153+
154+
return wkt_geometry_collection
142155

143156
def create_groups(self):
144157
"""
145158
The function to create groups from the project extent
146159
"""
147160
# first step get properties of each group from extent
148-
raw_groups = grouping_functions.extent_to_slices(
161+
raw_groups = grouping_functions.extent_to_groups(
149162
self.validInputGeometries, self.zoomLevel, self.groupSize
150163
)
151164

0 commit comments

Comments
 (0)