OTAnalytics 0.5.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- OTAnalytics/__init__.py +0 -0
- OTAnalytics/__main__.py +13 -0
- OTAnalytics/adapter_intersect/__init__.py +0 -0
- OTAnalytics/adapter_ui/__init__.py +0 -0
- OTAnalytics/adapter_ui/abstract_button_quick_save_config.py +12 -0
- OTAnalytics/adapter_ui/abstract_canvas.py +25 -0
- OTAnalytics/adapter_ui/abstract_frame.py +19 -0
- OTAnalytics/adapter_ui/abstract_frame_canvas.py +17 -0
- OTAnalytics/adapter_ui/abstract_frame_filter.py +50 -0
- OTAnalytics/adapter_ui/abstract_frame_project.py +27 -0
- OTAnalytics/adapter_ui/abstract_frame_remark.py +7 -0
- OTAnalytics/adapter_ui/abstract_frame_track_plotting.py +11 -0
- OTAnalytics/adapter_ui/abstract_frame_track_statistics.py +13 -0
- OTAnalytics/adapter_ui/abstract_frame_tracks.py +29 -0
- OTAnalytics/adapter_ui/abstract_main_window.py +9 -0
- OTAnalytics/adapter_ui/abstract_progressbar_popup.py +38 -0
- OTAnalytics/adapter_ui/abstract_treeview_interface.py +31 -0
- OTAnalytics/adapter_ui/default_values.py +12 -0
- OTAnalytics/adapter_ui/dto.py +6 -0
- OTAnalytics/adapter_ui/flow_adapter.py +54 -0
- OTAnalytics/adapter_ui/helpers.py +41 -0
- OTAnalytics/adapter_ui/text_resources.py +51 -0
- OTAnalytics/adapter_ui/ui_texts.py +29 -0
- OTAnalytics/adapter_ui/view_model.py +447 -0
- OTAnalytics/adapter_visualization/__init__.py +0 -0
- OTAnalytics/adapter_visualization/color_provider.py +87 -0
- OTAnalytics/application/__init__.py +0 -0
- OTAnalytics/application/analysis/__init__.py +0 -0
- OTAnalytics/application/analysis/intersect.py +40 -0
- OTAnalytics/application/analysis/traffic_counting.py +945 -0
- OTAnalytics/application/analysis/traffic_counting_specification.py +60 -0
- OTAnalytics/application/application.py +713 -0
- OTAnalytics/application/config.py +57 -0
- OTAnalytics/application/config_specification.py +54 -0
- OTAnalytics/application/datastore.py +456 -0
- OTAnalytics/application/eventlist.py +162 -0
- OTAnalytics/application/exception.py +31 -0
- OTAnalytics/application/export_formats/__init__.py +0 -0
- OTAnalytics/application/export_formats/event_list.py +23 -0
- OTAnalytics/application/export_formats/export_mode.py +41 -0
- OTAnalytics/application/export_formats/road_user_assignments.py +46 -0
- OTAnalytics/application/export_formats/track_statistics.py +17 -0
- OTAnalytics/application/geometry.py +24 -0
- OTAnalytics/application/logger.py +51 -0
- OTAnalytics/application/parser/__init__.py +0 -0
- OTAnalytics/application/parser/cli_parser.py +128 -0
- OTAnalytics/application/parser/config_parser.py +128 -0
- OTAnalytics/application/parser/deserializer.py +4 -0
- OTAnalytics/application/parser/flow_parser.py +41 -0
- OTAnalytics/application/playback.py +7 -0
- OTAnalytics/application/plotting.py +326 -0
- OTAnalytics/application/progress.py +95 -0
- OTAnalytics/application/project.py +161 -0
- OTAnalytics/application/run_configuration.py +225 -0
- OTAnalytics/application/state.py +711 -0
- OTAnalytics/application/track_filter.py +149 -0
- OTAnalytics/application/ui/__init__.py +0 -0
- OTAnalytics/application/ui/frame_control.py +152 -0
- OTAnalytics/application/use_cases/__init__.py +0 -0
- OTAnalytics/application/use_cases/add_new_remark.py +9 -0
- OTAnalytics/application/use_cases/apply_cli_cuts.py +47 -0
- OTAnalytics/application/use_cases/clear_repositories.py +53 -0
- OTAnalytics/application/use_cases/config.py +52 -0
- OTAnalytics/application/use_cases/config_has_changed.py +121 -0
- OTAnalytics/application/use_cases/create_events.py +171 -0
- OTAnalytics/application/use_cases/create_intersection_events.py +282 -0
- OTAnalytics/application/use_cases/cut_tracks_with_sections.py +78 -0
- OTAnalytics/application/use_cases/editor/__init__.py +0 -0
- OTAnalytics/application/use_cases/editor/section_editor.py +138 -0
- OTAnalytics/application/use_cases/event_repository.py +65 -0
- OTAnalytics/application/use_cases/export_events.py +50 -0
- OTAnalytics/application/use_cases/filter_visualization.py +76 -0
- OTAnalytics/application/use_cases/flow_repository.py +101 -0
- OTAnalytics/application/use_cases/flow_statistics.py +27 -0
- OTAnalytics/application/use_cases/generate_flows.py +170 -0
- OTAnalytics/application/use_cases/get_current_project.py +10 -0
- OTAnalytics/application/use_cases/get_current_remark.py +9 -0
- OTAnalytics/application/use_cases/get_road_user_assignments.py +23 -0
- OTAnalytics/application/use_cases/highlight_intersections.py +388 -0
- OTAnalytics/application/use_cases/inside_cutting_section.py +88 -0
- OTAnalytics/application/use_cases/intersection_repository.py +37 -0
- OTAnalytics/application/use_cases/load_otconfig.py +76 -0
- OTAnalytics/application/use_cases/load_otflow.py +94 -0
- OTAnalytics/application/use_cases/load_track_files.py +84 -0
- OTAnalytics/application/use_cases/number_of_tracks_to_be_validated.py +7 -0
- OTAnalytics/application/use_cases/preload_input_files.py +34 -0
- OTAnalytics/application/use_cases/quick_save_configuration.py +37 -0
- OTAnalytics/application/use_cases/reset_project_config.py +16 -0
- OTAnalytics/application/use_cases/road_user_assignment_export.py +259 -0
- OTAnalytics/application/use_cases/save_otflow.py +46 -0
- OTAnalytics/application/use_cases/section_repository.py +198 -0
- OTAnalytics/application/use_cases/start_new_project.py +39 -0
- OTAnalytics/application/use_cases/suggest_save_path.py +113 -0
- OTAnalytics/application/use_cases/track_export.py +57 -0
- OTAnalytics/application/use_cases/track_repository.py +205 -0
- OTAnalytics/application/use_cases/track_statistics.py +167 -0
- OTAnalytics/application/use_cases/track_statistics_export.py +140 -0
- OTAnalytics/application/use_cases/track_to_video_repository.py +16 -0
- OTAnalytics/application/use_cases/update_project.py +42 -0
- OTAnalytics/application/use_cases/video_repository.py +136 -0
- OTAnalytics/assets/OpenTrafficCam_800.png +0 -0
- OTAnalytics/domain/__init__.py +0 -0
- OTAnalytics/domain/common.py +27 -0
- OTAnalytics/domain/date.py +85 -0
- OTAnalytics/domain/event.py +588 -0
- OTAnalytics/domain/files.py +18 -0
- OTAnalytics/domain/filter.py +256 -0
- OTAnalytics/domain/flow.py +236 -0
- OTAnalytics/domain/geometry.py +194 -0
- OTAnalytics/domain/intersect.py +155 -0
- OTAnalytics/domain/observer.py +35 -0
- OTAnalytics/domain/progress.py +68 -0
- OTAnalytics/domain/remark.py +9 -0
- OTAnalytics/domain/section.py +483 -0
- OTAnalytics/domain/track.py +348 -0
- OTAnalytics/domain/track_dataset.py +431 -0
- OTAnalytics/domain/track_repository.py +269 -0
- OTAnalytics/domain/types.py +33 -0
- OTAnalytics/domain/video.py +339 -0
- OTAnalytics/helpers/__init__.py +0 -0
- OTAnalytics/helpers/time_profiling.py +20 -0
- OTAnalytics/plugin_datastore/__init__.py +0 -0
- OTAnalytics/plugin_datastore/python_track_store.py +837 -0
- OTAnalytics/plugin_datastore/track_geometry_store/__init__.py +0 -0
- OTAnalytics/plugin_datastore/track_geometry_store/pygeos_store.py +402 -0
- OTAnalytics/plugin_datastore/track_store.py +803 -0
- OTAnalytics/plugin_filter/__init__.py +0 -0
- OTAnalytics/plugin_filter/dataframe_filter.py +324 -0
- OTAnalytics/plugin_filter/pandas_track_id.py +23 -0
- OTAnalytics/plugin_intersect/__init__.py +0 -0
- OTAnalytics/plugin_intersect/shapely/__init__.py +0 -0
- OTAnalytics/plugin_intersect/shapely/mapping.py +57 -0
- OTAnalytics/plugin_intersect/simple/__init__.py +0 -0
- OTAnalytics/plugin_intersect/simple/cut_tracks_with_sections.py +82 -0
- OTAnalytics/plugin_intersect/simple_intersect.py +33 -0
- OTAnalytics/plugin_intersect_parallelization/__init__.py +0 -0
- OTAnalytics/plugin_intersect_parallelization/multiprocessing.py +50 -0
- OTAnalytics/plugin_intersect_parallelization/sequential.py +28 -0
- OTAnalytics/plugin_number_of_tracks_to_be_validated/__init__.py +0 -0
- OTAnalytics/plugin_number_of_tracks_to_be_validated/calculation_strategy.py +115 -0
- OTAnalytics/plugin_number_of_tracks_to_be_validated/metric_rates_builder.py +36 -0
- OTAnalytics/plugin_number_of_tracks_to_be_validated/otc_classes.py +22 -0
- OTAnalytics/plugin_number_of_tracks_to_be_validated/svz/__init__.py +0 -0
- OTAnalytics/plugin_number_of_tracks_to_be_validated/svz/metric_rates.py +23 -0
- OTAnalytics/plugin_number_of_tracks_to_be_validated/svz/number_of_tracks_to_be_validated.py +69 -0
- OTAnalytics/plugin_number_of_tracks_to_be_validated/tracks_as_dataframe_provider.py +38 -0
- OTAnalytics/plugin_parser/__init__.py +0 -0
- OTAnalytics/plugin_parser/argparse_cli_parser.py +189 -0
- OTAnalytics/plugin_parser/dataformat_versions.py +22 -0
- OTAnalytics/plugin_parser/export.py +290 -0
- OTAnalytics/plugin_parser/json_parser.py +70 -0
- OTAnalytics/plugin_parser/otconfig_parser.py +352 -0
- OTAnalytics/plugin_parser/ottrk_dataformat.py +63 -0
- OTAnalytics/plugin_parser/otvision_parser.py +1101 -0
- OTAnalytics/plugin_parser/pandas_parser.py +125 -0
- OTAnalytics/plugin_parser/road_user_assignment_export.py +78 -0
- OTAnalytics/plugin_parser/streaming_parser.py +349 -0
- OTAnalytics/plugin_parser/track_export.py +102 -0
- OTAnalytics/plugin_parser/track_statistics_export.py +137 -0
- OTAnalytics/plugin_progress/__init__.py +0 -0
- OTAnalytics/plugin_progress/multiprocessing_progress.py +48 -0
- OTAnalytics/plugin_progress/tqdm_progressbar.py +35 -0
- OTAnalytics/plugin_prototypes/__init__.py +0 -0
- OTAnalytics/plugin_prototypes/event_visualization.py +79 -0
- OTAnalytics/plugin_prototypes/eventlist_exporter/__init__.py +0 -0
- OTAnalytics/plugin_prototypes/eventlist_exporter/eventlist_exporter.py +354 -0
- OTAnalytics/plugin_prototypes/track_visualization/__init__.py +0 -0
- OTAnalytics/plugin_prototypes/track_visualization/track_viz.py +846 -0
- OTAnalytics/plugin_ui/__init__.py +0 -0
- OTAnalytics/plugin_ui/cli.py +489 -0
- OTAnalytics/plugin_ui/customtkinter_gui/__init__.py +0 -0
- OTAnalytics/plugin_ui/customtkinter_gui/abstract_ctk_frame.py +51 -0
- OTAnalytics/plugin_ui/customtkinter_gui/button_quick_save_config.py +22 -0
- OTAnalytics/plugin_ui/customtkinter_gui/canvas_observer.py +26 -0
- OTAnalytics/plugin_ui/customtkinter_gui/constants.py +70 -0
- OTAnalytics/plugin_ui/customtkinter_gui/custom_containers.py +164 -0
- OTAnalytics/plugin_ui/customtkinter_gui/dummy_viewmodel.py +1833 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_analysis.py +87 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_bbox_offset.py +90 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_canvas.py +223 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_configuration.py +36 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_date_filter_control.py +147 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_files.py +124 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_filter.py +860 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_flows.py +149 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_project.py +466 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_remarks.py +30 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_sections.py +171 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_track_plotting.py +155 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_track_statistics.py +159 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_tracks.py +94 -0
- OTAnalytics/plugin_ui/customtkinter_gui/frame_videos.py +107 -0
- OTAnalytics/plugin_ui/customtkinter_gui/gui.py +345 -0
- OTAnalytics/plugin_ui/customtkinter_gui/helpers.py +160 -0
- OTAnalytics/plugin_ui/customtkinter_gui/line_section.py +700 -0
- OTAnalytics/plugin_ui/customtkinter_gui/messagebox.py +136 -0
- OTAnalytics/plugin_ui/customtkinter_gui/scrollable_xy_frame.py +200 -0
- OTAnalytics/plugin_ui/customtkinter_gui/state.py +25 -0
- OTAnalytics/plugin_ui/customtkinter_gui/style.py +110 -0
- OTAnalytics/plugin_ui/customtkinter_gui/toplevel_export_counts.py +162 -0
- OTAnalytics/plugin_ui/customtkinter_gui/toplevel_export_events.py +121 -0
- OTAnalytics/plugin_ui/customtkinter_gui/toplevel_flows.py +228 -0
- OTAnalytics/plugin_ui/customtkinter_gui/toplevel_progress.py +168 -0
- OTAnalytics/plugin_ui/customtkinter_gui/toplevel_sections.py +127 -0
- OTAnalytics/plugin_ui/customtkinter_gui/toplevel_template.py +81 -0
- OTAnalytics/plugin_ui/customtkinter_gui/treeview_template.py +93 -0
- OTAnalytics/plugin_ui/customtkinter_gui/utility_widgets.py +38 -0
- OTAnalytics/plugin_ui/intersection_repository.py +34 -0
- OTAnalytics/plugin_ui/main_application.py +1373 -0
- OTAnalytics/plugin_ui/visualization/__init__.py +0 -0
- OTAnalytics/plugin_ui/visualization/visualization.py +981 -0
- OTAnalytics/plugin_video_processing/video_reader.py +165 -0
- OTAnalytics/version.py +1 -0
- otanalytics-0.5.3.dist-info/METADATA +45 -0
- otanalytics-0.5.3.dist-info/RECORD +217 -0
- otanalytics-0.5.3.dist-info/WHEEL +4 -0
- otanalytics-0.5.3.dist-info/licenses/LICENSE +674 -0
OTAnalytics/__init__.py
ADDED
|
File without changes
|
OTAnalytics/__main__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
3
|
+
from OTAnalytics.plugin_ui.main_application import ApplicationStarter
|
|
4
|
+
|
|
5
|
+
warnings.simplefilter(action="ignore", category=FutureWarning)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main() -> None:
|
|
9
|
+
ApplicationStarter().start()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
main()
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AbstractButtonQuickSaveConfig(ABC):
|
|
5
|
+
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def set_state_changed_color(self) -> None:
|
|
8
|
+
raise NotImplementedError
|
|
9
|
+
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def set_default_color(self) -> None:
|
|
12
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from customtkinter import CTkCanvas
|
|
4
|
+
|
|
5
|
+
from OTAnalytics.adapter_ui.helpers import WidgetPositionProvider
|
|
6
|
+
|
|
7
|
+
# from OTAnalytics.plugin_ui.canvas_observer import EventHandler
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AbstractCanvas(CTkCanvas, WidgetPositionProvider):
|
|
11
|
+
# TODO: Properly define abstract property here and in derived class(es)
|
|
12
|
+
# @property
|
|
13
|
+
# @abstractmethod
|
|
14
|
+
# def event_handler(self) -> EventHandler:
|
|
15
|
+
# pass
|
|
16
|
+
|
|
17
|
+
# TODO: Define whole interface (all properties and methods) required by viewmodel
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def introduce_to_viewmodel(self) -> None:
|
|
21
|
+
raise NotImplementedError
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def add_preview_image(self) -> None:
|
|
25
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AbstractFrame(ABC):
|
|
5
|
+
@abstractmethod
|
|
6
|
+
def set_enabled_general_buttons(self, enabled: bool) -> None:
|
|
7
|
+
raise NotImplementedError
|
|
8
|
+
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def set_enabled_add_buttons(self, enabled: bool) -> None:
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def set_enabled_change_single_item_buttons(self, enabled: bool) -> None:
|
|
15
|
+
raise NotImplementedError
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def set_enabled_change_multiple_items_buttons(self, enabled: bool) -> None:
|
|
19
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from OTAnalytics.domain.track import TrackImage
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AbstractFrameCanvas:
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def introduce_to_viewmodel(self) -> None:
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def update_background(self, image: TrackImage) -> None:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def clear_image(self) -> None:
|
|
17
|
+
pass
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from OTAnalytics.adapter_ui.dto import DateRangeDto
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AbstractFrameFilter(ABC):
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def _introduce_to_viewmodel(self) -> None:
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def set_active_color_on_filter_by_date_button(self) -> None:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def set_inactive_color_on_filter_by_date_button(self) -> None:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def set_active_color_on_filter_by_class_button(self) -> None:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def set_inactive_color_on_filter_by_class_button(self) -> None:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def enable_filter_by_date_button(self) -> None:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def disable_filter_by_date_button(self) -> None:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
def enable_filter_by_class_button(self) -> None:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
def disable_filter_by_class_button(self) -> None:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
def update_date_range(self, date_range: DateRangeDto) -> None:
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def reset(self) -> None:
|
|
49
|
+
"""Reset all filters."""
|
|
50
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AbstractFrameProject:
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def introduce_to_viewmodel(self) -> None:
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def update(self, name: str, start_date: Optional[datetime]) -> None:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def set_enabled_general_buttons(self, enabled: bool) -> None:
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AbstractFrameSvzMetadata:
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def introduce_to_viewmodel(self) -> None:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def update(self, metadata: dict) -> None:
|
|
27
|
+
pass
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from OTAnalytics.application.use_cases.track_statistics import TrackStatistics
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AbstractFrameTrackStatistics(ABC):
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def introduce_to_viewmodel(self) -> None:
|
|
9
|
+
raise NotImplementedError
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def update_track_statistics(self, track_statistics: TrackStatistics) -> None:
|
|
13
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from OTAnalytics.plugin_ui.customtkinter_gui.abstract_ctk_frame import AbstractCTkFrame
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AbstractFrameTracks(AbstractCTkFrame):
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def introduce_to_viewmodel(self) -> None:
|
|
9
|
+
raise NotImplementedError
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def update_offset(self, new_offset_x: float, new_offset_y: float) -> None:
|
|
13
|
+
raise NotImplementedError
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def configure_offset_button(self, color: str, enabled: bool) -> None:
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def enable_update_offset_button(self, enabled: bool) -> None:
|
|
21
|
+
raise NotImplementedError
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def set_offset_button_color(self, color: str) -> None:
|
|
25
|
+
raise NotImplementedError
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def get_default_offset_button_color(self) -> str:
|
|
29
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from tkinter import Widget
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from OTAnalytics.domain.progress import Counter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AbstractPopupProgressbar(ABC):
|
|
9
|
+
def update_progress(self) -> None:
|
|
10
|
+
raise NotImplementedError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ProgressbarPopupBuilder(ABC):
|
|
14
|
+
def __init__(self) -> None:
|
|
15
|
+
self._master: Optional[Widget] = None
|
|
16
|
+
self._counter: Optional[Counter] = None
|
|
17
|
+
self._total: Optional[int] = None
|
|
18
|
+
self._description = ""
|
|
19
|
+
self._unit = ""
|
|
20
|
+
|
|
21
|
+
def add_widget(self, widget: Widget) -> None:
|
|
22
|
+
self._master = widget
|
|
23
|
+
|
|
24
|
+
def add_counter(self, counter: Counter) -> None:
|
|
25
|
+
self._counter = counter
|
|
26
|
+
|
|
27
|
+
def add_description(self, description: str) -> None:
|
|
28
|
+
self._description = description
|
|
29
|
+
|
|
30
|
+
def add_unit(self, unit: str) -> None:
|
|
31
|
+
self._unit = unit
|
|
32
|
+
|
|
33
|
+
def add_total(self, value: int) -> None:
|
|
34
|
+
self._total = value
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def build(self) -> AbstractPopupProgressbar:
|
|
38
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from OTAnalytics.adapter_ui.helpers import WidgetPositionProvider
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AbstractTreeviewInterface(WidgetPositionProvider):
|
|
7
|
+
# TODO: add property viewmodel
|
|
8
|
+
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def _introduce_to_viewmodel(self) -> None:
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def _notify_viewmodel_about_selected_item_ids(self, ids: list[str]) -> None:
|
|
15
|
+
raise NotImplementedError
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def update_items(self) -> None:
|
|
19
|
+
raise NotImplementedError
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def update_selected_items(self, item_ids: list[str]) -> None:
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def enable(self) -> None:
|
|
27
|
+
raise NotImplementedError
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def disable(self) -> None:
|
|
31
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from OTAnalytics.domain.section import RelativeOffsetCoordinate
|
|
2
|
+
|
|
3
|
+
RELATIVE_SECTION_OFFSET: RelativeOffsetCoordinate = RelativeOffsetCoordinate(0.5, 0.5)
|
|
4
|
+
DATE_FORMAT: str = r"%Y-%m-%d"
|
|
5
|
+
DATETIME_FORMAT: str = r"%Y-%m-%d %H:%M:%S"
|
|
6
|
+
DATE_FORMAT_PLACEHOLDER = "yyyy-mm-dd"
|
|
7
|
+
|
|
8
|
+
DATE_FORMAT_GERMAN: str = r"%d.%m.%Y"
|
|
9
|
+
DATETIME_FORMAT_GERMAN: str = r"%d.%m.%Y %H:%M:%S"
|
|
10
|
+
DATE_FORMAT_PLACEHOLDER_GERMAN = "dd.mm.yyyy"
|
|
11
|
+
|
|
12
|
+
SUPPORTED_FORMATS: list[str] = [DATE_FORMAT, DATE_FORMAT_GERMAN]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from OTAnalytics.domain.section import COORDINATES, Section
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SectionRefPointCalculator(ABC):
|
|
7
|
+
def coordinates_from_section(self, section: Section) -> list[tuple[int, int]]:
|
|
8
|
+
coordinates_dicts = section.to_dict()[COORDINATES]
|
|
9
|
+
return [(d["x"], d["y"]) for d in coordinates_dicts]
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def get_reference_point(self, section: Section) -> tuple[float, float]:
|
|
13
|
+
"""
|
|
14
|
+
Calculates a reference point on a section.
|
|
15
|
+
Raises:
|
|
16
|
+
NotImplementedError: If derived classes have not implemented this method
|
|
17
|
+
Returns:
|
|
18
|
+
tuple[float, float]: Reference point
|
|
19
|
+
"""
|
|
20
|
+
raise NotImplementedError
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class InnerSegmentsCenterCalculator(SectionRefPointCalculator):
|
|
24
|
+
def get_reference_point(self, section: Section) -> tuple[float, float]:
|
|
25
|
+
coordinates = self.coordinates_from_section(section)
|
|
26
|
+
num_coordinates = len(coordinates)
|
|
27
|
+
if num_coordinates == 0:
|
|
28
|
+
raise ValueError("LineSection has no coordinates")
|
|
29
|
+
if num_coordinates % 2 == 0:
|
|
30
|
+
# Calculate center between innermost two points
|
|
31
|
+
innermost_coordinates = coordinates[
|
|
32
|
+
num_coordinates // 2 - 1 : num_coordinates // 2 + 1
|
|
33
|
+
]
|
|
34
|
+
center_x = (innermost_coordinates[0][0] + innermost_coordinates[1][0]) / 2
|
|
35
|
+
center_y = (innermost_coordinates[0][1] + innermost_coordinates[1][1]) / 2
|
|
36
|
+
else:
|
|
37
|
+
# Calculate innermost point
|
|
38
|
+
innermost_coordinate_index = len(coordinates) // 2
|
|
39
|
+
center_x, center_y = coordinates[innermost_coordinate_index]
|
|
40
|
+
return center_x, center_y
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class GeometricCenterCalculator(SectionRefPointCalculator):
|
|
44
|
+
def get_reference_point(self, section: Section) -> tuple[float, float]:
|
|
45
|
+
coordinates = self.coordinates_from_section(section)
|
|
46
|
+
total_x = 0
|
|
47
|
+
total_y = 0
|
|
48
|
+
num_points = len(coordinates)
|
|
49
|
+
for x, y in coordinates:
|
|
50
|
+
total_x += x
|
|
51
|
+
total_y += y
|
|
52
|
+
center_x = total_x / num_points
|
|
53
|
+
center_y = total_y / num_points
|
|
54
|
+
return center_x, center_y
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class WidgetPositionProvider(ABC):
|
|
5
|
+
@abstractmethod
|
|
6
|
+
def get_position(self, offset: tuple[float, float] = (0.5, 0.5)) -> tuple[int, int]:
|
|
7
|
+
raise NotImplementedError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def remove_wildcard_from(file_extension: str) -> str:
|
|
11
|
+
return file_extension[1:] if file_extension.startswith("*") else file_extension
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def ensure_file_extension_is_present(
|
|
15
|
+
file: str, allowed_extensions: list[str], defaultextension: str
|
|
16
|
+
) -> str:
|
|
17
|
+
"""
|
|
18
|
+
Ensure that the file contains a file extension. If no extension is appended, the
|
|
19
|
+
defaultextension will be used.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
file (str): file to ensure it has a file extension
|
|
23
|
+
allowed_extensions (list[str]): extensions that are allowed
|
|
24
|
+
defaultextension (str): default extension to be added if extension is missing
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Path: path object with file extension
|
|
28
|
+
"""
|
|
29
|
+
if not file:
|
|
30
|
+
return ""
|
|
31
|
+
file_extension = remove_wildcard_from(defaultextension)
|
|
32
|
+
allowed_file_extensions = set(
|
|
33
|
+
[remove_wildcard_from(ext) for ext in allowed_extensions]
|
|
34
|
+
)
|
|
35
|
+
allowed_file_extensions.add(file_extension)
|
|
36
|
+
for allowed_extension in allowed_file_extensions:
|
|
37
|
+
if file.endswith(allowed_extension):
|
|
38
|
+
return file
|
|
39
|
+
if file_extension.startswith("."):
|
|
40
|
+
return file + file_extension
|
|
41
|
+
return f"{file}.{file_extension}"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Iterator
|
|
3
|
+
|
|
4
|
+
COLUMN_NAME = "column_name"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True, order=True)
|
|
8
|
+
class ColumnResource:
|
|
9
|
+
"""
|
|
10
|
+
Represents a row in a treeview with an id and a dict of values to be shown.
|
|
11
|
+
The dicts keys represent the columns and the values represent the cell values.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
id: str
|
|
15
|
+
values: dict[str, str]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ColumnResources:
|
|
19
|
+
def __init__(
|
|
20
|
+
self, resources: list[ColumnResource], lookup_column: str = COLUMN_NAME
|
|
21
|
+
) -> None:
|
|
22
|
+
self._resources = resources
|
|
23
|
+
self._lookup_column = lookup_column
|
|
24
|
+
self._to_id = self._create_to_id(resources)
|
|
25
|
+
self._to_name = self._create_to_name(resources)
|
|
26
|
+
|
|
27
|
+
def _create_to_id(self, resources: list[ColumnResource]) -> dict[str, str]:
|
|
28
|
+
return {
|
|
29
|
+
resource.values[self._lookup_column]: resource.id for resource in resources
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
def _create_to_name(self, resources: list[ColumnResource]) -> dict[str, str]:
|
|
33
|
+
return {
|
|
34
|
+
resource.id: resource.values[self._lookup_column] for resource in resources
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def names(self) -> list[str]:
|
|
39
|
+
return [resource.values[self._lookup_column] for resource in self._resources]
|
|
40
|
+
|
|
41
|
+
def get_name_for(self, resource_id: str) -> str:
|
|
42
|
+
return self._to_name.get(resource_id, "")
|
|
43
|
+
|
|
44
|
+
def get_id_for(self, name: str) -> str:
|
|
45
|
+
return self._to_id.get(name, "")
|
|
46
|
+
|
|
47
|
+
def has(self, resource_id: str) -> bool:
|
|
48
|
+
return resource_id in [resource.id for resource in self._resources]
|
|
49
|
+
|
|
50
|
+
def __iter__(self) -> Iterator[ColumnResource]:
|
|
51
|
+
return self._resources.__iter__()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from OTAnalytics.application.project import (
|
|
2
|
+
CountingDayType,
|
|
3
|
+
DirectionOfStationing,
|
|
4
|
+
WeatherType,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
DIRECTIONS_OF_STATIONING = {
|
|
8
|
+
DirectionOfStationing.IN_DIRECTION: "In Stationierungsrichtung",
|
|
9
|
+
DirectionOfStationing.OPPOSITE_DIRECTION: "Gegen Stationierungsrichtung",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
COUNTING_DAY_TYPES = {
|
|
13
|
+
CountingDayType.NOW_1: "1. NoW",
|
|
14
|
+
CountingDayType.NOW_2: "2. NoW",
|
|
15
|
+
CountingDayType.FR_1: "1. Fr",
|
|
16
|
+
CountingDayType.FR_2: "2. Fr",
|
|
17
|
+
CountingDayType.SO_1: "1. So",
|
|
18
|
+
CountingDayType.SO_2: "2. So",
|
|
19
|
+
CountingDayType.FEW_1: "1. FeW",
|
|
20
|
+
CountingDayType.FEW_2: "2. FeW",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
WEATHER_TYPES = {
|
|
24
|
+
WeatherType.SUN: "sonnig",
|
|
25
|
+
WeatherType.CLOUD: "bewölkt",
|
|
26
|
+
WeatherType.RAIN: "Regen",
|
|
27
|
+
WeatherType.SNOW: "Schnee",
|
|
28
|
+
WeatherType.FOG: "Nebel",
|
|
29
|
+
}
|