Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 61 additions & 14 deletions mapswipe_workers/mapswipe_workers/definitions.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import logging.config
import os
import sentry_sdk
from xdg import XDG_DATA_HOME
from mapswipe_workers.config import SENTRY_DSN
from enum import Enum

import sentry_sdk
from xdg import XDG_DATA_HOME

class CustomError(Exception):
pass


class MessageType(Enum):
SUCCESS = 1
FAIL = 2
NOTIFICATION_90 = 3
NOTIFICATION_100 = 4

from mapswipe_workers.config import SENTRY_DSN

DATA_PATH = os.path.join(XDG_DATA_HOME, "mapswipe_workers")
if not os.path.exists(DATA_PATH):
Expand All @@ -27,7 +17,7 @@ class MessageType(Enum):
"disable_existing_loggers": True,
"formatters": {
"standard": {
"format": "%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(message)s"
"format": "%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(message)s" # noqa: E501
},
},
"handlers": {
Expand Down Expand Up @@ -104,3 +94,60 @@ class MessageType(Enum):
+ "tilematrix={z}&tilecol={x}&tilerow={y}&layer={layer}"
),
}


class CustomError(Exception):
pass


class MessageType(Enum):
SUCCESS = 1
FAIL = 2
NOTIFICATION_90 = 3
NOTIFICATION_100 = 4


class ProjectType(Enum):
"""
Definition of Project Type names, identifiers and constructors.

There are different project types with the same constructor.
Get the class constructor of a project type with:
ProjectType(1).constructor
"""

BUILD_AREA = 1
FOOTPRINT = 2
CHANGE_DETECTION = 3

@property
def constructor(self):
# Imports are first made once this method get called to avoid circular imports.
from mapswipe_workers.project_types.tile_map_service_grid.project import (
Project as tmsg_project,
)
from mapswipe_workers.project_types.arbitrary_geometry.project import (
Project as ag_project,
)

project_type_classes = {
1: tmsg_project,
2: ag_project,
3: tmsg_project,
}
return project_type_classes[self.value]

@property
def tutorial(self):
from mapswipe_workers.project_types.tile_map_service_grid import (
build_area_tutorial,
)
from mapswipe_workers.project_types.tile_map_service_grid import (
change_detection_tutorial,
)

project_type_tutorial = {
1: build_area_tutorial,
3: change_detection_tutorial,
}
return project_type_tutorial[self.value]
42 changes: 13 additions & 29 deletions mapswipe_workers/mapswipe_workers/mapswipe_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,29 @@
import json
import time

import click
import schedule as sched

import click
from mapswipe_workers import auth
from mapswipe_workers.definitions import CustomError, logger, sentry, MessageType
from mapswipe_workers.definitions import (
CustomError,
MessageType,
ProjectType,
logger,
sentry,
)
from mapswipe_workers.firebase_to_postgres import (
archive_project,
delete_project,
transfer_results,
update_data,
)
from mapswipe_workers.generate_stats import generate_stats
from mapswipe_workers.project_types.build_area import build_area_tutorial
from mapswipe_workers.project_types.build_area.build_area_project import (
BuildAreaProject,
)
from mapswipe_workers.project_types.change_detection import change_detection_tutorial
from mapswipe_workers.project_types.change_detection.change_detection_project import (
ChangeDetectionProject,
)
from mapswipe_workers.project_types.footprint.footprint_project import FootprintProject
from mapswipe_workers.utils import user_management
from mapswipe_workers.utils.create_directories import create_directories
from mapswipe_workers.utils.slack_helper import (
send_slack_message,
send_progress_notification,
send_slack_message,
)


Expand Down Expand Up @@ -63,12 +60,6 @@ def run_create_projects():
Save created projects, groups and tasks to Firebase and Postgres.
"""

project_type_classes = {
1: BuildAreaProject,
2: FootprintProject,
3: ChangeDetectionProject,
}

fb_db = auth.firebaseDB()
ref = fb_db.reference("v2/projectDrafts/")
project_drafts = ref.get()
Expand All @@ -83,7 +74,7 @@ def run_create_projects():
project_name = project_draft["name"]
try:
# Create a project object using appropriate class (project type).
project = project_type_classes[project_type](project_draft)
project = ProjectType(project_type).constructor(project_draft)
project.geometry = project.validate_geometries()
project.create_groups()
project.calc_required_results()
Expand Down Expand Up @@ -176,16 +167,9 @@ def run_create_tutorial(input_file) -> None:
try:
logger.info(f"will generate tutorial based on {input_file}")
with open(input_file) as json_file:
tutorial = json.load(json_file)

project_type = tutorial["projectType"]

project_types_tutorial = {
# Make sure to import all project types here
1: build_area_tutorial.create_tutorial,
3: change_detection_tutorial.create_tutorial,
}
project_types_tutorial[project_type](tutorial)
tutorial_data = json.load(json_file)
project_type = tutorial_data["projectType"]
ProjectType(project_type).tutorial(tutorial_data)
except Exception:
logger.exception()
sentry.capture_exception()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import List

from mapswipe_workers.project_types.base.group import BaseGroup
from mapswipe_workers.project_types.arbitrary_geometry.task import Task


class Group(BaseGroup):
def __init__(self, project: object, groupId: int) -> None:
super().__init__(project, groupId)

def create_tasks(self, feature_ids: List, feature_geometries: List) -> None:
"""Create tasks for a group

feature_geometries is a list of geometries or feature in geojson format.
These consist two keys: Coordinates and type.
Coordinates of four two pair coordinates.
Every coordinate pair is a vertex.
"""
for i in range(0, len(feature_ids)):
task = Task(self, feature_ids[i], feature_geometries[i])
self.tasks.append(task)
self.numberOfTasks = len(self.tasks)
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,26 @@


########################################################################################################################
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('-i', '--input_file', required=False, default=None, type=str,
help='the input file containning the geometries as geojson')
parser.add_argument('-g', '--group_size', required=False, default=50, type=int,
help='the size of each group')
parser = argparse.ArgumentParser(description="Process some integers.")
parser.add_argument(
"-i",
"--input_file",
required=False,
default=None,
type=str,
help="the input file containning the geometries as geojson",
)
parser.add_argument(
"-g",
"--group_size",
required=False,
default=50,
type=int,
help="the size of each group",
)
########################################################################################################################


def group_input_geometries(input_geometries_file, group_size):
"""
The function to create groups of input geometries using the given size (number of features) per group
Expand All @@ -28,43 +41,42 @@ def group_input_geometries(input_geometries_file, group_size):
the dictionary containing a list of "feature_ids" and a list of "feature_geometries" per group with given group id key
"""

driver = ogr.GetDriverByName('GeoJSON')
driver = ogr.GetDriverByName("GeoJSON")
datasource = driver.Open(input_geometries_file, 0)
layer = datasource.GetLayer()

groups = {}

# we will simply, we will start with min group id = 100
group_id = 100
group_id_string = f'g{group_id}'
group_id_string = f"g{group_id}"
feature_count = 0
for feature in layer:
feature_count += 1
if feature_count % (group_size+1) == 0:
if feature_count % (group_size + 1) == 0:
group_id += 1
group_id_string = f'g{group_id}'
group_id_string = f"g{group_id}"

try:
groups[group_id_string]
except:
groups[group_id_string] = {
"feature_ids": [],
"feature_geometries": []
}
groups[group_id_string] = {"feature_ids": [], "feature_geometries": []}

groups[group_id_string]['feature_ids'].append(feature.GetFID())
groups[group_id_string]['feature_geometries'].append(json.loads(feature.GetGeometryRef().ExportToJson()))
groups[group_id_string]["feature_ids"].append(feature.GetFID())
groups[group_id_string]["feature_geometries"].append(
json.loads(feature.GetGeometryRef().ExportToJson())
)

return groups


########################################################################################################################
if __name__ == '__main__':
if __name__ == "__main__":

try:
args = parser.parse_args()
except:
print('have a look at the input arguments, something went wrong there.')
print("have a look at the input arguments, something went wrong there.")

groups = group_input_geometries(args.input_file, args.group_size)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
import os
import urllib.request
from osgeo import ogr

from mapswipe_workers.definitions import DATA_PATH
from mapswipe_workers.definitions import CustomError
from mapswipe_workers.definitions import logger
from mapswipe_workers.base.base_project import BaseProject
from mapswipe_workers.project_types.footprint import grouping_functions as g
from mapswipe_workers.project_types.footprint.footprint_group import FootprintGroup


class FootprintProject(BaseProject):
"""
The subclass for an import of the type Footprint
"""
from mapswipe_workers.project_types.base.project import BaseProject
from mapswipe_workers.definitions import DATA_PATH, CustomError, logger
from mapswipe_workers.project_types.arbitrary_geometry import grouping_functions as g
from mapswipe_workers.project_types.arbitrary_geometry.group import Group
from osgeo import ogr

project_type = 2
project_type_name = "Footprint"

def __init__(self, project_draft):
# this will create the basis attributes
class Project(BaseProject):
def __init__(self, project_draft: dict) -> None:
super().__init__(project_draft)

# set group size
Expand Down Expand Up @@ -80,7 +70,7 @@ def validate_geometries(self):
raise Exception(err)

# get geometry as wkt
# for footprint type project we get the bounding box / extent of the layer
# get the bounding box/ extent of the layer
extent = layer.GetExtent()
# Create a Polygon from the extent tuple
ring = ogr.Geometry(ogr.wkbLinearRing)
Expand Down Expand Up @@ -148,14 +138,10 @@ def validate_geometries(self):
return wkt_geometry

def create_groups(self):
"""
The function to create groups of footprint geometries
"""

raw_groups = g.group_input_geometries(self.validInputGeometries, self.groupSize)

for group_id, item in raw_groups.items():
group = FootprintGroup(self, group_id)
group = Group(self, group_id)
group.create_tasks(item["feature_ids"], item["feature_geometries"])
self.groups.append(group)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from mapswipe_workers.project_types.base.task import BaseTask
from osgeo import ogr


class Task(BaseTask):
def __init__(self, group: object, featureId: int, featureGeometry: dict):
"""
Parameters
----------
feature_geometry: dict
The geometries or feature in geojson format.
It consist of two keys: Coordinates and type.
Coordinates of four two pair coordinates.
Every coordinate pair is a vertex.
"""
task_id = f"t{featureId}"
super().__init__(group, taskId=task_id)
self.geojson = featureGeometry

# create wkt geometry from geojson
poly = ogr.CreateGeometryFromJson(str(featureGeometry))
wkt_geometry = poly.ExportToWkt()
self.geometry = wkt_geometry
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class BaseGroup(metaclass=ABCMeta):
completedCount: int
Number of users who finished the group
neededCount: int
Required number of users left to finish the group. Decreases with the increase of completedCount
Required number of users left to finish the group.
Decreases with the increase of completedCount.
count: int
Number of tasks associated with the group
"""
Expand Down Expand Up @@ -45,11 +46,11 @@ def __init__(self, project, groupId):

@abstractmethod
def create_tasks():
'''
"""
Create tasks as task object for one group
and appends those to a tasks list of the group object.

The number of tasks has to be calculated
and saved to the numberOfTasks attribute of the group object.
'''
"""
pass
Loading